Week 5 — Swapping in the UR10 and cleaning up the framework
GSoC 2026 · Week 5 · Coding period
Week 5: Swapping in the UR10 and cleaning up the framework
My mentors suggested upgrading the palletizing arm from a UR5 to a UR10 — the UR10 has a 1.3 m reach (vs 0.85 m) and a 10 kg payload, which is a much better match for a real palletizing scenario. That sounded like a one-word change (ur_type: ur10), but the rabbit hole went a bit deeper than expected.
The hardcoded group name problem
The three shared C++ action servers that drive arm motion — move, robmove, robpose — all had this:
std::string group_name = "ur5_manipulator"; // hardcoded in 5 places
move_group_interface_ROB = MoveGroupInterface(node, group_name);
MoveIt uses this string to look up the planning group in the SRDF. If it doesn’t match exactly, every motion call fails silently with “unknown group.” So a UR10 that declares its group ur10_arm in the SRDF would never plan anything — not because the geometry is wrong, but because a single string literal points somewhere else.
The fix I went with (matching an approach mentor Jesus used on a parallel branch) was to add a MOVE_GROUP ROS parameter with a default of "ur5_manipulator". The existing Pick & Place launcher passes nothing → gets the default → unchanged behaviour. The new UR10 launcher explicitly sets {"MOVE_GROUP": "ur10_arm"} on all three nodes. Five hardcoded literals replaced, one rebuild, zero regressions.
The arm swap itself
With the framework unblocked, the swap was mostly renaming and config edits:
-
ur_type,ROB_PARAM→ur10everywhere - SRDF group
ur5_manipulator→ur10_arm - Joint limits and Pilz Cartesian limits swapped to the
ur10/config/paths - The Gazebo spawn entity name and the world’s
<robot_model_name>both updated tour10_suction— these two must change together becausegz_link_attacherlooks up the robot by that name to know where to attach the suction grip
Naming things properly
At one point during the work I noticed we had a file called ur5_suction.urdf.xacro that was already describing a UR10 arm. That’s exactly the kind of confusion that causes real bugs — a future me would open that file assuming UR5 geometry and get UR10 instead.
So I renamed the whole family: ur5_suction.* → ur10_suction.*, and moved the URDF from models/ur5/ into a proper models/ur10/ folder. The shared generic xacro includes (ur.urdf.xacro, ur.ros2_control.xacro) stayed in models/ur5/ — those are arm-agnostic and Pick & Place relies on them — but the suction-specific file now lives where it should.
The ghost package bug
While validating the xacro I ran into a crash: Package 'ur5_gripper_description' not found. It turned out config/ur10/visual_parameters.yaml was imported from IFRA (the upstream framework) with all 14 mesh references pointing at that package — which isn’t installed in the RA image. The UR10 meshes actually live inside ros2srrc_robots/ur10/meshes/, mirroring the convention the UR5 yaml already uses correctly.
One bulk replace later, the xacro parsed cleanly to 575 lines. The arm would have loaded without meshes otherwise — a silent rendering failure that would have been genuinely annoying to track down.
Demo
Here’s the current state — the UR10 loaded in Gazebo Harmonic alongside the palletizing scene, with the arm skeleton showing in RViz:
Also this week: rectangular boxes
One detail I also got in: the palletizing boxes are now proper rectangular cuboids instead of cubes. Real-world palletizing almost never involves perfect cubes, and the rectangular shape makes placement orientation meaningful — which matters once the motion planning is written.
What’s next
The arm is in, named correctly, and plans against the right group. Next is getting the HAL’s SuctionSet wired up — replacing the GripperSet stub copied from Pick & Place with a proper vacuum on/off toggle — and then writing the actual pick-and-place motion logic for the palletizing cycle.
Until next week.
Enjoy Reading This Article?
Here are some more articles you might like to read next: