ManyMove Repo on Nvidia Isaac ROS

Quick Start for ManyMove Repo on Nvidia Isaac ROS

Hi, I’m Marco from Italy, and I’m building a repo that handles planning/execution, collision objects, signals, HMI, and logic with behavior trees.

I’m building it for myself to use: I’m a roboticist and an end user, I usually program in RAPID or KRL. I needed to deploy some new applications with another brand of robots that supports ROS natively, so instead of learnin yet another language I decided to go with ROS. and I’m quite new to ROS. Transitioning from industrial robotics languages to ROS has proven quite a challenge, and I structured the repository I wrote to resemble some of the concepts I’m used to in industrial automation. I tried to take a step further and use behaviortrees to implement the control logic, as it can make handling complex programs a bit easier.

I’m sharing this because I would love to receive some feedback, either on the ManyMove package itself or on how to better reshape it to fully leverage the Isaac Manipulator workflow. As I said, I’m building it for myself as an end user, and if I can make it usable for everyone it would be consequently more usable for myself too!
Here’s the link:
https://github.com/pastoriomarco/manymove

My end goal is to deploy a bin picking solution with NVIDIA Jetson Orin. For now, I’m almost operational on a pick-and-place solution that uses all standard ROS packages for ROS2 Humble, like MoveIt, OMPL, and so on. I’ll thoroughly test the Isaac Manipulator workflow and packages, but I really need to deploy a couple of robots in production first.

WARNING: it’s still highly experimental. If you try it, be aware that stability and safety are not guaranteed: use at your own risk! Read all the instructions and disclaimers before trying it.

I already created a draft launcher and application with isaac_ros_cumotion and Ufactory Lite6 cobot.

For now it only works on ROS2 Humble. Don’t try the Jazzy version yet, it won’t work.

Here’s a little step-by-step to try it out:

Step 1: Developer Environment Setup

First, set up the compute and developer environment by following Nvidia’s instructions:

Step 2: Follow isaac_ros_cumotion_moveit Tutorial

Complete the isaac_ros_cumotion_moveit tutorial, preferably using the “build from source” tab (it’s the only one I tested):
https://nvidia-isaac-ros.github.io/repositories_and_packages/isaac_ros_cumotion/isaac_ros_cumotion_moveit/index.html
Verify that the example with the Franka robot works before proceeding!

ATTENTION: Step 3 needs to be run from inside the Docker container, so AFTER you run these lines from the above link for isaac_ros_cumotion_moveit tutorial:

cd ${ISAAC_ROS_WS}/src/isaac_ros_common && \
  ./scripts/run_dev.sh

Also, inside the container you must have already built isaac_ros_cumotion_examples:

sudo apt-get update
rosdep update && rosdep install --from-paths ${ISAAC_ROS_WS}/src/isaac_ros_cumotion --ignore-src -y
cd ${ISAAC_ROS_WS} && \
   colcon build --packages-up-to isaac_ros_cumotion_examples
source install/setup.bash

Step 3: Install xarm_ros2 and ManyMove Packages

Now you should be inside the first terminal with isaac_ros_cumotion_examples built and sourced.

To install xarm_ros2 and manymove you may follow the instructions from each package.

The example behaviortree logic is based on BehaviorTree.CPP v3.8, so you can install the old version of Groot to visualized. You can install it outside the container, as inside it would not compile as is.

To save you some time, here are the direct commands to install and build both packages, copy the required files on the correct folders and start cuMotion to receive commands:

cd ${ISAAC_ROS_WS}/src

git clone https://github.com/pastoriomarco/xarm_ros2.git --recursive -b $ROS_DISTRO
git clone --branch=humble https://github.com/pastoriomarco/manymove.git

cd ${ISAAC_ROS_WS}/src/xarm_ros2
git pull
git submodule sync
git submodule update --init --remote

cd ${ISAAC_ROS_WS}/src
rosdep update
rosdep install --from-paths . --ignore-src --rosdistro $ROS_DISTRO -y

mkdir -p ${ISAAC_ROS_WS}/src/xarm_ros2/xarm_description/meshes/other

cp ${ISAAC_ROS_WS}/src/manymove/manymove_object_manager/meshes/custom_end_tools/* ${ISAAC_ROS_WS}/src/xarm_ros2/xarm_description/meshes/other/
cp ${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/xarm_user_params.yaml ${ISAAC_ROS_WS}/src/xarm_ros2/xarm_api/config/
cp ${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/cuMotion/lite6_gr.xrdf ${ISAAC_ROS_WS}/src/xarm_ros2/xarm_description/urdf/lite6/lite6_gr.xrdf
cp ${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/cuMotion/lite6.urdf ${ISAAC_ROS_WS}/src/xarm_ros2/xarm_description/urdf/lite6/lite6.urdf
cp ${ISAAC_ROS_WS}/src/isaac_ros_cumotion/isaac_ros_cumotion_moveit/config/isaac_ros_cumotion_planning.yaml ${ISAAC_ROS_WS}/src/xarm_ros2/xarm_moveit_config/config/moveit_configs

cd ${ISAAC_ROS_WS}
colcon build --packages-skip realsense_gazebo_plugin
colcon build --packages-skip realsense_gazebo_plugin xarm_gazebo

source install/setup.bash
ros2 run isaac_ros_cumotion cumotion_planner_node --ros-args \
  -p robot:=${ISAAC_ROS_WS}/src/xarm_ros2/xarm_description/urdf/lite6/lite6_gr.xrdf \
  -p urdf_path:=${ISAAC_ROS_WS}/src/xarm_ros2/xarm_description/urdf/lite6/lite6.urdf

Yes, I know, there are 2 consecutive “colcon build”, it’s a workaround for the xarm_gazebo that is not compiling on the Isaac ROS container. I’m sure it’s solvable, but if I use Isaac ROS I would rather aim at using Isaac SIM instead of Gazebo, so I’m not investing time in it for now.


After cuMotion warms up, you can launch ManyMove example with lite6 robot.
In a new terminal, start the container first:

cd ${ISAAC_ROS_WS}/src/isaac_ros_common && \
  ./scripts/run_dev.sh

Then, from inside the container:

cd ${ISAAC_ROS_WS}
source install/setup.bash

ros2 launch manymove_planner lite_cumotion_movegroup_fake_cpp_trees.launch.py

That should do it. Now you can press start on the HMI to run the cycle.

I’m quite tight on time and I couldn’t build a decent documentation yet, let me know if you need some info to test it out!
I’ll try to add some detail about the various files to modify to adapt it to different applications in the ROS Discourse Topic.

1 Like

A little update: since I created the manymove_bringup package you have to use that to launch the cumotion example, so the last command will be:

cd ${ISAAC_ROS_WS}
source install/setup.bash


ros2 launch manymove_planner lite_cumotion_movegroup_fake_cpp_trees.launch.py

Some features of ManyMove:

  • Cartesian speed limit for all types of moves: it lets you stay within the mandatory cartesian speed limits for cobots without having to tune down too much velocity and acceleration scaling, boosting cycle times.
  • Real time collision check on all trajectories: enables working with multiple robots on the scene and in dynamic environments, while still using the basic Moveit2 functionalities. (Still to test thoroughly with cumotion!)
  • Robot-brand agnostic: you just need a functioning moveit config for your robot to load it up on ManyMove.
  • Logic built on Behavior Trees: it eases the construction of complex logic cycles. All the logic is build programmatically, and can be checked at runtime on the tree visualizer.
  • Simple HMI dinamically interacting with the Behavior Tree through ROS2 services.

An example of application with two robots interacting:

Screencast from 04-15-2025 10_23_02 AM


Also consider that the huge behavior tree shown in the picture can be summed up in code with this snippet:

    // General startup sequence:
    std::string startup_sequence_xml = sequenceWrapperXML(
        "StartUpSequence",
        {
            spawn_fixed_objects_xml,
            reset_movable_objects_xml,
            reset_graspable_objects_xml,
            parallel_sub_startup_sequences_xml,
        });

    // ROBOT 1
    // Repeat node must have only one children, so it also wrap a Sequence child that wraps the other children
    std::string repeat_forever_wrapper_1_xml = repeatSequenceWrapperXML(
        "RepeatForever",
        {
            go_to_ready_pose_1_xml,                       //< Go to ready position
            set_robot_1_out_of_working_position,          //< Signal robot 1 out of working position
            wait_for_cycle_on,                            //< Wait for robot cycle to be on
            spawn_graspable_object_1_xml,                 //< Add the graspable object to the scene
            reset_movable_objects_xml,                    //< Reset and reload the movable objects in the scene
            get_grasp_object_poses_1_xml,                 //< Get the updated poses relative to the graspable object
            go_to_pick_pose_1_xml,                        //< Pick move sequence
            close_gripper_1_xml,                          //< Attach the object
            go_to_wait_pose_1_xml,                        //< Go to wait pose
            wait_for_robot_2_out_of_working_position_xml, //< Wait for other robot out of working position
            wait_for_renamed_obj_removed_xml,             //< Wait for other robot to unload the graspable object
            go_to_drop_pose_1_xml,                        //< Drop move sequence
            set_robot_1_in_working_position_xml,          //< Signal robot 1 in working position
            wait_for_robot_2_in_working_position_xml,     //< Wait for other robot to be in working position
            open_gripper_1_xml,                           //< Detach the object
            rename_obj_1_xml,                             //< Rename the object for the other robot to use
        },
        -1); //< num_cycles=-1 for infinite

    // ROBOT 2
    // Repeat node must have only one children, so it also wrap a Sequence child that wraps the other children
    std::string repeat_forever_wrapper_2_xml = repeatSequenceWrapperXML(
        "RepeatForever",
        {
            go_to_ready_pose_2_xml,                       //< Go to ready position
            set_robot_2_out_of_working_position_xml,      //< Signal robot 2 out of working position
            wait_for_robot_1_in_working_position_xml,     //< Wait for other robot in working position
            get_grasp_object_poses_2_xml,                 //< Get the updated poses relative to the renamed graspable object
            get_load_poses_from_endplate_xml,             //< Get the updated pose from the machine's end plate
            go_to_insert_pose_2_xml,                      //< Go to insert pose
            set_robot_2_in_working_position,              //< Signal robot 2 in working position
            wait_for_robot_1_out_of_working_position_xml, //< Wait for other robot out of working position
            wait_for_renamed_drop_obj_xml,                //< Wait for other robot to release the graspable object and rename it
            attach_obj_2_xml,                             //< Attach the renamed graspable object
            go_to_load_pose_2_xml,                        //< Load sequence
            go_to_exit_pose_2_xml,                        //< Exit sequence
            detach_obj_2_xml,                             //< Detach the object
            remove_obj_2_xml,                             //< Delete the object for it to be added on the next cycle in the original position
        },
        -1); //< num_cycles=-1 for infinite

    // Runningh both robot sequences in parallel:
    std::string parallel_repeat_forever_sequences_xml = parallelWrapperXML("PARALLEL_MOTION_SEQUENCES", {repeat_forever_wrapper_1_xml, repeat_forever_wrapper_2_xml}, 2, 1);

    std::string retry_forever_wrapper_xml = retrySequenceWrapperXML("RetryForever", {startup_sequence_xml, parallel_repeat_forever_sequences_xml}, -1);

    // MasterSequence with startup sequence and RepeatForever as child to set BehaviorTree ID and root main_tree_to_execute in the XML
    std::vector<std::string> master_branches_xml = {retry_forever_wrapper_xml};
    std::string master_body = sequenceWrapperXML("GlobalMasterSequence", master_branches_xml);

Sorry! I didn’t update the command!
Here’s the right one to start the example with lite6 robots, to run from inside the container:

cd ${ISAAC_ROS_WS}

source install/setup.bash

ros2 launch manymove_bringup lite_cumotion_movegroup_fake_cpp_trees.launch.py

I updated the example so it does a bit of obstacle avoidance: ManyMove checks for collisions in real time, but do I also need to use cuMotion’s isaac_ros_cumotion_object_attachment for cuMotion to “see” the attached object?

Right now the gripper is a pneumatic gripper with no moving parts represented, and it’s the standard gripper for lite6 cobots. I’ll proceed to create an example with a controlled 2 jaws gripper.

Does anyone have suggestions on how to structure a pneumatic 2 finger gripper with simmetrical movement of the fingers?

Conceptually it works as the Panda hand gripper, but I can’t seem to find some reference or examples on the right way to define a pneumatic gripper so it’s activated through signals but the fingers apply a certain force to open/close.

Ok, I added an example with the standard Panda robot, using the same data included in isaac_ros_cumotion_moveit examples.
For updated info on ManyMove you can refer the new ROS Discourse topic.
Here’s an updated step by step to run both ManyMove examples:

Step 1: Developer Environment Setup

First, set up the compute and developer environment by following Nvidia’s instructions:

Step 2: Follow isaac_ros_cumotion_moveit Tutorial

Complete the isaac_ros_cumotion_moveit tutorial, preferably using the “build from source” tab (it’s the only one I tested): isaac_ros_cumotion_moveit

Verify that the example with the Franka robot works before proceeding!

ATTENTION: before executing Step 3, start the Docker container in TERMINAL 1, install and compile isaac_ros_cumotion_moveit package and dependencies:

cd ${ISAAC_ROS_WS}/src/isaac_ros_common && \
./scripts/run_dev.sh

Also, inside the container you must have already built isaac_ros_cumotion_examples:

sudo apt-get update
rosdep update && rosdep install --from-paths ${ISAAC_ROS_WS}/src/isaac_ros_cumotion --ignore-src -y

cd ${ISAAC_ROS_WS} && \
colcon build --packages-up-to isaac_ros_cumotion_examples

source install/setup.bash

Step 3: Install xarm_ros2 and ManyMove Packages

Now you should be inside the docker container in TERMINAL 1 with isaac_ros_cumotion_examples built and sourced.
Install and build ManyMove and xarm_ros2 packages:

cd ${ISAAC_ROS_WS}/src
git clone https://github.com/pastoriomarco/xarm_ros2.git --recursive -b $ROS_DISTRO
git clone --branch=$ROS_DISTRO https://github.com/pastoriomarco/manymove.git

cd ${ISAAC_ROS_WS}/src/xarm_ros2
git pull
git submodule sync
git submodule update --init --remote

cd ${ISAAC_ROS_WS}/src/manymove
git pull

cd ${ISAAC_ROS_WS}/src
rosdep update
rosdep install --from-paths . --ignore-src --rosdistro $ROS_DISTRO -y

mkdir -p ${ISAAC_ROS_WS}/src/xarm_ros2/xarm_description/meshes/other
cp ${ISAAC_ROS_WS}/src/manymove/manymove_object_manager/meshes/custom_end_tools/* ${ISAAC_ROS_WS}/src/xarm_ros2/xarm_description/meshes/other/
cp ${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/xarm_user_params.yaml ${ISAAC_ROS_WS}/src/xarm_ros2/xarm_api/config/

cd ${ISAAC_ROS_WS}
colcon build --packages-skip realsense_gazebo_plugin
colcon build --packages-skip realsense_gazebo_plugin xarm_gazebo

source install/setup.bash

Step 4: Run the examples:

Franka Panda:

  1. In TERMINAL 1 start cumotion_planner_node and wait for it to warm up:
ros2 run isaac_ros_cumotion cumotion_planner_node --ros-args \
  -p robot:=${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/cuMotion/franka.xrdf \
  -p urdf_path:=/opt/ros/humble/share/moveit_resources_panda_description/urdf/panda.urdf
  1. In TERMINAL 2, first enter the the docker container:
cd ${ISAAC_ROS_WS}/src/isaac_ros_common && \
  ./scripts/run_dev.sh
  1. From inside the docker container in TERMINAL 2, source the workspace and run the example:
source ${ISAAC_ROS_WS}/install/setup.bash
ros2 launch manymove_bringup panda_cumotion_movegroup_fake_cpp_trees.launch.py

Ufactory Lite6:

  1. In TERMINAL 1 start cumotion_planner_node and wait for it to warm up:
ros2 run isaac_ros_cumotion cumotion_planner_node --ros-args \
  -p robot:=${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/cuMotion/lite6_gr.xrdf \
  -p urdf_path:=${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/cuMotion/lite6.urdf
  1. In TERMINAL 2, first enter the the docker container:
cd ${ISAAC_ROS_WS}/src/isaac_ros_common && \
  ./scripts/run_dev.sh
  1. From inside the docker container in TERMINAL 2, source the workspace and run the example:
source ${ISAAC_ROS_WS}/install/setup.bash
ros2 launch manymove_bringup lite_cumotion_movegroup_fake_cpp_trees.launch.py

lite6

I just tried ManyMove with cuMotion planning pipeline on a Jetson Orin Agx Developer Kit and it runs just fine!

The only caveat: you may need to update the ros-humble-rclcpp* repos to solve a racing condition bug:

sudo apt install ros-humble-rclcpp*
1 Like

New update to further ease the setup tested on x86_64 and Jetson Orin AGX Developer Kit:

Step 1: Developer Environment Setup

First, set up the compute and developer environment by following Nvidia’s instructions:

It’ very important that you completely follow the above setup steps for the platform you are going to use. Don’t skip the steps for Jetson Platform if that’s what you are using, including VPI.

Step 2: Download and run the setup script

Download manymove_isaac_ros_startup.sh, make it executable and run it. It will download all the packages tested with ManyMove and Isaac ROS.

Step 3: Check isaac_ros_common-config

Since I’m working with realsense cameras, the current config includes the realsense package. If you are using them too, skip this step.

If you don’t need it, modify the following file with your favorite editor:

${ISAAC_ROS_WS}/src/isaac_ros_common/scripts/.isaac_ros_common-config

Remove .realsense step from the config line from:

CONFIG_IMAGE_KEY=ros2_humble.realsense.manymove

To:

CONFIG_IMAGE_KEY=ros2_humble.manymove

Step 4: Launch the Docker container

Launch the docker container using the run_dev.sh script:

cd ${ISAAC_ROS_WS}/src/isaac_ros_common && \
   ./scripts/run_dev.sh

Step 5: Run the examples:

Franka Panda:

  1. In TERMINAL 1 start cumotion_planner_node and wait for it to warm up:
ros2 run isaac_ros_cumotion cumotion_planner_node --ros-args \
  -p robot:=${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/cuMotion/franka.xrdf \
  -p urdf_path:=/opt/ros/humble/share/moveit_resources_panda_description/urdf/panda.urdf
  1. In TERMINAL 2, first enter the the docker container:
cd ${ISAAC_ROS_WS}/src/isaac_ros_common && \
  ./scripts/run_dev.sh
  1. From inside the docker container in TERMINAL 2, source the workspace and run the example:
source ${ISAAC_ROS_WS}/install/setup.bash
ros2 launch manymove_bringup panda_cumotion_movegroup_fake_cpp_trees.launch.py

Ufactory Lite6:

  1. In TERMINAL 1 start cumotion_planner_node and wait for it to warm up:
ros2 run isaac_ros_cumotion cumotion_planner_node --ros-args \
  -p robot:=${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/cuMotion/lite6_gr.xrdf \
  -p urdf_path:=${ISAAC_ROS_WS}/src/manymove/manymove_planner/config/cuMotion/lite6.urdf
  1. In TERMINAL 2, first enter the the docker container:
cd ${ISAAC_ROS_WS}/src/isaac_ros_common && \
  ./scripts/run_dev.sh
  1. From inside the docker container in TERMINAL 2, source the workspace and run the example:
source ${ISAAC_ROS_WS}/install/setup.bash
ros2 launch manymove_bringup lite_cumotion_movegroup_fake_cpp_trees.launch.py
1 Like