-
Notifications
You must be signed in to change notification settings - Fork 935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Executing multiple trajectories with different controllers is not supported #2287
Comments
Thanks for reporting an issue. Because we're a volunteer community, providing a pull request with suggested changes is always welcomed. |
What sort of robot is this? An industrial robot with multiple motion groups on a single controller, or a custom job with multiple controllers? |
I am using 4 Panda Arms which I have attached to a plane which works as a base link (just as a simulation in Gazebo). |
So multiple controllers? I'm a bit puzzled by this part of your description:
If you have multiple pandas, with multiple controllers, and are not using a combined hw |
Yes indeed. I have 4 action servers to give commands to the controllers, thats why I am able to control them each on its own. I just read https://answers.ros.org/question/317028/how-run-multiple-move_group-for-different-robots-in-single-system/ and assumed that MoveIt is going to pipe each motion plan into an action server (which might be wrong) before adressing the controller action servers. Sorry for the unclear description. |
I can't help you with the So MoveIt would submit action goals to each individual action server. With such a setup, synchronous execution of trajectories would be inherently impossible. If "somewhat simultaneous" would be enough, that should be possible. |
If you need them actually synchronized, I would suggest using a single planning group with all your pandas inside it. Are you sure that 4 |
Thanks anyways @gavanderhoorn. What I am trying to create is a robot with 4 arms that simulates an improved process of additive manufacturing. The goal of reducing the manufacturing process time is the reason that all of the 4 arms need to be working at the same time. If they have a delay of a few seconds behind each other that won't be a problem but obviously if there is only 1 arm working at all times there is no reason to use 4 of them. @felixvd It looks like by default the moveit_config package generates 1 move_group action server, in my script I create 4 instances of the MoveGroupCommander class one for each arm. Is this a wrong approach? |
Well, not "wrong", but you won't be able to run 4 robots asynchronously with that setup. I assume this is what happened:
Also see the MoveIt concepts here. If you want to run the 4 robots asynchronously in the way you describe, my understanding is that you will need to launch 4 The "cleanest" way is probably to namespace the I haven't tried this and don't know anyone who has, but I know running planning groups simultaneously is a desirable feature. Pinging @henningkayser, @v4hn to correct if I wrote something completely off the mark. I also wonder if #2078 is related. |
Ok I understand a bit better now what the problem is, thanks! You are right, I am launching 1 move_group but 4 MoveGroupCommanders. I have launched the move_group launch file in 4 different namespaces now, however I had to also namespace the joint_state_publisher and robot_state_publisher. The controller_spawner node inside the ros_controllers launch file does not work for now due multiple nodes named the same. Are launchfiles inside launchfiles not automatically launched under the aforementioned namespace? As in both cases I will have to run 4 move_group nodes is it better to run 4 nodes or launch 4 times the move_group launch file? And regarding the ros_namespace argument, will this have to be added into the source code of the MoveGroupCommander or is there another way? Thanks again, you already helped a lot! |
I don't know if the
As far as I can see, yes, but it should be as simple as adding the namespace in front of the I do think this is a workaround though, and I think the |
The problem with the controllers is that it seems to be looking for the /move_group action server, which is now called /move_group1/move_group/[...] , /move_group2/move_group/[...] etc. due to the namespaces. Remapping all the topics and the action server back to /move_group from inside the move_group launch file so that the controller client can find it is unefficient but remapping the /move_group server to the 4 new-named instances of move_group from inside the controller launch file is not even possible from my understanding. So in conclusion the controllers can't find the move_group action server after namespacing it and I am not sure how to solve this if I let the controller launch file live in the namespace where it currently is.
With this approach I will still need 4 move_group nodes which will lead to the same problem with the controllers or does this work with only one move_group too? I have also seen #757, I think this could be a substitute to a ros_namespace variable. Other opinions are highly welcome! |
The controllers advertise
Yes, you will still need 4 |
[ INFO] [1599482396.609129695, 3.730000000]: Failed to call service get_planning_scene, have you launched move_group or called psm.providePlanningSceneService()? This is the error I get which will come up for every controller that I am trying to launch. |
Yes, try that. And note that you can format code with ```, if you paste more terminal output. |
Did you manage to get this running or were there more difficulties? |
I have not been able to test it yet because of an unrelated error that popped up but I will come back to this as soon as it's fixed. |
AFAIK, there is no way to do this with MoveGroup for several reasons:
The single MoveGroup way to solve this would really be to define a planning group that includes all arms. Of course you need an IK solver and a planner to support this or you need to merge the different trajectories by hand. Otherwise, running multiple MoveGroup nodes should work with proper namespacing, but there could still be some issues with global parameters or topics. Keep in mind that arm-to-arm collision checking and syncing of the planning scenes can still be tricky and error-prone. Another thing that might be worth looking into is to execute preplanned trajectories directly by sending FollowJointTrajectory actions to the ros controllers (of course you have to rule out arm-to-arm collisions first). This would bypass MoveGroup's trajectory execution manager so you won't have any trajectory monitoring in this case, but to me this seems like the easiest and safest solution. |
Thanks for posting here as well, after the discussion in the meeting. This is a very interesting topic and this post got sort of long. Sorry in advance. You mentioned that the TrajectoryExecutionManager only runs a single thread. I have read some of the code today, and it is true that only one thread is launched at a time - in pushAndExecute or execute. But the fact that execution is in a separate thread makes me think that much of the heavy lifting towards simultaneous execution is already done. As you said, the MoveGroup's move and execute capabilities only run a SimpleActionServer, which only support one request. While it is true that each new goal causes the old action to be preempted, and thus a The plan service capability does get a It is also true that there is currently no trajectory validation/monitoring for motions that are being executed. But there is executeAndMonitor which is connected to the "Replanning" checkbox in our Rviz panel, does monitor the remaining path of a trajectory for collisions and has this entertaining comment questioning if it should live in
It has been a long time since I have tried that, but my lasting impression was that At least, that seems more feasible to me than namespacing each arm of a humanoid robot and trying to keep their planning scenes synchronized. But anyone with opinions about this architecture choice is warmly invited to comment.
Just for the record, I agree, and this is part of what I will be trying next myself. |
Thanks for answering to this. I think in my case sending preplanned trajectories directly to the controllers seems very viable as I am able to split the space for the arms into 'workspaces' so that they won't collide with each other ideally. I think I even saw a function to define these workspaces in the MoveGroupCommander. However, the purpose is to 'print' filament by adding flat boxes along the followed cartesian path. From my understanding that won't be possible because the planning scene needs to be locked if I use the mentioned approach. Additionally I was thinking to use the Perception feature for dynamic collision avoidance so that the arms would stop the trajectory if another arm enters a foreign workspace. Would that still be possible? Is locking the scene even necessary if the robot is split into workspaces and the (ideally) few cases of possible collisions are filtered out by perception? |
Hello guys, this issue seems to join lots of features, it took me a while to read all the documentation related to it.
I took a look at the tutorial for Perception and I wonder if it would be necessary to add the arm as a collision object for this to work. It can be a nice implementation, but I think the solution, as pointed out in GSoC's proposal of project is to do this avoidance dynamically. |
Let's assume a single URDF with two robot arms (planning groups). Both arms are already part of the collision environment, so they don't need to be added as collision objects. I'm not sure what you mean by "movement functions" or "spoiling the simulation". If you mean the trajectory, the TrajectoryExecutionManager would know all trajectories that are being executed, so you could access the current and future position of all planning groups relatively easily. |
Hello, going through the comments, it seems that the agreed upon way for simultaneous trajectory execution is by sending FollowJointTrajectory actions to the ros controllers.
If I interpret this correctly, this means that by leveraging the TrajectoryExecutionManager we can check for all potential cases of |
This interface will definitely not change, yes.
A few thoughts, not only for you:
Finally, importantly:
|
Thank you for the pointers, especially the idea of using merged trajectories, I will try to keep them in mind while coming up with a solution.
Got it, as mentioned earlier(discord), I have been able to run multiple robot arms. I will proceed to write a short tutorial for this and open a PR against #465 |
I did not read this thread before because the name did not at all represent the discussed problem, but @felixvd pointed me here in another related issue. Missing support for multiple simultaneous trajectories It is a (among maintainers) well-known shortcoming of the execution engine. As mentioned here multiple times, clearly, it should be possible to send trajectories to different controllers and sending them directly to the controllers is possible. Henning mentioned many points above, but from my perspective the main limiting factor is the current choice to implement |
I have been able to execute multiple trajectories asynchronously using separate instances of the TrajectoryExecutionManager running in their own thread launched with the std::package_task construct. An overly simplified snippet of that is as follows: // declare type aliases
using ExecStatus = moveit_controller_manager::ExecutionStatus;
// declare and initialize moveitcpp
moveit::planning_interface::MoveItCppPtr planning_interface_ = ... ; // MoveItCpp is only used to gain access to the robot model and planning scene monitor
...
// declare trajectories and controller names
std::vector<moveit_msgs::RobotTrajectory> trajectories = ...
std::vector<std::string> controller_name = {"fake_arm1_controller", "fake_arm2_controller", ...};
// declare vector for storing futures
std::vector<std::shared_future<ExecStatus>> exec_futures;
for(std::size_t i =0; i < trajectories.size(); i++)
{
auto traj = trajectories[i];
std::string controller_name = controller_names[i];
// instantiate controller
trajectory_execution_manager::TrajectoryExecutionManagerPtr traj_exec_mngr = std::make_shared< trajectory_execution_manager::TrajectoryExecutionManager>(
planning_interface_->getRobotModel(), planning_interface_->getPlanningSceneMonitorNonConst()->getStateMonitorNonConst(), false);
// create packaged task with lambda that executes the trajectory
std::packaged_task< ExecStatus ()> async_task ([traj_exec_mngr, traj, controller_name]() -> ExecStatus{
traj_exec_mngr->push(traj.joint_trajectory, controller_name);
traj_exec_mngr->execute([](const moveit_controller_manager::ExecutionStatus& st){
ROS_INFO_COND(st,">>>> Trajectory completed");
ROS_ERROR_COND(!st,"Trajectory failed");
});
moveit_controller_manager::ExecutionStatus st = traj_exec_mngr->waitForExecution();
traj_exec_mngr->stopExecution(true); // don't know if this is necessary
traj_exec_mngr->clear();
return st;
});
// get shared future and store
exec_futures.push_back(std::shared_future<ExecStatus>(async_task.get_future()));
// move task into new thread
std::thread t(std::move(async_task));
t.detach();
}
// wait for threads to complete
while(ros::ok() && loop_pause.sleep())
{
if(std::all_of(exec_futures.begin(), exec_futures.end(),[](std::shared_future<ExecStatus>& f){
std::future_status st = f.wait_for(std::chrono::duration<double>(0.01));
return st == std::future_status::ready;
}))
{
break;
}
}
|
Does this give you an advantage over sending the trajectory directly to the robot driver? It would still leave you without collision checking between the trajectories from what I can see. |
Does this give you an advantage over sending the trajectory directly to the robot driver?
It would still leave you without collision checking between the trajectories from what I can see.
It's only a partial way out, but at least it gives you the usual monitoring / online validity checking for each trajectory separately.
It should even find potential future collisions if one robot moves into the executing future trajectory of the other one.
|
You are right. I'm unsure about the resulting computational overhead, so I won't propose to add that logic there just now. So the only thing you really gain when using the upstream repository is monitoring of the trajectory duration (mostly to catch controllers that fail to respond), but it's just a few lines to get partial collision checking too 🐈 |
I've been thinking lightly about this. Instantiating multiple In plan_execution.cpp, I guess it would be *In an earlier post I thought about merging two |
I was playing around with the idea of @jrgnicho to spawn one Reading the TrajectoryExecutionManager in more detail, it seems like there are two redundant entry points: Seeing as there is already functionality in TEM to work through a queue of trajectories, extending it appears to be the best option. Instead of executing the trajectories one-by-one, the My only concern is that the TEM currently does not have a notion of safety, but it would need to be able to check if two robot trajectories collide or not. But it owns a |
Dear all, I am working with two real panda robots. I built a MoveIT package for interface with the two panda robots and it works fine in the simulator. Then, I configured the controllers.yaml to act with the real two robots via the combined_panda/effort_joint_trajectory_controller and I can read and visualize the robots state/joints values (/combined_panda/joints) in the Rviz. I have three planning groups in the moveIT package. From rviz, I can control both robots (combined_panda planning group) to reach different/random poses, and it is working fine. But I can not control one robot separately (I can not use ( panda_1 planning group or panda_2 planning group), it gives the following error, So, I run different move_groups on a script: When I worked with the combined group (14 joints → which has the two subgroups (panda_1 and panda_2)), and I set a target pose for every robot (panda_1 and panda_1) and execute them from one planning group by setting the pose target and gripper link of every robot. It give me these error: Can anyone help me in this regard ? |
In case it helps, here are my comments on trying to work this issue around with the two methods discussed above. Please, note that my comments reference Namespacing
|
Description
Hi,
I'm trying to move 4 move groups on 1 robot simultaneously. I have found out that it is not easy to do so as all of the 4 motion plans pipe into the same action server. However there were some suggestions to use the async_move() function of the move_group class which should provide this functionality. This can be activated by setting
group.go(wait=False)
. However executing this did not change any behavior, all of the 4 groups are still moved one after another. Any help will be appreciated.Your environment
Expected behaviour
Groups should be moved simultaneously
Actual behaviour
Same behavior as with wait=True, groups move one after another
The text was updated successfully, but these errors were encountered: