I’m building a Gazebo (Fortress) simulation of a Panther on ROS 2 Humble, using husarion/husarion-ugv-gazebo:humble-2.2.2-20250702, and want to add an Interbotix ViperX-300s arm to the simulated robot. The base sim (sensors, controllers, Nav2) is working well.
Looking at husarion_components_description, the components.urdf.xacro dispatcher accepts a fixed set of component types (CAM0x, LDR20, MAN01–07, WCH01, etc.), and the native manipulators are UR/Kinova. There doesn’t appear to be a type: custom path for attaching an arbitrary manipulator xacro.
A few questions:
Is there an intended/supported way to attach a non-native manipulator (like the Interbotix vx300s) to the Panther in the new-gz simulation — e.g. via the components mechanism, or is the expected approach a separate top-level URDF / a second spawned model joined by a static transform?
The OpenManipulator-X integration (husarion/open_manipulator_x) solves arm-as-component with new-gz control and a use_sim toggle. Is that the recommended template to mirror for other arms, or is it OM-X-specific?
Interbotix’s own description ships ros2_control only for actual / fake / gz_classic (no Fortress/ign_ros2_control branch), so I expect to write a gz_ros2_control/GazeboSimSystem block myself for the 6 arm joints and merge/namespace its controllers. Is there a Husarion-recommended pattern for the arm’s controller_manager coexisting with the base’s in the same world?
Any pointers to existing examples of a third-party arm on the Panther in Fortress would save some reinvention. Thanks!
Since June 2026, there has been a commit in husarion_components_description that allows adding a custom URDF outside of the predefined component types. An example can be found here:
We do not plan to update the Humble image with this change, so the recommended option would be to fork the relevant repositories, update the dependency versions, and build a local Docker image containing the updated husarion_components_description . Due to the RAM requirements, I would recommend running the build sequentially.
Alternatively, since you would already be maintaining a fork, you can also modify the URDF/Xacro configuration directly to add the manipulator.
Simulating a manipulator is somewhat dependent on what the manufacturer provides in terms of URDF, ros2_control and Gazebo integration. For consistency, the OpenManipulator-X integration should ideally also be part of husarion_components_description , but for historical reasons it remains in the rosbot_ros repository.
The approach used there is a good one and can be used as a template for integrating other manipulators, although some parts will necessarily be specific to the particular arm and its available simulation/control interfaces.
I don’t have enough information about the intended controller setup for the Interbotix arm to give you a reliable recommendation here. In particular, I would avoid claiming that there is a Husarion-specific pattern for running a second controller_manager alongside the Panther’s base controller without verifying the exact gz_ros2_control setup.
If you share the Interbotix URDF/Xacro and the controllers you plan to use, I can take a look at how this could be integrated with the Panther simulation.
Thanks alot for the reply, that’s really helpful. The type: custom mechanism is exactly what I was missing, and good to know the fork-and-build-local path for Humble.
You offered to look at the Interbotix integration, so here’s the relevant situation:
The arm: Interbotix ViperX-300s (vx300s), 6-DOF. I have the full description vendored (interbotix_xsarm_descriptions). The description xacro is clean geometry with namespaced frames (vx300s/base_link, vx300s/shoulder_link, … vx300s/ee_gripper_link), which preserves 1:1 frame names with our real robot which we have mounted on the real husarion panther.
The blocker: Interbotix’s control.urdf.xacro only ships ros2_control hardware plugins for actual (their xs_sdk), fake (GenericSystem), and gz_classic (gazebo_ros2_control/GazeboSystem). There’s no new-gz / gz_ros2_control branch. So to run it in the Panther Fortress sim, I think I would need to write my own ros2_control block with gz_ros2_control/GazeboSimSystem over the 6 arm joints, rather than reuse theirs.
The 6 joints (all revolute, from their description), with limits:
waist (±π), shoulder (−106°…72°), elbow (−101°…92°), forearm_roll (±π), wrist_angle (−107°…128°), wrist_rotate (±π), plus a gripper (left_finger/right_finger, prismatic).
On the real robot, the arm currently runs as its own stack (xsarm_moveit, hardware_type:=actual) joined to the Panther only by a static transform base_link → vx300s/base_link i.e. the arm has its own controller_manager, separate from the Panther base. So in sim I was planning to mirror that by attaching the vx300s via type: custom then giving it its own gz_ros2_control block + joint_trajectory_controller/joint_state_broadcaster, and join it by the same static transform.
My questions:
For the arm’s gz_ros2_control block, would you recommend it run its own controller_manager (mirroring how the real arm is a separate stack), or be merged into the Panther base’s controller_manager? You flagged this needs verifying against the actual gz_ros2_control setup how do I handle it?
Any gotchas with two gz_ros2_control plugin instances in one world / one model vs. two models because we aim to scale the simulation to multiple panthers in one world?
Happy to share the actual xacro files if useful. Thanks again for the offer to look.