3. Physics Simulator Setup
The MoveIt Pro Simulator uses MuJoCo as its underlying simulation engine. This means in order to set up the MoveIt Pro Simulator, you must create a MuJoCo Modeling XML File (MJCF) that defines the robot and the environment. The easiest way to create this file is by starting with your existing URDF file.
This how-to guide will walk through the URDF to MJCF migration process.
Configuration package references:
MJCF references:
Create the MuJoCo config
Create a new config based on the site config called [robot_name]_mujoco_config
and create the [robot_name]_mujoco_config/description/mujoco/assets
directory.
The assets
directory will be populated with all the collision and visual files for the robot. You can populate this directory manually, or use a script to copy the files over automatically (see below).
If the visual files are currently in the .dae
format, use Blender or Meshlab to convert them to .obj
files. The .stl
file format is also accepted by MuJoCo.
- Note 1: Make sure the axes are aligned correctly when you export the
.obj
files from Blender. You may need to change the "Up Axis" to Z and the "Forward Axis" to X when you export. - Note 2: May need to use the obj2mjcf tool to create
.obj
files that have material information embedded in them. This tool can also perform convex mesh decomposition if needed.
The file structure beneath the description
directory should resemble the following:
description
├── mujoco
│ ├── assets
└── robot_description.xacro
Other configuration package changes
- In the
[robot_name]_mujoco_config/config/config.yaml
file, make sure to change all package references from[robot_name]_base_config
to[robot_name]_mujoco_config
.
Prepare the robot description xacro
Use the MujocoSystem plugin
Change the xacro defining your robot's <ros2_control>/<hardware>
tag to use the picknik_mujoco_ros/MujocoSystem
plugin.
Refer to the example in our lab_sim example here.
We recommend exposing mujoco_model
as a xacro argument to enable quickly switching the robot between simulated worlds.
Optional Params
MuJoCo Interactive Viewer
You can launch MuJoCo's interactive viewer (in passive mode) on startup and safely use it in parallel with commands sent by your Objectives.
Do this by setting the mujoco_viewer
parameter to true
in the above MujocoSystem plugin.
Learn more about the interactive viewer's capabilities in this video.
Ignore Joint Validation
-
By default, the simulation enforces that every joint in the URDF exists in the MJCF model. You may want to skip this in cases where the joint isn't intended to be simulated, e.g. mock joints.
-
A list of joints to ignore can be specified using the
ignore_joint_validation
parameter.<ros2_control>
<hardware>
<plugin>picknik_mujoco_ros/MujocoSystem</plugin>
...
<param name="ignore_joint_validation">linear_x_joint linear_y_joint rotational_yaw_joint</param>
</hardware>
</ros2_control>
Retrieve the rendered URDF of the robot
This guide assumes you generate a URDF file for your robot from a xacro file. If you already have a URDF file, you can skip to the next section.
You can generate a rendered URDF file from the non-MuJoCo MoveIt Pro site config using the following commands.
-
Run the non-MuJoCo MoveIt Pro site config:
moveit_pro run -v
-
Enter the MoveIt Pro Docker container:
moveit_pro shell
-
Copy the auto-generated URDF file from the
/robot_description
topic to a file.ros2 topic echo --once --field data --full-length /robot_description | head -n -1 > ~/user_ws/robot_description.urdf
Prepare the rendered URDF for conversion
Copy your robot_description.urdf
file into the [robot_name]_mujoco_config/description
directory.
Manipulators with a mobile base
If you are migrating just an arm to MuJoCo, skip this section.
For mobile bases/manipulators, additional processing of the URDF is required so that the MJCF is properly generated.
In the URDF, if the root link is base_link
of the robot, an additional joint needs to be added so that the MuJoCo URDF to MJCF compiler properly nests bodies in the MJCF.
In the URDF, add the following frame and joint:
<link name="base_link_reference">
<joint name="base_link_reference_to_base_link" type="floating">
<origin rpy="0 0 0" xyz="0 0 0"/>
<parent link="base_link_reference"/>
<child link="base_link"/>
</joint>
Generating MuJoCo xml from the rendered URDF
Move files into a flat directory
MuJoCo does not have a built-in mechanism for resolving package://
URIs or relative paths. We provide a utility to locate meshes referenced in a URDF and copy them into the current directory.
Inside your moveit_pro shell
terminal, run the following commands.
cd ~/user_ws/src/[robot_name]_mujoco_config/description/assets
ros2 run moveit_studio_utils_py flatten_meshes ../robot_description.urdf
If this script fails to locate the mesh files for your robot, you may need to copy into the assets
directory manually.
This step is necessary in order to complete the MJCF conversion. After the conversion, you may need to modify the location of the meshes in your MJCF file.
PickNik Accessories
The picknik_accessories package contains reusable xml scenes and components. To use them with an XML in another package, the symlinks from picknik_accessories can be copied over to the package’s install folder that contains the top level XML. See here.
Compile your MuJoCo xml
MuJoCo provides a compile
utility to convert URDF to MJCF. We wrap this utility with additional post-processing functions that are often helpful.
Now we will start running the conversion script and resolve some possible warnings and errors. It may be necessary to run this script several times until all errors are addressed. At the end of this step we will have the beginning of a functional mujoco model.
Inside your moveit_pro shell
terminal, run the following commands.
cd ~/user_ws/src/[robot_name]_mujoco_config/description
ros2 run moveit_studio_utils_py urdf_to_mjcf robot_description.urdf
Possible WARNING: Geom with duplicate name
Geom with duplicate name '' encountered in URDF, creating an unnamed geom.
This is expected, as most URDFs do not name these tags.
<collision name="link1_collision">
<geometry>
<box size="1 1 1"/>
</geometry>
</collision>
<visual name="link1_visual">
<geometry>
<box size="1 1 1"/>
</geometry>
</visual>
We do not need mujoco to name the geoms so this is fine.
Possible ERROR: Error opening file
Error opening file 'temp/base_link.STL': No such file or directory
This is typically a sign you forgot to copy a file into your flat "temp" directory.
Possible ERROR: Mesh decimation
To improve collision checking performance, MuJoCo limits the number of faces that can be in a mesh file.
Error: number of faces should be between 1 and 200000 in STL file 'temp/base_link.stl'; perhaps this is an ASCII file? Element name 'body', id 0
We have a built in tool for decimating meshes to reduce the number of faces. You may need to run it multiple times for large files.
decimate_mesh base_link.stl base_link.stl
Possible ERROR: Missing inertia
Some URDF generating tools may only generate partial dynamics information in the exported URDF. This is important information for physics engines and must be included.
Either:
- Generate missing values in CAD software and copy over to xacro
- Regenerate URDF in temp folder
- If the missing values cannot be easily generated, delete the partially populated inertial tag. MuJoCo will by default provide a guess of the values via inertiafromgeom. You can use these values initially and resolve the inaccuracies later.
- You can get a sanity check of the inertia values it generates via the Inertia Rendering capability.
- TODO would be nice to find a way to extract these estimates, so we could have the inertia matrix, but set our own mass estimate (to a low value) to make the actuators more responsive.
Change
<link name="left_arm_wrist_link_x"/>
To
<link name="left_arm_wrist_link_x">
<inertial>
<origin rpy="0 0 0" xyz="0 0 0"/>
<mass value="0.05"/>
<inertia ixx="1.0E-05" ixy="0" ixz="0" iyy="1.0E-05" iyz="0" izz="1.0E-05"/>
</inertial>
</link>
Final config contents
When the urdf_to_mjcf
script completes without errors, your mujoco_config
should have the following structure:
my_robot_mujoco_config
├── description
│ ├── robot_description.urdf
│ ├── base_link.obj
│ ├── base_link.STL
│ │ └── ...
│ ├── robot.xml # generated by urdf_to_mjcf
│ └── scene.xml
Modify the MJCF file
Gravcomp
To simulate arms with brakes that hold the arm in place when it is not actively commanded, we add gravity compensation to robot bodies. This also makes tuning actuator strength simpler.
Gravity compensation can be added to a body by adding the gravcomp="1"
attribute to the <body>
tag.
This is done automatically by the urdf_to_mjcf
script. If you don't want gravcomp on a body, you can remove it by changing the body
tags in the robot_description.xml
file from:
<body name="link1" gravcomp="1">
...
</body>
back to:
<body name="link1">
...
</body>
Use implicitfast integration
The default Euler integration typically does not perform well for the instructions in this guide. Use implicitfast integration with multi contact consideration.
<mujoco>
<option integrator="implicitfast">
<flag multiccd="enable" />
</option>
...
MujoCo Keyframes
You can start the simulation with a specific keyframe (including initial joint values) as specified in the MJCF file:
-
Capture the keyframe the qpos entry for a keyframe by launching with the MuJoCo interactive viewer, expanding the
Simulation
left sidebar, and clickingCopy pose
. -
Paste the keyframe output to your MJCF file. Optionally add a name if you paste in multiple keyframes.
Name all your keyframes so they are accessible by the ResetMujocoKeyframe
Behavior.
Name your first keframe 'defaut' to work with the Reset MuJoCo Sim
Objective.
<keyframe>
<key
name='default'
qpos='0 0 0 0 0 0'
/>
<key
name='ones'
qpos='1 1 1 1 1 1'
/>
</keyframe>
...
</mujoco>
Some configurations may also require recording the ctrl
values, but this is rare.
-
If keyframes are specified in the MJCF, the simulation will default to the first keyframe.
-
You can launch a specific, named keyframe by referencing it in the xacro defining your robot's
<ros2_control>/<hardware>
tag:<ros2_control>
<hardware>
<plugin>picknik_mujoco_ros/MujocoSystem</plugin>
...
<param name="mujoco_keyframe">ones</param>
</hardware>
</ros2_control>Alternatively, using the interactive viewer, you can load a specific keyframe by expanding the
Simulation
left sidebar, dragging theKey
value to the index of the keyframe you want to load, and clickingLoad Key
.
For complex scenes with many objects, the keyframe can be quite large.
The starting joint values of the robot will be the last X items in the keyframe qpos
, where X is the ordered list of joints in the interactive viewer's Joint
right sidebar.
You can use this knowledge to quickly iterate additional keyframes from an initial keyframe.
Simulated Sensors
All <site>
tags with a name
attribute defined in the MJCF file will be picked up by the MuJoCo ros2_control
plugin and published to tf2.
The transforms will be published in world
frame.
Like a physical sensor, our simulated sensors do not know where they are mounted and do not include this transform information along with their sensor data.
A controller and/or broadcaster is typically configured with the additional information of what frame the sensor has been mounted at.
Simulated Force Torque Sensor
- Add a site for the FTS pose in the MJCF file.
The simulator will publish the transform of the site at the rate defined by
tf_publish_rate
. Refer to thetcp_fts_sensor
site in our lab_sim example here. - Add
<force>
and<torque>
tags referencing the site in the MJCF file. The created hardware interface will have the same name as the site. Refer to the tags referencingtcp_fts_sensor
in our lab_sim example here. - Optionally, add a FTS broadcaster to your ros2_control configuration yaml to publish the values to a ROS topic. Refer to the force_torque_sensor_broadcaster declaration and definition in our lab_sim example here.
- Optionally, add a VelocityForceController to your ros2_control configuration yaml to directly leverage the simulated hardware interface. Refer to the velocity_force_controller declaration and definition in our lab_sim example here.
Simulated Depth Camera Sensor
-
Add a
<camera>
sensor tag and a<site>
tag corresponding to the camera frame and camera optical frame, respectively. Refer to thewrist_camera
andwrist_camera_optical_frame
tags in our lab_sim example here.- Positive X points to right of camera.
- Positive Y points up towards the top of the camera.
- Positive Z points to behind the camera.
The camera optical frame should be set to the
<camera>
position rotated 180 degrees about its x-axis.tipWhen using MuJoCo's interactive viewer, you can quickly obtain the
<camera>
and<site>
definitions for a scene camera by adjusting your viewpoint and copying the equivalent camera pose using theCopy camera
button under theRendering
tab on the left hand side of the viewer. You can paste the camera position in your XML description, which will contain a position (pos
) and orientation (xyaxes
). Be sure to add thename
,fovy
,mode
, andresolution
, as shown in the example above. To determine the camera optical frame, multiply the cameraxyaxes
orientation by1 1 1 -1 -1 -1
and use the same position as the camera. -
Add a
render_publish_rate
param in theros2_control
hardware section of the robot description file. Refer to the example in our lab_sim example here.
When using MuJoCo's interactive viewer, you can quickly obtain the <camera>
and <site>
definitions for a scene camera by adjusting your viewpoint and copying the equivalent camera pose using the Copy camera
button under the Rendering
tab on the left hand side of the viewer.
You can paste the camera position in your XML description, which will contain a position (pos
) and orientation (xyaxes
).
Be sure to add the name
, fovy
, mode
, and resolution
, as shown in the example above.
To determine the camera optical frame, multiply the camera xyaxes
orientation by 1 1 1 -1 -1 -1
and use the same position as the camera.
Simulated Lidar Sensor
-
Add a site for each lidar laser angle using the
<replicate>
tag in the MJCF along with a<rangefinder>
. Ex:<replicate count="360" sep="-" offset="0 0 0" euler="0.0174533 0 0">
<site name="lidar" size="0.01" pos="-0.075 0.0 0.0" quat="0.0 0.0 0.0 1.0"/>
</replicate>
...
<sensor>
<rangefinder site="lidar" user="0.1 -3.14159 3.14159 0.0174533 0.1 6.0"/>
</sensor> -
Add a
lidar_publish_rate
param in theros2_control
hardware section of the robot description file. Ex:<ros2_control>
<hardware>
<plugin>picknik_mujoco_ros/MujocoSystem</plugin>
...
<param name="lidar_publish_rate">10</param>
</hardware>
</ros2_control>
Additional steps for a mobile manipulator
If trying to migrating a URDF for a mobile base/manipulator to MuJoCo, additional steps need to be taken so that the base can move in MuJoCo.
Adding mecanum wheels to the robot base
Currently in MoveIt Pro, we only support holonomic mobile bases.
To properly support holonomic movement in MuJoCo, we generate mecanum wheels for the MJCF using this repository.
As of the time of writing, we were using the latest commit off of main
: 4d0fb46f363fc23fe4eb58653a6a4653e73a3c76 (add images).
Clone the repository and from the root directory, run the following:
python3 wheel_code_gen.py --link_name <wheel-name> --size <radius> <half-height> --type <type-of-wheel>
In the command, the link_name
argument should designate what wheel is being generated, i.e. front_right, back_left, etc.
The size
arguments should be the radius of the wheel and the half-height of the wheel, not the full height.
The type
argument is important because it designates the orientation of the rollers for the mecanum wheels.
For the front right and back left wheels, the type should be 0, and for the front left and back right wheels, the type should be 1.
Whenever the wheel is generated, it is saved as a wheel.xml
file.
Rename the file depending on what wheel it is, i.e. the front right wheel should be named front_right_wheel.xml
.
Move the wheel files to the mujoco directory where the MJCF lives.
You can add a wheel to the MJCF by adding the following:
<body name="name-of-body" pos="0 0 0">
<include file="file-name.xml" />
</body>
Set the name
, pose
, and file
arguments and do this for each generated wheel.
Load the MJCF in the mujoco viewer to see if the mecanum wheels are loaded properly.
Ensure that there are no contacts internally between the mecanum wheels and the body of the robot. This is explained in the Possible ERROR: colliding adjacent meshes section.
The next step is to add an actuator for each mecanum wheel to the MJCF.
This can be done by adding the following to the MJCF for each wheel:
<actuator>
<velocity name="name-of-velocity-actuator" joint="name-of-joint-to-actuate" ctrlrange="-15 15" kv="50" />
</actuator>
The joint
field should match the name of the main joint in the corresponding wheel xml file. i.e.
<actuator>
<velocity name="front_right_wheel" joint="R1_front_right_wheel_rolling_joint" ctrlrange="-15 15" kv="50" />
</actuator>
Reload the MJCF in the mujoco viewer and in the "Control" section of the right sidebar, you should see each wheel actuator listed. Try actuating each wheel to ensure that the wheels are being controlled as expected.
Simulate your robot
Next we will use the mujoco simulate binary to start making actuation work.
simulate ~/user_ws/my_robot_mujoco_config/description/robot_description.xml
This should launch the mujoco viewer without any errors in the UI, but the robot will immediately flop and hang under its base link.
Make sure the robot is upright
If the robot immediately flops and hangs under its base link, it is likely that gravcomp is not enabled on each body. Ensure each <body>
tag contains a gravcomp="1"
attribute.
Check the inertia of the robot links
In the mujoco viewer, under the Rendering tab to the left, the "Inertia" model element can be turned on to see the inertias of the various bodies.
More information on where to find this toggle can be found in the Possible ERROR: Missing inertia section.
If the inertias do not make physical sense, it is highly recommended that the <inertial>
tag in the offending <body>
be deleted, so that mujoco can estimate the inertia from the mesh.
Tune arm actuators
Again, if your xml file only contains robot elements, and not environment elements, then it is easy to extract every joint and then make a corresponding actuator for it.
MuJoCo supports a number of different types of actuators, but for ease of getting a robotic arm up and running, we are going to use position actuators.
The urdf_to_mjcf
script adds position actuators for any named joints in the MJCF file by adding the following tags.
<mujoco>
<actuator>
<position joint="<name-of-joint-to-actuate>" name="<name-of-actuator>" ctrlrange="-3.14 3.14" kp="1000" forcelimited="false" dampratio="1"/>
...
</actuator>
</mujoco>
More information on position actuators can be found here.
The right sidebar's "Control" entry should have entries for each joint. Command some values, see how well it tracks and settles.
Recommendation: kp and dampratio tuning (Experimental)
- Small robot arms / fingers:
- kp: 10-100
- dampratio: 1-1.5
- Medium-scale limbs / manipulators:
- kp: 100-500
- dampratio: 0.7-1
- Large or high-inertia systems:
- kp: 500-2000
- dampratio: 0.6-0.9
- Start with 1.0 (critical damping)
- If you want faster response, reduce dampratio (e.g. 0.5).
- If you see oscillations or jitter, increase it toward 1.2–1.5.
- Keep consistent units: since dampratio is used alongside kp, make sure kp is realistic for your joint scale and mass.
After making changes, Reload and re-test.
If your robot arm has an internal controller handling the PID loop (e.g. most commercial arms) or the physical modeling of the actuators is not a concern, it is recommended that kp
for arm joints be set to a large value to quickly achieve behavior similar to what the onboard controller produces.
Recommendation: Remove body joint force limits
If the robot is still very weak after increasing kp to >10,000, it may be because your MuJoCo joints have limits on the force that can be applied to them (by the actuators) which are too conservative. Check for "actuatorfrcrange" attributes in your joint entries. These are generated if your URDF joint entries have a non-zero effort limit, for example below:
<joint name="feet_joint" type="revolute">
<origin rpy="-3.1416 0 0" xyz="0 0 0.0156"/>
<parent link="base_link"/>
<child link="feet_link"/>
<axis xyz="0 0 -1"/>
<limit effort="100" lower="-3.14" upper="3.14" velocity="0"/>
</joint>
Consider increasing or removing these “actuatorfrcrange” statements from the Xacro and XML.
Possible ERROR: colliding adjacent meshes
If certain actuators do not move at all despite the control value sent, it could be colliding with another link. Enable "Contact Point" visualization as well as "Convex Hull" visualization. Look for a cylinder as you command the joint, which indicates a collision. Setting "Label" to "Contact" under "Rendering" will also show the names of the geoms that are under collision.
There are two ways to resolve collisions:
1. via exclude (body to body) tag
<mujoco>
<contact>
<exclude body1="base_link" body2="J1_link" />
<exclude body1="fork" body2="J5_link" />
<exclude body1="fork" body2="J6_link" />
<exclude body1="fork" body2="head" />
</contact>
</mujoco>
Note that the exclude tag is not inherited by the nested bodies, so if you want to exclude contacts for multiple nested bodies, an exclude tag needs to be created for each nested body.
2. via contype and conaffinity tags (for things attached to "world" - geom to geom)
URDF meshes connected to one another via a urdf fixed joint are combined under the same mujoco body by the compile tool. This means your base_link, and any other fixed link attached to it, are all part of the mujoco "world" body, as will be any environment asset. We still want assets in the environment to interact with the base link, so we use contype and conaffinity, which can be set per-geom instead of per-body.
<mujoco>
<worldbody>
<geom type="mesh" rgba="0.898039 0.917647 0.929412 1" mesh="base_link" contype="1" conaffinity="2"/>
<body name="feet_link" pos="0 0 0.0156" quat="-3.67321e-06 -1 0 0" gravcomp="1">
<inertial pos="3.959e-07 -0.031579 -0.19136" quat="0.694431 -0.133517 0.133511 0.694344" mass="43.789" diaginertia="0.453199 0.385 0.281311"/>
<joint name="feet_joint" pos="0 0 0" axis="0 0 -1" range="-3.14 3.14"/>
<geom type="mesh" rgba="0.89804 0.91765 0.92941 1" mesh="feet_link" contype="1" conaffinity="2"/>
</body>
</worldbody>
</mujoco>
Alternatively, we could wrap the base_link in its own body and use the exclude tag approach.
Iterate through these recommendations and you should end up with responsive actuators.
Check for meshes that were not convex hulls and are not poorly converted
Left sidebar ---> header ??? ---> Convex Hulls
Make sure convex hulls make sense.
Otherwise decompose - we have a guide here for that.
ROBOT_description/
description/
ROBOT_DETAILED.xml
meshes/
base_link.stl
link1.stl # decomposed mesh
temp/
ROBOT_DETAILED.test.urdf
base_link.stl
link1.stl # decomposed mesh
ROBOT_DETAILED.xml
Copy mujoco xml and decimated/decomposed meshes back to ROBOT_description
ROBOT_description/
description/
ROBOT_DETAILED.xml
meshes/
base_link.stl # decimated mesh
link1.stl # decimated mesh
urdf/
ROBOT_model.urdf.xacro # new inertia values
ROBOT_COMPONENT_macro.urdf.xacro # new inertia values
launch/
view_robot.launch
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
Set up ros2_control and MoveIt config files
a. Make ros2_control macro xacro for urdf tags
In a future revision, we will add a script to automatically add ros2_control tags to xacro file(s).
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro # now calls ros2_control xacro macro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
helper-scripts/
add-gravcomp.py
add-position-actuators.py
b. Make ros2_control controllers file
Manually create and populate with Pro controllers
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/ # or ROBOT_DETAILED_config/ if you expect to have variations of gripper type, etc
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro # now calls ros2_control xacro macro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
c. Configuring "ros2_control" for a mobile base
To control an omnidiretional mobile base, we use the clearpath_mecanum_drive_controller.
As of writing this, we are using the latest commit of the pr-add-world-frame-control-option
branch: 50ff0df61042ca5d16cf5d98c386661023bd6185 (fix test).
This controller is used to control the mecanum wheels that were generated in the "Adding mecanum wheels to the robot base" section.
To use the controller, clone the repo into your user workspace and build the package.
Add the parameters under platform_velocity_controller to the controllers.yaml
file.
Most of the parameters are self explanatory, except kinematics.sum_of_robot_center_projection_on_X_Y_axis
.
That parameter is equal to l + w in the image below (in meters).
d. Generate MoveIt SRDF ACM
Two options:
- Use MoveIt Pro CLI (Recommended) - From inside the dev container:
moveit_pro dev
update_acm src/[robot_name]_mujoco_config/description/robot_description.urdf --output src/[robot_name]_mujoco_config/config/moveit/robot.srdf
Or from the host:
moveit_pro update_acm ~/user_ws/src/[robot_name]_mujoco_config/description/robot_description.urdf --output ~/user_ws/src/[robot_name]_mujoco_config/config/moveit/robot.srdf
- Use the MoveIt Setup Assistant - create the
.setup_assistant
file so it will let you save your changes. Only use the SRDF tab and only save the new SRDF file - no other changes.
🐙
ros2 run moveit_setup_assistant collisions_updater --urdf <PATH_TO_URDF> --srdf <PATH_TO_OLD_SRDF> --output out.srdf --trials 100000 --default --always --min-collision-fraction 0.99 --verbose
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf # Just ACM
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
e. Manually define groups in SRDF
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf # Now with group definitions
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
f. Manually create ompl file
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf
ompl_planning.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
g. Manually create PoseIK kinematics file
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf
ompl_planning.yaml
pose_ik_distance.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
h. Create servo.yaml file
I copy lab_sim and start manually replacing things.
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf
ompl_planning.yaml
pose_ik_distance.yaml
servo.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
i. Create joint_limits.yaml file
Can probably write a script to use the extracted joints to make these.
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf
joint_limits.yaml
ompl_planning.yaml
pose_ik_distance.yaml
servo.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
Set up Pro config files
a. Copy over ROBOT_sim boilerplate package
~/user_ws contents:
ROBOT_sim/
config/
config.yaml
description/
meshes/
launch/
agent_bridge.launch
moveit_pro.launch.xml
objectives/
waypoints/
waypoints.yaml
CMakeLists.txt
package.xml
LICENSE
README.md
.gitattributes
b. Create ROBOT_sim TASK-scene.xml
<mujoco model="gen3_proto1">
<option integrator="implicitfast">
<flag multiccd="enable" />
</option>
<include file="ROBOT_DETAILED.xml" />
<compiler angle="radian"/>
<asset>
<texture
type="2d"
name="groundplane"
builtin="checker"
mark="edge"
rgb1="0.2 0.3 0.4"
rgb2="0.1 0.2 0.3"
markrgb="0.8 0.8 0.8"
width="300"
height="300"
/>
<material
name="groundplane"
texture="groundplane"
texuniform="true"
texrepeat="5 5"
reflectance="0.2"
/>
</asset>
<statistic center="0.3 0 0.4" extent="0.8" />
<visual>
<headlight diffuse="0.6 0.6 0.6" ambient="0.1 0.1 0.1" specular="0 0 0" />
<rgba haze="0.15 0.25 0.35 1" />
<global azimuth="120" elevation="-20" />
<map zfar="50" />
</visual>
<worldbody>
<light pos="0 0 2.5" dir="0 0 -1" directional="true" />
<geom
name="floor"
pos="0 0 0"
size="0 0 0.05"
type="plane"
material="groundplane"
/>
</worldbody>
</mujoco>
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
ROBOT_DETAILED_config/
moveit/
groups.srdf
joint_limits.yaml
ompl_planning.yaml
pose_ik_distance.yaml
servo.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
helper-scripts/
add-gravcomp.py
add-position-actuators.py
ROBOT_sim/
config/
config.yaml
description/
TASK-scene.xml
launch/
agent_bridge.launch
moveit_pro.launch.xml
objectives/
waypoints/
waypoints.yaml
CMakeLists.txt
package.xml
LICENSE
README.md
Optional - add scene geometry
Tables, widget, doodads, etc
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf
joint_limits.yaml
ompl_planning.yaml
pose_ik_distance.yaml
servo.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
helper-scripts/
add-gravcomp.py
add-position-actuators.py
ROBOT_sim/
config/
config.yaml
description/
meshes/
interesting_object.stl
TASK-scene.xml
launch/
agent_bridge.launch
moveit_pro.launch.xml
objectives/
waypoints/
waypoints.yaml
CMakeLists.txt
package.xml
LICENSE
README.md
Optional - configure scene camera
Optional - configure keyframes
https://docs.picknik.ai/how_to/configuration_tutorials/migrate_to_mujoco_config/#mujoco-keyframes
c. Configure ROBOT_sim CMakeLists.txt to install ROBOT_description mujoco xml & mesh files into its description and meshes folder
# Specify all packages we will install files from here to populate '_DIR' path
find_package(ROBOT_description REQUIRED)
...
# MuJoCo models in this package use relative paths to assets such as meshes and textures
# To simplify building relative paths to assets in other packages, we will copy those assets into this project's file structure
# Paths we will copy from - the assets we want to easily reference in our MuJoCo model
# set(PICKNIK_ACCESSORIES_PATH "${picknik_accessories_DIR}/../mujoco_assets/")
set(ROBOT_MESHES_PATH "${ROBOT_description_DIR}/../meshes/")
set(ROBOT_MODEL_PATH "${ROBOT_description_DIR}/../description/")
# Path we will copy to - the common folder in this project to copy all MuJoCo related files to
set(MUJOCO_MESHES_DIR "share/${PROJECT_NAME}/meshes/")
set(MUJOCO_MODEL_DIR "share/${PROJECT_NAME}/description/")
message(STATUS"ROBOT_MESHES_PATH ${ROBOT_MESHES_PATH}")
message(STATUS"ROBOT_MODEL_PATH ${ROBOT_MODEL_PATH}")
message(STATUS"MUJOCO_MESHES_DIR ${MUJOCO_MESHES_DIR}")
message(STATUS"MUJOCO_MODEL_DIR ${MUJOCO_MODEL_DIR}")
# Copy all contents into the installed description folder
install(DIRECTORY "${ROBOT_MESHES_PATH}"
DESTINATION "${MUJOCO_MESHES_DIR}"
FILES_MATCHING PATTERN "*")
install(DIRECTORY "${ROBOT_MODEL_PATH}"
DESTINATION "${MUJOCO_MODEL_DIR}"
FILES_MATCHING PATTERN "*")
🐙
cd ~/user_ws
colcon build --packages-select ROBOT_sim
find . -name ROBOT_DETAILED.xml
find . -name base_link.stl
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf
joint_limits.yaml
ompl_planning.yaml
pose_ik_distance.yaml
servo.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
helper-scripts/
add-gravcomp.py
add-position-actuators.py
ROBOT_sim/
config/
config.yaml
description/
TASK-scene.xml
launch/
agent_bridge.launch
moveit_pro.launch.xml
objectives/
waypoints/
waypoints.yaml
CMakeLists.txt
package.xml
LICENSE
README.md
d. Expose mujoco model settings in xacro files
This is so that the config.yaml can be quickly updated to start a different mujoco world or tun on/off the mujoco viewer.
ROBOT_model.urdf.xacro
<robot>
<!-- Use $() for xacro processing that must be done at runtime (roslaunch or CLI arguments, filepaths, etc) -->
<!-- Use ${} for xacro processing that is not done at runtime (passing values between xacro files) -->
<xacro:arg name="left_gripper_type" default="default_vacuum" />
<xacro:arg name="right_gripper_type" default="default_vacuum" />
<xacro:arg name="base_type" default="none" />
<!-- hardware_interface options: sim, physical (TODO), or mock (TODO) -->
<xacro:arg name="hardware_interface" default="sim" />
<xacro:arg name="mujoco_model_package" default="rapid_rad_base_config" />
<xacro:arg
name="mujoco_model_relpath"
default="description/simple-scene.xml"
/>
<xacro:arg name="mujoco_viewer" default="true" />
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf
joint_limits.yaml
ompl_planning.yaml
pose_ik_distance.yaml
servo.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
helper-scripts/
add-gravcomp.py
add-position-actuators.py
ROBOT_sim/
config/
config.yaml
description/
TASK-scene.xml
launch/
agent_bridge.launch
moveit_pro.launch.xml
objectives/
waypoints/
waypoints.yaml
CMakeLists.txt
package.xml
LICENSE
README.md
e. Configure "hardware" dictionary entries in config.yaml
# Baseline hardware configuration parameters for MoveIt Pro.
# [Required]
hardware:
# Set simulated to false if you are using this as a configuration for real hardware.
# This allows users to switch between mock and real hardware by changing a single parameter with config inheritance.
# [Required]
simulated: true
# If simulated is false, launch the following file:
# [Optional, defaults to a blank launch file if not specified]
robot_driver_persist_launch_file:
package: "moveit_studio_agent"
path: "launch/blank.launch.py"
# If the MoveIt Pro Agent should launch the ros2 controller node.
# [Optional, default=True]
launch_control_node: True
# If the MoveIt Pro Agent should launch the robot state publisher.
# This should be false if you are launching the robot state publisher as part of drivers.
# [Optional, default=True]
launch_robot_state_publisher: True
# Parameters used to configure the robot description through XACRO.
# A URDF and SRDF are both required.
# [Required]
robot_description:
urdf:
package: "factory_sim"
path: "description/picknik_fanuc.xacro"
srdf:
package: "factory_sim"
path: "config/moveit/picknik_fanuc.srdf"
# Specify any additional parameters required for the URDF.
# Many of these are specific to the descriptions packages, and can be customized as needed.
# [Optional]
urdf_params:
- hardware_interface: "sim"
- mujoco_model_package: "ROBOT_sim"
- mujoco_model_relpath: "description/TASK-scene.xml"
- mujoco_viewer: "true"
f. Configure "moveit_params" dictionary entries in config.yaml
TODO - unclear which are required in 7.x
# Configuration files for MoveIt.
# For more information, refer to https://moveit.picknik.ai/main/doc/how_to_guides/moveit_configuration/moveit_configuration_tutorial.html
# [Required]
moveit_params:
# Used by the Waypoint Manager to save joint states from this joint group.
joint_group_name: "whole_body"
joint_limits:
package: "ROBOT_description"
path: "config/moveit/joint_limits.yaml"
kinematics:
package: "ROBOT_description"
path: "config/moveit/pose_ik_speed.yaml"
ompl_planning:
package: "ROBOT_description"
path: "config/moveit/ompl_planning.yaml"
servo:
package: "ROBOT_description"
path: "config/moveit/servo.yaml"
# servo_kinematics:
# package: "ROBOT_description"
# path: "config/moveit/pose_ik_speed.yaml"
# servo_joint_limits:
# package: "ROBOT_description"
# path: "config/moveit/joint_limits.yaml"
g. Configure "ros2_control" dictionary entries in config.yaml
# Configuration for launching ros2_control processes.
# [Required, if using ros2_control]
ros2_control:
config:
package: "ROBOT_description"
path: "config/ros2_control/controllers.yaml"
# MoveIt Pro will load and activate these controllers at start up to ensure they are available.
# If not specified, it is up to the user to ensure the appropriate controllers are active and available
# for running the application.
# [Optional, default=[]]
controllers_active_at_startup:
- "joint_trajectory_controller"
- "joint_state_broadcaster"
- "tool_attach_controller"
- "suction_cup_controller"
# Load but do not start these controllers so they can be activated later if needed.
# [Optional, default=[]]
controllers_inactive_at_startup:
- "servo_controller"
# Any controllers here will not be spawned by MoveIt Pro.
# [Optional, default=[]]
controllers_not_managed: []
# Optionally configure remapping rules to let multiple controllers receive commands on the same topic.
# [Optional, default=[]]
controller_shared_topics: []
Don't forget to add the mobile base controller if required.
h. Configure "objectives" dictionary entries in config.yaml
make blank waypoints.yaml file
# Configuration for loading behaviors and objectives.
# [Required]
objectives:
# List of plugins for loading custom behaviors.
# [Required]
behavior_loader_plugins:
# This plugin will load the core MoveIt Pro Behaviors.
# Add additional plugin loaders as needed.
core:
- "moveit_studio::behaviors::CoreBehaviorsLoader"
- "moveit_studio::behaviors::MTCCoreBehaviorsLoader"
- "moveit_studio::behaviors::ServoBehaviorsLoader"
- "moveit_studio::behaviors::VisionBehaviorsLoader"
# Specify source folder for objectives
# [Required]
objective_library_paths:
core:
package_name: "ROBOT_sim"
relative_path: "objectives"
# Specify the location of the saved waypoints file.
# [Required]
waypoints_file:
package_name: "ROBOT_sim"
relative_path: "waypoints/waypoints.yaml"
i. Launch! 🤞🤞
Launch pro and iteratively check terminal output for errors in finding and/or loading files.
moveit_pro build user_workspace
moveit_pro run -v -c ROBOT_sim
Configure Teleop objectives
If the Pro UI loads and you can see the 3D visualization of your robot, then we are ready to start configuring teleoperation objectives:
https://docs.picknik.ai/how_to/configuration_tutorials/configure_custom_robot/#configuring-robot-description-and-semantics
~/user_ws contents:
Dockerfile
docker-compose.yaml
ROBOT_description/
config/
moveit/
groups.srdf
joint_limits.yaml
ompl_planning.yaml
pose_ik_distance.yaml
servo.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch # from xacro
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
helper-scripts/
add-gravcomp.py
add-position-actuators.py
ROBOT_sim/
config/
config.yaml
description/
TASK-scene.xml
launch/
agent_bridge.launch
moveit_pro.launch.xml
objectives/
clear_snapshot.xml
disengage_grasp.xml
engage_grasp.xml
interpolate_to_joint_State.xml
move_to_joint_state.xml
move_to_pose_with_approval.xml
request_teleoperation.xml
reset_planning_scene.xml
take_snapshot.xml
teleoperation.xml
waypoints/
waypoints.yaml
CMakeLists.txt
package.xml
LICENSE
README.md
Final directory contents
Dockerfile
docker-compose.yaml
helper-scripts/
add-gravcomp.py
add-position-actuators.py
mujoco-3.3.1/
bin/
...
ROBOT_description/
config/
moveit/
groups.srdf
joint_limits.yaml
ompl_planning.yaml
pose_ik_distance.yaml
servo.yaml
ros2_control/
controllers.yaml
description/
meshes/
base_link.stl
link1.stl
ROBOT_DETAILED.xml
urdf/
ROBOT_model.urdf.xacro
ROBOT_COMPONENT_macro.urdf.xacro
ROBOT_macro.ros2_control.xacro
launch/
view_robot.launch
view_robot.rviz
CMakeLists.txt
package.xml
LICENSE
README.md
helper-scripts/
add-gravcomp.py
add-position-actuators.py
ROBOT_sim/
config/
config.yaml
description/
TASK-scene.xml
launch/
agent_bridge.launch
moveit_pro.launch.xml
objectives/
clear_snapshot.xml
disengage_grasp.xml
engage_grasp.xml
interpolate_to_joint_State.xml
move_to_joint_state.xml
move_to_pose_with_approval.xml
request_teleoperation.xml
reset_planning_scene.xml
take_snapshot.xml
teleoperation.xml
waypoints/
waypoints.yaml
CMakeLists.txt
package.xml
LICENSE
README.md
temp/
ROBOT_DETAILED.test.urdf
base_link.stl
link1.stl
ROBOT_DETAILED.xml
Troubleshooting
See our Digital Twin Troubleshooting page here.
Visual Issues
If your robot model appears oversaturated or visually "blown out" in the MoveIt Pro UI, see the Robot model looks oversaturated or blown out troubleshooting entry.