简体   繁体   中英

Running interacting functions simultaneously in python

So I'm trying to build a robot that can drive autonomously. For that I need the robot to drive forward and check distance at the same time. And if distance is less than preferred distance, stop forward movement. By now I've written this code below, but it doesn't seem to run simultaneously and they also don't interact. How can I make it that these two functions do indeed interact. If there's anymore information needed I'm happy to supply you. Thanks!

from multiprocessing import Process
from TestS import distance
import Robot
import time

constant1 = True
min_distance = 15

def forward():
    global constant1:
    robot.forward(150)                       #forward movement, speed 150
    time.sleep(2)

def distance_check():
    global constant1
    while constant1:
        distance()                           #checking distance
        dist = distance()
        return dist
        time.sleep(0.3)

        if dist < min_distance:
            constant1 = False
            print 'Something in the way!'
            break

def autonomy():                              #autonomous movement
    while True:
        p1 = Process(target=forward)         
        p2 = Process(target=distance_check)
        p1.start()                           #start up 2 processes
        p2.start()
        p2.join()                            #wait for p2 to finish

So, there's some serious problems with the code you posted. First, , because it's running a while loop. ,因为它正在运行while循环。 You should not do p2.join() , nor should you be starting new processes all the time in your while loop. You're mixing too many ways of doing things here - either the two children run forever, or they each run once, not a mix.

However, the main problem is that (unless you do some more work). (除非您做更多工作)。 Threads are much more suited to this problem.

You also have a return inside your distance_check() function, so (including the sleep , and the setting of constant1 (which should really have a better name). (包括sleep ,以及constant1的设置(应该有更好的名字)。

In summary, I think you want something like this:

from threading import Thread
from TestS import distance
import Robot
import time

can_move_forward = True
min_distance = 15


def move_forward():
    global can_move_forward
    while can_move_forward:
        robot.forward(150)
        time.sleep(2)
        print('Moving forward for two seconds!')


def check_distance():
    global can_move_forward
    while True:
        if distance() < min_distance:
            can_move_forward = False
            print('Something in the way! Checking again in 0.3 seconds!')
        time.sleep(0.3)


def move_forward_and_check_distance():
    p1 = Thread(target = move_forward)
    p2 = Thread(target = check_distance)
    p1.start()
    p2.start()

Since you specified python-3.x in your tags, I've also corrected your print .

Obviously I can't check that this will work as you want it to because I don't have your robot, but I hope that this is at least somewhat helpful.

One issue with your multiprocessing solution is that distance_check returns and stops

    dist = distance()
    return dist        # <------ 
    time.sleep(0.3)

    if dist < min_distance:
        ....

It seems like you are trying to exchange information between the processes: which is typically done using Queues or Pipes .

I read between the lines of your question and came up with the following specs:

  • a robot moves if its speed is greater than zero
  • continually check for obstacles in front of the robot
  • stop the robot if it gets to close to something.

I think you can achieve your goal without using multiprocessing. Here is a solution that uses generators/coroutines.

For testing purposes, I have written my own versions of a robot and an obstacle sensor - trying to mimic what I see in your code

class Robot:
    def __init__(self, name):
        self.name = name
    def forward(self, speed):
        print('\tRobot {} forward speed is {}'.format(self.name, speed))
        if speed == 0:
            print('\tRobot {} stopped'.format(speed))

def distance():
    '''User input to simulate obstacle sensor.'''
    d = int(input('distance? '))
    return d

Decorator to start a coroutine/generator :

def consumer(func):
    def wrapper(*args,**kw):
        gen = func(*args, **kw)
        next(gen)
        return gen
    wrapper.__name__ = func.__name__
    wrapper.__dict__ = func.__dict__
    wrapper.__doc__  = func.__doc__
    return wrapper

A producer to continually check to see if it is safe to move

def can_move(target, min_distance = 15):
    '''Continually check for obstacles'''
    while distance() > min_distance:
        target.send(True)
        print('check distance')
    target.close()

A generator/coroutine that consumes safe-to-move signals and changes the robot's speed as needed.

@consumer
def forward():
    try:
        while True:
            if (yield):
                robot.forward(150)
    except GeneratorExit as e:
        # stop the robot
        robot.forward(0)

The robot's speed should change as fast as the obstacle sensor can produce distances. The robot will move forward till it gets close to something and just stop and it all shuts down . By tweaking the logic a bit in forward and can_move you could change the behaviour so that the generators/coroutines keep running but send a zero speed command as long as something is in front of it then when the thing gets out of the way (or the robot turns) it will start moving again.

Usage:

>>> 
>>> robot = Robot('Foo')
>>> can_move(forward())
distance? 100
    Foo forward speed is 150
check distance
distance? 50
    Foo forward speed is 150
check distance
distance? 30
    Foo forward speed is 150
check distance
distance? 15
    Foo forward speed is 0
    Robot 0 stopped
>>>

While this works in Python 3.6, it is based on a possibly outdated notion/understanding of generators and coroutines. There may be a different way to do this with some of the async additions to Python 3+.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM