This project implements most features from the original franka_ros repository in ROS2 Humble, specifically for the Franka Emika Robot (Panda). This project significantly expands upon the original franka_ros2 from the company, who dropped the support for the Pandas.
The current version relies on a fork of the repository
More thorough information is available in the documentation.
- FrankaState broadcaster
- All control interfaces (torque, position, velocity, Cartesian)
- Example controllers for all interfaces
- Controllers are swappable using rqt_controller_manager
- Runtime
franka::ControlExceptionerror recovery via~/service_server/error_recovery- Upon recovery, the previously executed control loop will be executed again, so no reloading necessary
- Runtime internal parameter setter services much like what is offered in the updated
franka_ros2
- Same as the real robot, except Cartesian command interface is not available, and there is no plan to implement this for now
- Gripper server with identical interface to the real gripper (i.e. action servers)
- Example controllers for the real single-arm listed above, that correspond to those interfaces, work out of the box
- FrankaState implements the basics: torque, joint position/velocity,
O_T_EEandO_F_ext_hat - Model provides all the existing functions:
pose,zeroJacobian,bodyJacobian,mass,gravity,coriolis- Gravity for now just returns the corresponding
qfrc_gravcompforce from mujoco - Coriolis =
qfrc_bias - qfrc_gravcomp
- Gravity for now just returns the corresponding
- Camera is available as part of
mujoco_ros_pkg's features. You can simply add a<camera>object in your mujoco XML file, and the package will handle them. - With the forked repository's
mujoco_ros2_control_systempackage, you can easily add components with additional degrees of freedom to your robot. Take a look atgarmi_packages/garmi_description/robots/*.ros2_control.xacrofor an example on how to do this.
Open cmd as administrator:
wsl --install -d UbuntuThis installs Virtual Machine Platform, Windows Subsystem for Linux, and Ubuntu. Reboot your device. The Ubuntu installation may resume on its own after reboot — let it finish, then it asks for a username and password (this is a new Linux login, separate from Windows). It may then ask about metrics collection — either answer works.
Now you're in the Ubuntu terminal — leave it open, and open a separate cmd window and run:
wsl -l -vConfirm VERSION shows 2, e.g.:
NAME STATE VERSION
* Ubuntu Running 2
Still in that same cmd window (not the Ubuntu one), run:
notepad "%USERPROFILE%\.wslconfig"Press Yes to create the file. Paste:
[wsl2]
networkingMode=mirroredSave, close, then:
wsl --shutdownReopen the Ubuntu app from the Start menu.
Install Docker Desktop for Windows (docker.com) — keep "Use WSL 2 instead of Hyper-V" checked during install (default). After install, go to Docker Desktop → Settings → Resources → WSL Integration:
- "Enable integration with my default WSL distro" — ON
- Your Ubuntu distro toggled ON individually
- Apply & Restart
Back in the Ubuntu WSL terminal:
docker infoIf you see "permission denied" — close the Ubuntu window entirely, reopen, and retry.
(Optional, if you have an NVIDIA GPU):
nvidia-smiIf this shows your GPU, Docker will auto-detect it later — nothing else needed.
Clone the repository:
cd ~
mkdir -p UET_BRIDGE
cd UET_BRIDGE
git clone --recursive https://github.com/zainali3174/multipanda_ros2.git
cd multipanda_ros2Checkout the branch you actually want to work on — a fresh clone defaults to the repo's default branch (humble), not fyp-dev or uet_bridge:
git checkout uet_bridgeSet up and enter the container:
./tools/setup_env
sudo apt update
sudo apt install -y x11-xserver-utils
./runYou're now inside the container at a developer@docker-desktop prompt. Still inside the container, build the workspace:
colcon buildMake ROS see your built packages in every future shell:
echo "source ~/multipanda_ws/install/setup.bash" >> ~/.bashrcTo open a second terminal into the same running container later (open a new WSL/Ubuntu terminal window, then run):
docker exec -it --user developer multipanda-container /bin/bash -c "source /home/developer/.bashrc && bash"Everything above is identical, except:
- Mirrored networking (the
.wslconfigstep) may not be supported on older Windows 10 builds. Check withwsl --version— ifnetworkingModeisn't recognized afterwsl --shutdown, skip that step and flag it so therunscript's--networkflag can be adjusted instead. - Install VcXsrv (search "VcXsrv" on SourceForge), launch it via XLaunch with "Disable access control" checked, and leave it running in the background.
- Add this line to
~/.bashrcinside WSL (not the container) before running./run:
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0Then:
source ~/.bashrcMake sure VcXsrv is already running before ./run.
- Clone the repository recursively to include mujoco_ros_pkgs:
git clone --recursive https://github.com/zainali3174/multipanda_ros2.git- Change into the cloned repository:
cd multipanda_ros2- Build the docker image by running one command (takes some time):
./tools/setup_env- Once the image is built, start the development container:
./runThe default config allows for communication in the network, GPU access, display forwarding for GUI applications, hardware devices, etc. By default the script opens a bash shell inside the container as a developer user (password can be modified in the Dockerfile) in the ROS2 workspace under ~/multipanda_ws.
- Build ROS2 packages with:
colcon buildIn case there are problems with missing packages, try running the following commands inside the container before colcon build:
sudo apt update && \
rosdep update && \
rosdep install --from-paths src --ignore-src -y -r- To verify that the installation was successful, run:
source ~/multipanda_ws/install/setup.bash && \
ros2 launch franka_bringup franka_sim.launch.pyThis should open up a MuJoCo simulation with one Franka Panda arm.
To open the docker container in an additional terminal, use the docker exec command:
docker exec -it --user developer multipanda-container bash-
(Optional) Check that the connection to the robot, RT kernel, and screen are all working fine (make sure the FCI feature is activated).
Check that docker is properly linked to your screen by running either:
ros2 run rviz2 rviz2 # or ~/Libraries/mujoco/bin/simulate
For RT kernel and robot connection, run:
~/Libraries/libfranka/bin/communication_test <robot-ip>
This fork extends the base multipanda_ros2 project with additional packages developed as part of a Final Year Project:
panda_cartesian_control— provides Cartesian (XYZ/HTM-based) motion control and pick-and-place orchestration for the Franka arm on top of MoveIt, exposing custom ROS2 actions (htm_motion,pick_place) instead of requiring manual RViz interaction.panda_cartesian_control_msgs— custom action definitions (HTMMotion,PickPlace) used by the above.
docker exec -it --user developer multipanda-container bashRun the commands below inside the container unless noted otherwise.
# Simulation
ros2 launch franka_moveit_config sim_moveit.launch.py
# Hardware (fake)
ros2 launch franka_moveit_config moveit.launch.py robot_ip:=dummy use_fake_hardware:=true
# Hardware (real)
ros2 launch franka_moveit_config moveit.launch.py robot_ip:=172.16.0.2Simulation
# Terminal 1
ros2 launch franka_moveit_config sim_moveit.launch.py
# Terminal 2
ros2 run panda_cartesian_control cartesian_moveit_server
# Terminal 3
ros2 action send_goal /cartesian_via_motion panda_motion_generator_msgs/action/CartesianViaMotion "{via_poses: [{position: {x: 0.4, y: 0.0, z: 0.5}, orientation: {x: 1.0, y: 0.0, z: 0.0, w: 0.0}}], v_scale: 0.2}"Hardware
# Terminal 1
ros2 launch franka_moveit_config moveit.launch.py robot_ip:=172.16.0.2
# Terminal 2
ros2 run panda_cartesian_control cartesian_moveit_server
# Terminal 3
ros2 action send_goal /cartesian_via_motion panda_motion_generator_msgs/action/CartesianViaMotion "{via_poses: [{position: {x: 0.4, y: 0.0, z: 0.5}, orientation: {x: 1.0, y: 0.0, z: 0.0, w: 0.0}}], v_scale: 0.2}"Checking current end-effector HTM
ros2 run tf2_ros tf2_echo panda_link0 panda_link8ros2 action send_goal /htm_motion panda_cartesian_control_msgs/action/HTMMotion "{htm: [1,0,0,0.4, 0,-1,0,-0.2, 0,0,-1,0.4, 0,0,0,1], v_scale: 0.2}"
# Corrected orientation
ros2 action send_goal /htm_motion panda_cartesian_control_msgs/action/HTMMotion "{htm: [0.707,-0.707,0,0.4, -0.707,-0.707,0,-0.2, 0,0,-1,0.4, 0,0,0,1], v_scale: 0.2}"# Simulation
ros2 action send_goal /panda_gripper_sim_node/move franka_msgs/action/Move "{width: 0.08, speed: 0.1}"
# Hardware
# Terminal 1
ros2 launch franka_moveit_config moveit.launch.py robot_ip:=172.16.0.2 load_gripper:=true
# Terminal 2
ros2 action send_goal /panda_gripper/move franka_msgs/action/Move "{width: 0.08, speed: 0.1}"
ros2 action send_goal /panda_gripper/grasp franka_msgs/action/Grasp "{width: 0.05, epsilon: {inner: 0.01, outer: 0.01}, speed: 0.05, force: 20.0}"Simulation
# Terminal 1
ros2 launch franka_moveit_config sim_moveit.launch.py
# Terminal 2
ros2 run panda_cartesian_control cartesian_moveit_server
# Terminal 3
ros2 run panda_cartesian_control pick_place_server --ros-args -p use_sim:=true
# Terminal 4
ros2 action send_goal /pick_place panda_cartesian_control_msgs/action/PickPlace "{pick_xyz: [0.4, -0.2, 0.3], place_xyz: [0.4, 0.2, 0.3], z_offset: 0.1, grasp_width: 0.05, grasp_force: 20.0}" --feedbackHardware
# Terminal 1
ros2 launch franka_moveit_config moveit.launch.py robot_ip:=172.16.0.2
# Terminal 2
ros2 run panda_cartesian_control cartesian_moveit_server
# Terminal 3
ros2 run panda_cartesian_control pick_place_server --ros-args -p use_sim:=false
# Terminal 4
ros2 action send_goal /pick_place panda_cartesian_control_msgs/action/PickPlace "{pick_xyz: [0.4, -0.2, 0.3], place_xyz: [0.4, 0.2, 0.3], z_offset: 0.1, grasp_width: 0.05, grasp_force: 20.0}" --feedbackUse these commands to add and remove obstacle in RViz. These are not permanent and wont be there if you restart your setup. These obstacles will also not be visible in Mujuco.
Adding the obstacle
python3 << 'PYEOF'
import rclpy
from rclpy.node import Node
from moveit_msgs.msg import PlanningScene, CollisionObject
import time
rclpy.init()
node = Node('remove_obstacle')
pub = node.create_publisher(PlanningScene, '/planning_scene', 10)
time.sleep(1.0)
obj = CollisionObject()
obj.header.frame_id = 'panda_link0'
obj.id = 'human_obstacle'
obj.operation = CollisionObject.REMOVE
scene = PlanningScene()
scene.world.collision_objects.append(obj)
scene.is_diff = True
for _ in range(3):
pub.publish(scene)
time.sleep(0.5)
print("Removed collision object")
node.destroy_node()
rclpy.shutdown()
PYEOFRemoving/ the obstacle
python3 << 'PYEOF'
import rclpy
from rclpy.node import Node
from moveit_msgs.msg import PlanningScene, CollisionObject
import time
rclpy.init()
node = Node('remove_obstacle')
pub = node.create_publisher(PlanningScene, '/planning_scene', 10)
time.sleep(1.0)
obj = CollisionObject()
obj.header.frame_id = 'panda_link0'
obj.id = 'human_obstacle'
obj.operation = CollisionObject.REMOVE
scene = PlanningScene()
scene.world.collision_objects.append(obj)
scene.is_diff = True
for _ in range(3):
pub.publish(scene)
time.sleep(0.5)
print("Removed collision object")
node.destroy_node()
rclpy.shutdown()
PYEOFAll packages of multipanda_ros2 are licensed under the Apache 2.0 license, following franka_ros2.
