How can I make my robot do more than one thing at once, while being in the same state?
How can I make my robot do more than one thing at once, while being in the same state?
It's common for the driving logic of a ROS program to be structured like this:
Here, your code
runs at most 20 times per second (it can run less frequently if your code
takes longer than 1/20th of a second to execute). This is a useful framework, especially if you want to have your robot continually check for its current state and execute code accordingly.
For example, in the code below, the robot executes different functions depending on whether its state is that of follower
or leader
.
But suppose your robot must do more than one thing at once, that conceptually falls under its responsibilities as a leader
. For example, it might have to execute some complex_function
, while at the same time publishing messages over a topic.
In my case, my robot had to publish messages to other robots, letting it know that it was the leader, while at the same time telling the robots where to go.
One solution to this would be to write a whole new ROS node that publishes the required messages (in its own while not rospy.is_shutdown
loop), and have complex_function
run on the current node. But this separates into two processes what belongs as a logical unit, and also carries with it the overhead of having to launch another ROS node.
A simpler solution is to use multithreading. For example:
===WARNING: This is pseudocode, since, among other reasons, we didn't define the variable send_messages_thread
. In real code, send_messages_thread
should probably be an attribute of your robot, which you should define as a python Class
(along the same lines, robot_state
above should also be an attribute).===
This code first checks if the variable send_messages_thread
has been initialized. If it hasn't, it defines a thread that, when started in send_messages_thread.start()
, executes the function send_messages
. Note that the thread is defined as a daemon
thread, which shuts down when your current thread (the one in which you're defining the send_messages_thread
shuts down).
This is the basis of a design framework you can apply to make your robot multitask appropriately. It's only the basis, because by leveraging a couple more items in python's concurrency library you can make your robot multitask in more sophisticated ways.
For example, suppose you have a mechanism which allows for communication between threads. By this device, thread A can tell thread B that something has happened that should cause B to act differently, or to simply terminate.
This would open up a lot of doors. In our example above, for example, you would be able to shut down the send_messages_thread
at will by having the while loop of send_messages
check for the communication from thread A that an event has happened:
But this mechanism that allows for threads to communicate with each other is just what is provided by python's Event
object. Together with the join
function that allows a thread to wait for another thread to finish, you can do a suprising variety of multitasking.