Migrate User Workspace From 9.x to 10.0
MoveIt Pro 10.0 completes the move to direct controller execution for MoveIt Task Constructor (MTC) solutions that began in 9.0. The legacy MTC execution path is now fully removed: the ExecuteMTCTask Behavior, the /execute_task_solution move_group capability, and the controller_names and trajectory_monitoring ports on InitializeMTCTask that only fed that path. 10.0 also removes the deprecated ExecuteFollowJointTrajectory and ExecuteTrajectoryWithAdmittance Behaviors, which were consolidated into the single ExecuteTrajectory Behavior in 9.0.
If you already completed the 9.0 migration and adopted the Execute MTC Solution Subtree, most of your workspace already uses the new path and the changes below are small.
Migration Summary
These are breaking changes. A Behavior Tree that still references the removed Behavior, ports, or capability will fail to load or run, so complete the Required Migration Changes below. Run the shell commands from the top level of your user workspace (for example ~/moveit_pro/moveit_pro_example_ws/).
10.0 also introduces one non-breaking deprecation — the position_only port on the Cartesian path Behaviors. Existing Objectives keep working, so it is not in the required list; see Replace the Deprecated position_only Port on the Cartesian Path Behaviors below to silence the deprecation warning.
Required Migration Changes
Rename Docker Image References
MoveIt Pro 10.0 renames Docker image repositories from moveit-studio to moveit-pro. This applies to published images and locally built development images. For example:
| MoveIt Pro 9.x image | MoveIt Pro 10.0 image |
|---|---|
picknikciuser/moveit-studio | picknikciuser/moveit-pro |
picknikciuser/moveit-studio-frontend | picknikciuser/moveit-pro-frontend |
moveit-studio-dev | moveit-pro-dev |
moveit-studio-base | moveit-pro-base |
moveit-studio-agent-bridge | moveit-pro-agent-bridge |
moveit-studio-drivers | moveit-pro-drivers |
moveit-studio-overlay-dev | moveit-pro-overlay-dev |
Update custom Dockerfiles, Compose files, CI workflows, deployment scripts, and image-retention rules that name the old repositories. Search the workspace for candidates with:
grep -RIn --exclude-dir=.git 'moveit-studio' .
Review each result rather than replacing the text globally: legacy ROS package and module names that contain moveit_studio are unchanged. After updating the image references, rebuild or pull the 10.0 images. Existing images under the old repository names are not reused automatically.
Remove ExecuteMTCTask
The ExecuteMTCTask Behavior, deprecated in 9.0, has been removed. Execute MTC solutions with the Execute MTC Solution Subtree (or the ExecuteMTCSolution Behavior), which run the solution directly through the JTAC or JTC controllers instead of the MoveIt 2 execution pipeline.
Replace:
<Action ID="ExecuteMTCTask" solution="{solution}" />
With:
<SubTree
ID="Execute MTC Solution"
solution="{solution}"
execution_pipeline="jtac"
controller_names="joint_trajectory_admittance_controller"
controller_action_name="/joint_trajectory_admittance_controller/follow_joint_trajectory"
/>
For a JTC-like controller, set execution_pipeline="jtc" (or use the Execute MTC Solution (JTC) convenience Subtree) and point controller_names and controller_action_name at your controller.
Remove controller_names and trajectory_monitoring From InitializeMTCTask
InitializeMTCTask no longer accepts the controller_names or trajectory_monitoring input ports. Because Behavior Trees reject unknown port attributes at load time, an Objective that still sets either attribute on InitializeMTCTask will fail to load.
Remove both attributes from every InitializeMTCTask Action. For example, change:
<Action
ID="InitializeMTCTask"
task_id="pick_object"
controller_names="joint_trajectory_admittance_controller"
task="{mtc_task}"
trajectory_monitoring="false"
/>
To:
<Action ID="InitializeMTCTask" task_id="pick_object" task="{mtc_task}" />
InitializeMTCTaskcontroller_names is still a valid input on the Execute MTC Solution Subtree and on core motion Objectives, and many Objectives declare it as a top-level port. Only remove controller_names where it appears as an attribute of an InitializeMTCTask Action — leave every other use in place.
trajectory_monitoring is used only by InitializeMTCTask, so on a Linux workspace you can safely remove it everywhere at once:
find . -name '*.xml' -exec sed -i '/^[[:space:]]*trajectory_monitoring=/d' {} +
Why these ports were removed
Both ports only fed the removed /execute_task_solution execution path:
- Controller selection is now handled by the
Execute MTC SolutionSubtree —ExecuteMTCSolutionchooses its controller through its owncontroller_action_nameport, and controllers are activated with an explicitSwitchControllerstep. - Per-subtrajectory collision monitoring (
trajectory_monitoring) is no longer performed automatically during execution. To collision-check a planned trajectory against an updated planning scene, use theValidateTrajectoryBehavior at the Behavior Tree level before executing.
Remove the /execute_task_solution move_group Capability
The ExecuteTaskSolutionCapability move_group capability (the /execute_task_solution action server) has been removed, since ExecuteMTCSolution executes MTC solutions directly through the controllers.
- Most users: no action needed — this capability was loaded by the default MoveIt Pro configuration, which no longer references it.
- If your robot configuration overrides the move_group capability list, remove
move_group/ExecuteTaskSolutionCapabilityfrom it. - Custom action clients that sent goals to the
/execute_task_solutionaction must switch to running theExecute MTC SolutionSubtree.
Remove the MoveIt Controller-Manager Configuration
10.0 removes the MoveIt controller-manager plugin layer (the MoveItSimpleControllerManager / Ros2ControlManager plugins) that the trajectory execution manager drove. Trajectory execution and controller switching now run entirely through ros2_control controllers driven by the Behavior Tree — controllers are activated with an explicit SwitchController step, and MTC solutions execute directly through the JTAC or JTC controllers.
moveit_params.moveit_simple_controller_managerconfig key: remove it from your robot configuration package. The key is now silently ignored (the config schema drops unknown keys), so a workspace that still sets it loses that functionality with no error. Hardware that is not exposed through ros2_control must now provide a ros2_control interface — the previous "drivers without ros2_control" path is no longer available.SetActiveControllerServicemove_group capability: removed. Most users need no action (it was loaded by the default configuration). If your robot configuration overrides the move_group capability list, removemove_group/SetActiveControllerServicefrom it.allow_trajectory_executionlaunch argument: still accepted, but it no longer has any effect. Trajectory execution is now driven by the Behavior Tree. Remove any workflow that relied on it as a runtime toggle.moveit_studio_agent_msgs/srv/SetStringArraySDK message: removed along with the controller-switching service it backed. Any external Behavior, Python, or C++ client that referenced this message type must drop it; controller switching is done with theSwitchControllerBehavior forros2_controlcontrollers, or custom Behaviors for custom controllers.moveit_params.trajectory_executionconfig block: removed. It configured the MoveIt trajectory execution manager, so every field under it (manage_controllers,allowed_execution_duration_scaling,allowed_goal_duration_margin,allowed_start_tolerance,control_multi_dof_joint_variables) is now silently ignored. Remove the block from your robot configuration package.
Remove ExecuteFollowJointTrajectory and ExecuteTrajectoryWithAdmittance
The ExecuteFollowJointTrajectory and ExecuteTrajectoryWithAdmittance Behaviors, deprecated in 9.0, have been removed. Both are replaced by the consolidated ExecuteTrajectory Behavior, which selects the execution interface through its execution_pipeline input port — "jtc" for a standard FollowJointTrajectory controller, "jtac" for the Joint Trajectory Admittance Controller. ExecuteFollowJointTrajectory's execute_follow_joint_trajectory_action_name port is renamed to controller_action_name; ExecuteTrajectoryWithAdmittance already used controller_action_name.
Replace ExecuteFollowJointTrajectory:
<Action
ID="ExecuteFollowJointTrajectory"
execute_follow_joint_trajectory_action_name="{controller_action_server}"
joint_trajectory_msg="{joint_trajectory_msg}"
/>
With:
<Action
ID="ExecuteTrajectory"
execution_pipeline="jtc"
controller_action_name="{controller_action_server}"
joint_trajectory_msg="{joint_trajectory_msg}"
/>
Replace ExecuteTrajectoryWithAdmittance:
<Action
ID="ExecuteTrajectoryWithAdmittance"
controller_action_name="{controller_action_server}"
joint_trajectory_msg="{joint_trajectory_msg}"
admittance_parameters_msg="{admittance_parameters}"
/>
With:
<Action
ID="ExecuteTrajectory"
execution_pipeline="jtac"
controller_action_name="{controller_action_server}"
joint_trajectory_msg="{joint_trajectory_msg}"
admittance_parameters_msg="{admittance_parameters}"
/>
ExecuteTrajectory reads its goal and path tolerances from the controller configuration when the corresponding ports are left unset, rather than applying Behavior-side default tolerances. It has no goal_time_tolerance input port and no trajectory_remainder output port. If you relied on ExecuteFollowJointTrajectory's goal_time_tolerance, configure the equivalent tolerance on your controller.
Remove CreateStampedPose, CreateStampedTwist, and CreateStampedWrench
These three Behaviors were deprecated in favor of CreatePoseStamped, CreateTwistStamped, and CreateWrenchStamped, and are now removed. An Objective that still references a removed name will fail to load.
The replacements take the same input ports; only the output port name changed:
| Removed Behavior | Replacement | Output port rename |
|---|---|---|
CreateStampedPose | CreatePoseStamped | stamped_pose → pose_stamped |
CreateStampedTwist | CreateTwistStamped | stamped_twist → twist_stamped |
CreateStampedWrench | CreateWrenchStamped | stamped_wrench → wrench_stamped |
Rename the Action and its output port. For example, change:
<Action ID="CreateStampedPose" reference_frame="world" position_xyz="0.5;0;0.1" orientation_xyzw="0;0;0;1" stamped_pose="{pose}" />
To:
<Action ID="CreatePoseStamped" reference_frame="world" position_xyz="0.5;0;0.1" orientation_xyzw="0;0;0;1" pose_stamped="{pose}" />
The blackboard variable the output writes to ({pose} above) is unchanged, so downstream Actions that read it need no edit. The position and orientation ports also adopt the typed-message form described in Pose and Transform Behaviors Use Typed Orientation and Position Ports below.
Adopt moveit_msgs/RobotState (Retire RobotJointState)
MoveIt Pro 10.0 replaces the custom moveit_studio_agent_msgs/msg/RobotJointState message with the standard moveit_msgs/msg/RobotState everywhere a joint-space robot state is produced or consumed. RobotState is a superset of the old message: it keeps the same joint_state and multi_dof_joint_state fields and adds attached_collision_objects and is_diff. The shipped Behaviors, Objectives, and UI are all updated to the new type, so most workspaces need no changes. The exceptions below apply only if your workspace references the old message type, the renamed service, or the generated converter Behaviors directly.
Port keys are unchanged; seven Behaviors are also renamed. RetrieveWaypoint, SaveRobotJointStateToYaml, and LoadRobotJointStateFromYaml keep both their names and their port keys — only the port type changed from RobotJointState to RobotState. Seven planning Behaviors whose names carried the ambiguous JointState term are additionally renamed so the name matches the type they actually carry (see Planning Behaviors renamed to use RobotState below); their old names keep working as deprecation aliases. In every case the port keys are unchanged, so an Objective that only wires these Behaviors together by name needs no edit; the type break is in custom code that constructs or reads the message with the explicit old type.
Planning Behaviors renamed to use RobotState
Seven planning Behaviors carried the ambiguous JointState term in their names — some producing the composite whole-robot state, one producing a plain sensor_msgs/JointState. They are renamed so the name states the type: RobotState for the whole-robot state, JointState for the single-DOF message.
| Old name | New name |
|---|---|
GetRobotJointState | GetJointState |
CreateJointState | CreateRobotState |
GetTrajectoryStateAtTime | GetRobotStateFromTrajectory |
RetrieveJointStateParameter | RetrieveRobotStateParameter |
SetupMTCPlanToJointState | SetupMTCPlanToRobotState |
SetupMTCInterpolateToJointState | SetupMTCInterpolateToRobotState |
SetupMTCCartesianMoveToJointState | SetupMTCCartesianMoveToRobotState |
The old names are still registered as deprecation aliases, so existing Objectives keep loading unchanged; they will be removed in a future major release. The shipped Objectives already use the new names — update your own Objective XML at your convenience by swapping the ID="…" string.
Update Objectives that use the Pack/Unpack converter Behaviors
The message-conversion Behaviors are generated per message type, so retiring RobotJointState removes PackRobotJointStateMessage and UnpackRobotJointStateMessage; they are replaced by PackRobotStateMessage and UnpackRobotStateMessage. An Objective that references a removed node ID fails to register.
Rename both the node ID and its message port — the message port is named after the message type, so it changes from robot_joint_state to robot_state. The field ports (joint_state, multi_dof_joint_state) are unchanged; the new type simply adds attached_collision_objects and is_diff ports you can ignore. For example, change:
<Action ID="UnpackRobotJointStateMessage" robot_joint_state="{robot_state_msg}" joint_state="{joint_state}" multi_dof_joint_state="{multi_dof}" />
To:
<Action ID="UnpackRobotStateMessage" robot_state="{robot_state_msg}" joint_state="{joint_state}" multi_dof_joint_state="{multi_dof}" />
PackRobotStateMessage changes the same way — its output message port is renamed robot_joint_state → robot_state.
Update custom code that names the old message type or service
- Custom C++ / Python Behaviors and nodes that reference
moveit_studio_agent_msgs::msg::RobotJointState(ormoveit_studio_agent_msgs/msg/RobotJointState) must switch tomoveit_msgs::msg::RobotState. Field access is unchanged —joint_stateandmulti_dof_joint_stateare the same members — so usually only the type name and include change (#include <moveit_msgs/msg/robot_state.hpp>). - The
RetrieveJointStateservice is renamed.moveit_studio_agent_msgs/srv/RetrieveJointStateis nowRetrieveRobotState, and its response fieldrobot_joint_stateis nowrobot_state(amoveit_msgs/RobotState). The service endpoint name (retrieve_joint_state) is unchanged; the wrapper Behavior is renamedRetrieveJointStateParameter→RetrieveRobotStateParameter(old name kept as a deprecation alias — see above). Only a custom client that calls the service with the old.srvtype needs updating. - Custom rosbridge integrations that publish to
/moveit_pro_ui/store_joint_statemust sendmoveit_msgs/msg/RobotStateinstead ofmoveit_studio_agent_msgs/msg/RobotJointState.
Set is_diff = false on robot states you build by hand
moveit_msgs/RobotState carries an is_diff flag that RobotJointState did not. The full-state consumers — PlanToJointGoal, the Plan/Interpolate/CartesianMoveTo Joint State MTC setup Behaviors, GeneratePointToPointTrajectory, and SetMujocoState — treat the message as absolute joint values and reject is_diff == true with a clear error ("... must be a complete robot state (is_diff == false), not a diff."). Every shipped producer emits is_diff = false. If your custom Behavior constructs a RobotState to feed one of these consumers, set is_diff = false (the default) and populate the named joints; do not send a differential state.
Saved waypoint YAML files keep working
No action is required for existing saved joint-state files. SaveRobotJointStateToYaml / LoadRobotJointStateFromYaml keep their names and now read and write RobotState, and the YAML loader tolerates the pre-10.0 layout: a file saved as a RobotJointState (only joint_state and multi_dof_joint_state, with no is_diff or attached_collision_objects keys) still loads, with the new fields defaulting (is_diff = false, empty attachments). You do not need to re-save waypoints.
Zero the Force/Torque Sensor Before Executing a Trajectory
MoveIt Pro 10.0 restricts the force/torque tare — the Joint Trajectory Admittance Controller's ~/zero_fts/<sensor_frame> services and the Velocity Force Controller's ~/zero_fts service — to run only while the controller is idle. A tare triggered while the JTAC is executing a goal, or while the VFC is actively streaming a command, is now rejected and the service reply reports success = false. Previously the tare ran mid-execution.
This is disallowed because zeroing the sensor mid-trajectory steps the force offset — introducing a discontinuity in the admittance control signal — and averages a changing load into a meaningless offset.
Refactor any Objective that tares the sensor during execution so the tare runs before the trajectory is sent for execution: sequence the ~/zero_fts CallTriggerService step ahead of the ExecuteTrajectory step instead of running them in parallel or triggering the tare mid-motion. The tare service now also replies only after the averaged offset has been applied, so a step that zeroes the sensor and then commands motion waits for the tare to complete instead of racing it.
Replace the Deprecated position_only Port on the Cartesian Path Behaviors
MoveIt Pro 10.0 adds a cartesian_constraint input port to the PlanCartesianPath and SetupMTCPathIK Behaviors and deprecates their position_only port. Unlike the changes above this is not a breaking change — an Objective that sets position_only still loads and runs — but whenever the position_only port is wired explicitly the Behavior logs a deprecation warning on each run. Migrate to cartesian_constraint to silence the warning and prepare for the port's removal in a future major release.
The two ports are mutually exclusive: setting both on the same Behavior is an error and the Behavior fails to run. Replace an explicit position_only attribute with the equivalent cartesian_constraint value:
Deprecated position_only | Replacement cartesian_constraint |
|---|---|
position_only="false" | cartesian_constraint="[{constraint_type: position_and_orientation}]" |
position_only="true" | cartesian_constraint="[{constraint_type: position_only}]" — or just delete the attribute, since position-only is the default |
For example, change (the ... stands for the Behavior's other, unchanged ports):
<Action ID="PlanCartesianPath" ... position_only="false" />
To:
<Action ID="PlanCartesianPath" ... cartesian_constraint="[{constraint_type: position_and_orientation}]" />
An Objective that does not set position_only needs no migration: with neither port wired the Behavior keeps the historical position-only default and logs no warning.
C++ Access Specifier Cleanup: protected Removed
MoveIt Pro 10.0 removes all protected members from its C++ classes. Every class member is now either public or private:
- Extension points are now
public. Members that derived classes are meant to use — virtual hooks you override, base-class state you read, helpers you call — are now public. - Implementation details are now
private. Members that only the defining class used are now private.
No changes needed for most overrides
If your custom Behaviors derive from the standard base classes and only override subclass hooks, those overrides compile unchanged:
AsyncBehaviorBase—doWork(),doHalt(),getFuture(), andnotifyCanHalt()are now public.ServiceClientBehaviorBase—createRequest(),processResponse(),getServiceName(),doHalt(), and the timeout hooks are now public.ActionClientBehaviorBase—createGoal(),processResult(),processFeedback(), and the message hooks are now public.GetMessageFromTopicBehaviorBase— the timeout hooks are now public.SharedResourcesNode— the shared Behavior context is now exposed through the publicgetBehaviorContext()accessor. Direct member references require the source update described below.
Your existing overrides keep compiling no matter which access section they sit in: C++ lets a derived class declare an override at any access level. You do not need to move your own protected: overrides — although we recommend adopting the same public/private convention in your workspace.
The same applies to the other customer-facing inheritance hierarchies, whose subclass-facing members are now public: MoveIt Task Constructor stages (Stage, PropagatingEitherWay, Generator, MonitoringGenerator, ContainerBase, GeneratePose), KinematicsBase (custom IK plugins), CollisionEnv, KinematicConstraint, JointModel, PlanningContext, OccupancyMapUpdater, MoveGroupCapability, and the ActionBasedControllerHandle controller-handle bases.
Action required: use getBehaviorContext() for shared Behavior context
SharedResourcesNode now keeps its shared context in a private member named behavior_context_ and exposes it through getBehaviorContext(). Custom Behaviors that directly accessed the old member must update their source code:
// Before
shared_resources_->logger->publishInfoMessage(name(), "message");
// After
getBehaviorContext()->logger->publishInfoMessage(name(), "message");
A mechanical search/replace is usually enough:
grep -RIl 'shared_resources_->' src/ | xargs --no-run-if-empty sed -i 's/shared_resources_->/getBehaviorContext()->/g'
Action required: members that became private
Members that were used only inside their defining class became private. This is a breaking change only if your workspace defines a class that derives from one of the classes below and touches the listed members. Overriding a now-private virtual still compiles — only direct reads, writes, or calls break.
| Class | Now-private members | Use instead |
|---|---|---|
RobotModel | Internal model state (urdf_, srdf_, link/joint maps, …) | Public getters (getURDF(), getSRDF(), getJointModel(), …) |
JointModelGroup | Internal group state (joint/link vectors, index maps, …) | Public getters |
RevoluteJointModel, PrismaticJointModel | axis_, continuous_ | getAxis() / setAxis(), isContinuous(). Note: setAxis() normalizes the axis and recomputes cached rotation products — code that wrote axis_ directly had a latent stale-cache bug that this fixes |
PlanningSceneMonitor | Internal state (scene_, mutexes, subscribers, …) | Public accessors and LockedPlanningSceneRO / LockedPlanningSceneRW |
Transforms | target_frame_, transforms_map_ | getTargetFrame(), getAllTransforms() |
PlannerManager | config_settings_ | getPlannerConfigurations() / setPlannerConfigurations() |
KinematicConstraintSet | Constraint containers | getAllConstraints() and per-type getters |
KinematicConstraint | type_, robot_model_, constraint_weight_ | Pass the constraint type to the two-argument base constructor, use getType() / getRobotModel() / getConstraintWeight(), and apply validated weights with setConstraintWeight() |
JointConstraint, OrientationConstraint, PositionConstraint, VisibilityConstraint | Constraint state and cached matrices | Public getters; reconfigure via configure() |
CollisionEnv | robot_model_ | getRobotModel() |
VoxelGrid<T> | Grid data and dimensions | getSize(), getResolution(), getCell(), … |
DistanceField | inv_twice_resolution_ | getResolution() |
SynchronizedStringParameter | Node/publisher internals | Public getValue() API |
ShapeMask | bodies_, bspheres_, transform_callback_ | addShape() / removeShape() for managed shapes, setTransformCallback() for the callback, and maskContainment() / getMaskContainment() for queries |
MTC Connect, MoveTo, MoveRelative, ModifyPlanningScene, ComputeIK, CurrentState, FixedState, FixedCartesianPoses | Stage-internal state (planner_, upstream_solutions_, …) | Goal/group/IK-frame state: stage properties (setGoal(), properties(), …). The planner: keep the solvers::PlannerInterfacePtr you passed to the stage's constructor — the stage never replaces it |
TaskSolutionVisualization, TaskSolutionPanel, TrajectoryVisualization, TrajectoryPanel, TrajectoryDisplay, RobotStateDisplay | rviz widget/render internals | Public display API |
RRTConnectPlanner | Planner parameters (max_iters_, timeout_s_, seed_, …) | Public setters |
Concrete (leaf) Behaviors (e.g. the vision Behaviors, ExecuteTrajectory, AddCollisionObjectBase's doWork()/getFuture()) | doWork(), doHalt(), getFuture(), internal state | Derive from AsyncBehaviorBase (or the relevant base) instead of subclassing a shipped concrete Behavior; AddCollisionObjectBase subclasses override the public buildCollisionObject() |
If you hit a compile error on a member not listed here, the pattern is the same: the member moved to private because a public accessor covers it, or the class was not designed for subclassing. Prefer the public API; if no public equivalent exists for something your integration genuinely needs, contact MoveIt Pro support.
Pose and Transform Behaviors Use Typed Orientation and Position Ports
The pose and transform Behaviors now type their orientation and position ports as geometry_msgs messages instead of vector<double>: orientation ports (orientation_xyzw, rotation_xyzw, quaternion_xyzw) take a Quaternion, and position ports (position_xyz, translation_xyz) take a Vector3. This affects CreatePoseStamped, CreateTransform, TransformPose, and OverridePoseOrientation.
- Literal values in XML need no change.
orientation_xyzw="0;0;0;1"andposition_xyz="0.5;0.0;0.1"still parse — the semicolon form is read directly into the typed message. - Blackboard references must supply the matching type. If a custom Behavior writes a
std::vector<double>to the blackboard and wires it in (for exampleposition_xyz="{my_xyz}"), change that Behavior to output ageometry_msgs::msg::Vector3(orQuaternionfor orientation). A vector-typed blackboard entry no longer matches the port, and the tree will fail when the Behavior ticks. - Malformed values are now rejected at parse time. The new parser requires exactly the right element count and finite numbers, so
nan,inf, and trailing garbage (e.g.1x) that the oldstd::vector<double>port silently accepted now fail the Behavior loudly. This is a deliberate tightening; fix any Objective that relied on the old leniency. OverridePoseOrientationnear-zero-norm threshold. It now shares the commonnormalize_orientation()helper (like the other three Behaviors), which rejects a quaternion only when its norm falls below machine epsilon (was1e-10). A quaternion whose norm sits between epsilon and1e-10— almost always noise or user error — now normalizes and succeeds instead of failing.