1. Home
  2. Docs
  3. Niryo One documentation
  4. Tutorials
  5. Control simultaneously several robots with multithreading

Control simultaneously several robots with multithreading

https://niryo.com/wp-content/uploads/2020/11/Schéma-MultiThreading-600×709.png

In this tutorial, we’ll see how to control several robots at the same time from the same Python program by using Python threading library. To do so, we will use:

  • Software
    • Python 3.7
    • The “threading” library (automatically installed with Python)
    • The “PyNiryo API” library for the Niryo One.
  • Hardware
    • Two Niryo One

First, it is necessary to connect to the robot.

To use this program’s exemple, you will have to replace “” and “” by the IP addresses of your robots. 

from niryo_one_tcp_client import *

robot1_ip =
robot2_ip =

#robot1 connexion
client1 = NiryoOneClient()
client1.connect(robot1_ip)
client1.calibrate(CalibrateMode.AUTO)

#robot2 connexion
client2 = NiryoOneClient()
client2.connect(robot2_ip)
client2.calibrate(CalibrateMode.AUTO)

sleep_joints =
#robot1 sequence
client1.move_joints(*sleep_joints)
client1.set_learning_mode(True)

#robot2 sequence
client2.move_joints(*sleep_joints)
client2.set_learning_mode(True)

In this example, we connect to two robots and then ask them to do a slight movement. The first robot will do the asked movement, turn to learning mode, then the second robot will do the asked movement and turn to learning mode too. 

This is due to the use of move_joints() function. The program waits for the robot to end its movement to run the next line.

To make a movement on the two robots in a simultaneous way, we will use the threading library provided by default with Python. 

Multithreading allows you to run several parts of the same program in parallel. It is often used to spread the load of calculations betweens several processors and to run several actions simultaneously. Thus, it will allow us to execute several commands of the Python API TPC/IP  at the same time. To do so, we will create a thread for each robot.

If you don’t know multithreading yet, we invite you to read and follow the links down below:

We can now modify the program in order to run the actions of each robot in a different thread.

from niryo_one_tcp_client import *
import threading
from threading import *robot1_ip =
robot2_ip =sleep_joints = class RobotThread(threading.Thread):


def __init__(self, client, robot_id):

Thread.__init__(self)
self.client = client
self.robot_id = robot_id

#program of the robots
def run(self):

print(“robot n°”, self.robot_id, “start”)
self.client.calibrate(CalibrateMode.AUTO)
self.client.move_joints(*sleep_joints)
self.client.set_learning_mode(True)
print(“robot n°”, self.robot_id, “end”)

client1 = NiryoOneClient()
client1.connect(robot1_ip)

client2 = NiryoOneClient()
client2.connect(robot2_ip)

#creating one thread for each robot
robot1 = RobotThread(client1, 1)
robot2 = RobotThread(client2, 2)

#starting the threads
robot1.start()
robot2.start()

In this program, the two robots perform their movements simultaneously. The two threads we have created in this example don’t share any data. To synchronize the two robots, we’ll need a variable shared by the two threads.

There are two ways to share a variable between several threads:

  • The first way is to create global variables
  • The second way is to use a mother class which will contain the two classes of the threads.

By giving the mother class as an argument to the “RobotThread”, we grant them the access to the variables the mother class contains. That way, the “RobotThread” will keep the variables they contain in private and will use their mother class variables to communicate. 

In the following example, the mother class is “RobotsMains”

from niryo_one_tcp_client import *
import threading
from threading import *robot1_ip =
robot2_ip = sleep_joints = class RobotsMain:

def __init__(self, client1, client2):

self.client1 = client1
self.client2 = client2

self.share_var_examples = 0

def run(self):

#creating one thread for each robot
robot1 = self.RobotThread(self, self.client1, 1)
robot2 = self.RobotThread(self, self.client2, 2)

#starting the threads
robot1.start()
robot2.start()

class RobotThread(threading.Thread):

def __init__(self, parent, client, robot_id):

Thread.__init__(self)
self.parent = parent
self.client = client
self.robot_id = robot_id

#program of the robots
def run(self):

self.client.calibrate(CalibrateMode.AUTO)
self.client.move_joints(*sleep_joints)
self.parent.share_var_examples += 1

print(“robot n°”, self.robot_id, “shared var value”,self.parent.share_var_examples)

self.client.set_learning_mode(True)

client1 = NiryoOneClient()
client1.connect(robot1_ip)

client2 = NiryoOneClient()
client2.connect(robot2_ip)

mains = RobotsMains(client1, client2)
mains.run()

To correctly synchronize multiple robots, we recommend you to use the following functions:

  • “Event” = threading.Event()
    • Allows to create an “Event” object on which a thread can wait by using the “Event”.wait() function. It can be unlocked by another thread using “Event”.set(). So “Event”.wait() can work again, “Event”.clear() must be recalled.
  • “Lock” = threading.Lock()
    • Allows to create a lock that can be used by one thread. An instinctive way to imagine lock’s use is to consider it as a key which grants access to a part of the code. Before a thread uses the key, it must wait until the other has finished to use the key as well. 

Note

If you use several threads to control the same robot, you must know that a NiryoOneClient() instance can only be used by one thread at a time. Think about using threading.Event() to avoid the sending of two simultaneous TCP commands to the same robot.

How can we help?