The objective in this section is to control not only one robot, but multiple at the same time. This technique, although computationally expensive when controlling many DoFs, allows us to:
Specify constraints (contacts, collisions) between robots
Achieve tasks in cooperation
Manipulate articulated objects
All of this without having to perform explicit inverse kinematics.
To do this, our QP controller will minimize under constraints an objective function that takes into account the whole system of robots.
In our example we will focus on manipulating a simple object with two degrees of freedom: a door. Our goal is to move the robot's hand to the door handle, turn the handle and open the door.
Note: this article assumes you are able to run and visualize the controller using ROS.
Example
We will build a simple controller that will load JVRC1 and a door. This door is part of the mc_rtc_data package that you should already have.
Now, let's build a controller that takes multiple robots as input:
In this new example, we have loaded an extra robot: the door. We have done so by proviing a list of robot modules to load. The loaded robots are then indexed according to the order in which the modules were provided. It means that our main robot still has the index 0, however we now have the door at index 1 and the ground at index 2. It means that the contacts setting must be updated as follows:
If you start the controller now, you will notice that the door and the robot are in the same location, for the purpose of this tutorial, we will manually reposition the door:
Note: we don't add contact for the door yet as it has a fixed base. However, note that the contact constraint is directly available for every robots in the controller.
Setting up the controller logic
In that part of the tutorial we will setup the logic of our controller. We want to:
For this phase, we will introduce the SurfaceTransformTask. It is very similar to the EndEffectorTask we used except that the task is controlling a surface of the robot instead of an end-effector. This usually makes it easier to express the objective. Furthermore, we will define the target using the position of the door's handle so that we don't have to adapt our code if we decide to move the door or change the hand.
The first point will be to monitor the execution of the SurfaceTransformTask. For the second point, we will add a contact between the door and the robot's gripper, remove the task on the robot's gripper (it is now handled by the contact) and change the target for the handle position.
This phase is very similar to the previous one. We will check the handle position that has been reached to trigger the transition and then set an objective for the door opening.
At this point you can play around with some of the parameters and see the benefits of the multi-robot approach as you can change the following without changing anything else:
Change the door position
Change the handle opening angle
Change the door opening angle
Change the robot's hand used to open the door
Note: of course, you may end up with an unfeasible setup. For example, if you put the door 10 meters away from the robot it won't be able to reach the handle.
Introducing the FSM facilities
This tutorial concludes the introduction of mc_rtc controllers. The next tutorials are focused on the advanced tools available in the framework to help you program and debug complex controllers. However, you might have noticed we have used a very crude approach to program the logic of our controller. The framework provides a much more powerful way to deal with such scenarios as introduced in the tutorial introducing the FSM facilties and the FSM in practice tutorial. The latter will re-program this tutorial using the FSM facilities.
The full sources for this controller are available here.