Advice on robot control - image processing design architecture
Question: This is more a software engineering question than a Python question, but since
I am using Python to implement everything, any Python solution is very
welcome.

I have two classes. One class controls a robot and sends to it commands to
perform. Like moving to some position or do some action. The communication
between the robot and the computer is USB serial.

The robot has a camera. This camera is connected to the computer using a USB
cable. The other class I have receives frames from this camera, and analyzes
them.

So I have two classes. One that controls the robot, and one that performs all
the image processing.

My initial idea was to have a file "main.py", which creates an object for each
class, and handles it. I think this solution is too simple, ugly and hard to
escale. At the same time, the image processing part requires a continuous loop
where the frames are grabbed. This means that I will have to insert my robot
code inside the loop. I would this not to happen, and have the classes running
on different processes.

I am open to any suggestion, like using sockets or anything. I am just
starting to implement it so I am very open.


Answer: Okay, this example should give you an idea on how you could split the vision
and motor control tasks. Run it to see how the tasks run side by side. Can't
help with the specifics of _receiving_ the image without more details though.

Whether you put your classes in separate files or not is entirely up to you,
it doesn't really matter. I tend to put several classes together in a file for
smaller projects, but spread them out more in larger ones.

    
    
    import threading
    import time
    import random
    import sys
    
    class Robot:
        def __init__(self):
            self.worldKnowledge = {"currentFrame": 0, "objects":[]}
            self.visionThread = threading.Thread(target=self.vision)
            self.visionThread.daemon = True
            self.motorThread = threading.Thread(target=self.motorControl)
            self.motorThread.daemon = True
    
            self.visionThread.start()
            self.motorThread.start()
    
            while True:
                # This is to keep the main thread alive and responsive while the 
                # vision and motor threads are running
                try:
                    time.sleep(1)
                except KeyboardInterrupt:
                    sys.exit()
    
        def getFrame(self):
        # simulate retrieval of latest camera frame
        # return value indicates whether there is a new frame or not
            if random.random() > 0.7: 
                self.worldKnowledge["currentFrame"] += 1
                return True
            return False
    
        def vision(self):
            while True:
                if self.getFrame():
                    print "Processing incoming frame!"
                    # do object detection here = detected objects can go into self.worldKnowledge, 
                    # for example: 
                    # self.worldKnowledge["objects"] += [(objectID, objectLocation, objectSize, isMoving, currentFrame )]
                time.sleep(1)
    
        def motorControl(self):
        # move the robot based on the most recent world knowledge
            while True:
                print("Acting on latest information (from frame %i)" % 
                    self.worldKnowledge["currentFrame"])
                time.sleep(1)
    
    if __name__ == "__main__":
        Robot()
    

