Search code examples
pythonpython-3.xmultithreadingsocketspython-multithreading

How to make multithread my communication code between Raspberry Pis?


Im trying to communicate two RPi with TCP. One RPi is server and other is client. Server part includes motor and sensor, client part includes joystick. I want to send control values from client to the server, and sensor values from server to the client. My code can do these separately, i can control BLDC from server to the client and send sensor values from client to the server. But i am trying to do these at the same time. How can i do that?

Server code:

import socket
import os
import time
os.system("sudo pigpiod")
time.sleep(1)
import pigpio
import RPi.GPIO as GPIO

pi = pigpio.pi()
ESC = 4
min_value = 1200
max_value = 2400
HOST = '' 
PORT = 65458
a = 0
c = 0
def control():
  data = conn.recv(1024)
  stringdata = data.decode('ascii')
  altan = int(stringdata)
  alta = altan + 1000
  print(alta)
  pi.set_servo_pulsewidth(ESC, alta)
def update():
  global a
  global c
  a = a + 5
  c = c + 3
def sendsensorvalues():
  b = 'd1' + str(a)
  conn.send(b.encode('ascii'))
  d = 'd2' + str(c)
  conn.send(d.encode('ascii'))
  update()
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
  s.bind((HOST, PORT))
  s.listen()
  conn, addr = s.accept()
  with conn:
    print('CONNECTED BY', addr)
    while True:
        control()
        sendsensorvalues()

Client code :

import socket
import serial
from time import sleep
HOST = '169.254.78.190'
PORT = 65458
def sendmotor():
  read = ser.readline()
  a = int(read)
  b = str(a)
  s.sendall(b.encode('ascii'))

def displayfirst():
  a = strdata[2:]
  print('First senso value is : ' + a)
def displaysecond():
  b = strdata[2:]
  print('Second sensor value is : ' + b)
def getsensorvalues():
  data = s.recv(1024)
  strdata = data.decode('ascii')
  if strdata[1] == '1':
    displayfirst()
  else:
    displaysecond()


with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
  s.connect((HOST, PORT))
  ser = serial.Serial("/dev/ttyUSB0", 57600)
  ser.baudrate = 57600
  while True:
    sendmotor()
    getsensorvalues()

When i run this codes, i get errors:

Server part error, control() function takes two value

Client part error


Solution

  • Server part error

    The server receives up to 1024 bytes at once with data = conn.recv(1024). From the screen image it is obvious that the data items sent were 516 and that two consecutive items 516516 were received at once, causing the error when interpreted as one large number. One way to fix this is to not send data of variable length, but rather of fixed length and receive only that number of bytes, e. g. with import struct and in the client changing

      b = str(a)
      s.sendall(b.encode('ascii'))
    

    to

      b = struct.pack('i', a) # length 4
      s.sendall(b)
    

    as well as in the server changing

      data = conn.recv(1024)
      stringdata = data.decode('ascii')
      altan = int(stringdata)
    

    to

      data = conn.recv(4)
      altan = struct.unpack('i', data)[0]
    
    Client part error

    The shown client error is likely a consequence of strdata being empty due to the termination of the server. Besides that, the client has the same problem as the server with potentially receiving concatenated sensor values, which you can address in a similar way, e. g. by changing

      b = 'd1' + str(a)
      conn.send(b.encode('ascii'))
    

    to

      conn.send(struct.pack('=2si', b'd1', a))    # length 6