0

I am using socket to send commands from one RPi to another. The receiving rpi turns a servo (by running Yservo function) when it receives the command "turnRight" and stops turning the servo by terminating the process when it receives "stop". The servo position starts at half which is x = 50. The issue is the servo position is not updated in the main code so the next time the process is run it starts at 50 again.

I need to either update/change a value in a python process (to have Yservo break it's while loop. For instance while state == True:, so when state is updated to false, the while loop breaks and can return the value x instead of having the process be terminated) or have the process update a variable (x) in the main instance.

Receive Code:

import socket
from multiprocessing import Process 
import RPi.GPIO as gpio
import time
gpio.setmode(gpio.BCM)

ps = 27
ys = 28

gpio.setup(ps,gpio.OUT)
gpio.setup(ys,gpio.OUT)


pitchS = gpio.PWM(ps,50)
pitchS.start(0)


x = 50

def Yservo(): #x is starting position / current position
    global x
    while 1:
        x += 1
        pitchS.ChangeDutyCycle(x)
        time.sleep(1)
        print(x)
        if x >= 100:
            while 1:
                pass


server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(('', 6666))
print ("UDPServer Waiting for client on port 6666")


try:
    while True:  
        dataFromClient, address = server_socket.recvfrom(256)
        data = str(dataFromClient.decode('utf-8'))
        data = data.split(',')
        if data[0] == 'turnRight':
            TS = Process(target=Yservo,args=())
            TS.daemon = True
            TS.start()
            #TS.join()
        if data[0] == 'stop':
            TS.terminate()
            TS.join()

except:
    print('STOP! wait a minute')
    TS.terminate()
    TS.join()

Gami
  • 33
  • 3
  • I thought of a much simpler solution. I wrote the value X to a file in Yservo. Then read the value to update X in the main loop. – Gami Nov 22 '19 at 00:23
  • 1
    Sure ... but that's not a very elegant way of solving this simple problem :) – Victor Deleau Nov 22 '19 at 00:36

1 Answers1

1

I recommend to keep your process alive instead or spawning/killing it each time, and have it listen to a queue every 1s to get orders from the main process. Also your inner while loop in the Yservo sub-process will max out one of your core if x>=100 for as long as you don't terminate the sub-process, which is not desirable. This version will remember the position you previously stopped at:

import socket
from multiprocessing import Process, Queue
import RPi.GPIO as gpio
import time
import Queue

gpio.setmode(gpio.BCM)
start_position=50
ps = 27
ys = 28

gpio.setup(ps,gpio.OUT)
gpio.setup(ys,gpio.OUT)
pitchS = gpio.PWM(ps,50)
pitchS.start(0)

def Yservo(q, start_position):

    command = None
    x = start_position
    while True:
        try:
            command = q.get(False)
        except Queue.Empty:
            pass
        if command == "turn_right" and x < 100:
            x += 1
            pitchS.ChangeDutyCycle(x)
        time.sleep(1)
        print(x)


q = Queue()
TS = Process(target=Yservo,args=(q,start_position))
TS.daemon = True
TS.start()

try:
    while True:  
        dataFromClient, address = server_socket.recvfrom(256)
        data = str(dataFromClient.decode('utf-8'))
        data = data.split(',')
        if data[0] == 'turnRight':
            q.put("turn_right")
        if data[0] == 'stop':
            q.put("stop")
except:
    print('STOP! wait a minute')
    TS.terminate()
    TS.join()

q.get() will block the execution of your code, but by passing a False boolean and catching the Queue.Empty exception you can just try to consume an object in the queue in a non-blocking way.

Victor Deleau
  • 875
  • 5
  • 17