Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ project(multi_robot_arm)
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(gazebo_ros REQUIRED)
find_package(ros_gz_sim REQUIRED)

include_directories(include)
link_directories(
Expand All @@ -16,7 +16,14 @@ set(THIS_PACKAGE_INCLUDE_DEPENDS
std_msgs
)

install(DIRECTORY launch config urdf worlds DESTINATION share/${PROJECT_NAME})
install(DIRECTORY launch config urdf worlds scripts DESTINATION share/${PROJECT_NAME})

# Install Python scripts
install(PROGRAMS
scripts/dance_arms.py
scripts/activate_controllers.py
DESTINATION lib/${PROJECT_NAME}
)
ament_environment_hooks("${CMAKE_CURRENT_SOURCE_DIR}/env-hooks/multi_robot_arm.dsv.in")

ament_package()
96 changes: 81 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,62 @@ The UR5 robotic arm, a versatile and widely-used model in robotics, serves as th
![image](https://github.com/arshadlab/multi_robot_arm/assets/85929438/4e052e79-65c7-4fe5-b73a-871b76b9f01e)
![image](https://github.com/arshadlab/multi_robot_arm/assets/85929438/3189c420-33c1-424c-aaa4-0cc2b8cc868c)

## Demo: Gazebo Harmonic Simulation
Check out the demo video showcasing multi-robot arm simulation with Gazebo Harmonic:

![Gazebo Harmonic Demo](./run.mp4)

## What's New

### ROS2 Jazzy & Gazebo Harmonic Support
We've added full support for **ROS2 Jazzy** and **Gazebo Harmonic**, the latest stable distributions in the ROS2 ecosystem. This brings several benefits:

- **Enhanced Physics Simulation**: Gazebo Harmonic provides improved physics accuracy and performance
- **Improved Compatibility**: Full integration with modern ROS2 tooling and libraries
- **Better Performance**: Optimized for the latest hardware and software stacks
- **ROS-Gazebo Bridge**: Native support via `ros-gz` for seamless ROS2-Gazebo integration

### Launch Files
- **`gazebo_arm.launch.py`**: For ROS2 Humble + Gazebo 11 (legacy)
- **`gazebo_harmonic_arm.launch.py`**: For ROS2 Jazzy + Gazebo Harmonic (recommended)

## Python MoveIt2 Bindings
The present version of this tutorial employs a fork of pymoveit2, a Python library developed to facilitate interaction with MoveIt2. This has been an effective approach and served the purpose well.

However, in recent times, MoveIt2 has introduced native Python bindings in its codebase. These bindings enable direct interaction with MoveIt2 via Python, eliminating the need for additional libraries like pymoveit2. This advancement simplifies the setup process, reduces dependency issues, and potentially enhances performance and stability.

As part of ongoing improvements and in the spirit of keeping up with these updates, future versions of this tutorial may transition to using the Python bindings provided directly by MoveIt2. This would replace the current reliance on the pymoveit2 fork, streamlining the implementation process and ensuring compatibility with future developments in MoveIt2. Consequently, this change will not only refine the tutorial but also make it more adaptable and robust for future use-cases.

## Setup
The package is verified with ROS2 Foxy and Humble.

Dependencies: ROS2 [Foxy or Humble], moveit2, pymoveit2, Gazebo 11
### Supported Configurations
The package is verified and tested with the following configurations:

| ROS2 Version | Gazebo Version | Launch File | Status |
|---|---|---|---|
| Humble | 11 | `gazebo_arm.launch.py` | ✓ Tested |
| Jazzy | Harmonic | `gazebo_harmonic_arm.launch.py` | ✓ Tested |

### Dependencies

**For ROS2 Humble + Gazebo 11:**
- ROS2 Humble
- moveit2
- pymoveit2
- Gazebo 11

**For ROS2 Jazzy + Gazebo Harmonic:**
- ROS2 Jazzy
- moveit2
- pymoveit2
- Gazebo Harmonic
- ros-gz (ROS-Gazebo bridge)

## Clone and Build
```
source /opt/ros/<DISTRO>/setup.bash

### For ROS2 Humble
```bash
source /opt/ros/humble/setup.bash
mkdir -p robot_ws/src
cd robot_ws/src
git clone https://github.com/arshadlab/multi_robot_arm.git
Expand All @@ -29,30 +71,54 @@ rosdep install --from-paths src --ignore-src -r -y
colcon build --symlink-install
```

## Launch
### Console A (Launch Gazebo)
### For ROS2 Jazzy
```bash
source /opt/ros/jazzy/setup.bash
mkdir -p robot_ws/src
cd robot_ws/src
git clone https://github.com/arshadlab/multi_robot_arm.git
cd ..
rosdep install --from-paths src --ignore-src -r -y
sudo apt install ros-jazzy-pymoveit2
colcon build --symlink-install
```

**Note:** For ROS2 Jazzy, pymoveit2 is available as an apt package, so cloning from git is not required.

## Launch

### Option 1: ROS2 Humble with Gazebo 11
#### Console A (Launch Gazebo)
```bash
source ./install/setup.bash
ros2 launch multi_robot_arm gazebo_arm.launch.py
```

### Console B (Trigger ARM movement)

ARM1 movement to position [0.5, 0.4,0.2] using kinematic path planner
### Option 2: ROS2 Jazzy with Gazebo Harmonic (Recommended)
#### Console A (Launch Gazebo Harmonic)
```bash
source ./install/setup.bash
ros2 launch multi_robot_arm gazebo_harmonic_arm.launch.py
```

### Triggering ARM Movement
#### Console B (Trigger ARM movement)

ARM1 movement to position [0.5, 0.4, 0.2] using kinematic path planner:
```bash
source ./install/setup.bash
cd ./src/pymoveit2/examples
python ex_pose_goal.py --ros-args -r __ns:=/arm1 -p position:=[0.5, 0.4,0.2]
python ex_pose_goal.py --ros-args -r __ns:=/arm1 -p position:=[0.5,0.4,0.2]
```

ARM4 movement to position [0.5, 0.4,0.2] using cartesian path planner
```
ARM4 movement to position [0.5, 0.4, 0.2] using cartesian path planner:
```bash
source ./install/setup.bash
cd ./src/pymoveit2/examples
python ex_pose_goal.py --ros-args -r __ns:=/arm4 -p position:=[0.5, 0.4,0.2] -p cartesian:=True
python ex_pose_goal.py --ros-args -r __ns:=/arm4 -p position:=[0.5,0.4,0.2] -p cartesian:=True
```

__ns:=/namespace parameter is to direct commands to a specific instance of robot. Position coordinates are given relative to arm position.
**Note:** The `__ns:=/namespace` parameter directs commands to a specific instance of robot. Position coordinates are given relative to arm position.

## Acknowledgement
pymoveit2 -> https://github.com/AndrejOrsula/pymoveit2
pymoveit2 https://github.com/AndrejOrsula/pymoveit2
21 changes: 3 additions & 18 deletions config/ur/ur5/ros_controllers_robot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ arm_controller:
wrist_1_joint: { trajectory: 0.25, goal: 0.1 }
wrist_2_joint: { trajectory: 0.25, goal: 0.1 }
wrist_3_joint: { trajectory: 0.25, goal: 0.1 }
use_sim_time: false
use_sim_time: true

forward_velocity_controller:
ros__parameters:
Expand All @@ -58,7 +58,7 @@ forward_velocity_controller:

interface_name:
- velocity
use_sim_time: false
use_sim_time: true
forward_position_controller:
ros__parameters:
joints:
Expand All @@ -68,19 +68,4 @@ forward_position_controller:
- wrist_1_joint
- wrist_2_joint
- wrist_3_joint
use_sim_time: false
# Gripper controller
rgripper_controller1:
ros__parameters:
joint: robotiq_85_left_knuckle_joint
action_monitor_rate: 20.0
goal_tolerance: 0.002
max_effort: 100.0
stall_velocity_threshold: 0.001
stall_timeout: 1.0
command_interfaces:
- position
state_interfaces:
- position
- velocity
use_sim_time: false
use_sim_time: true
26 changes: 8 additions & 18 deletions launch/gazebo_arm.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ def spawn_robot(

robot_description = {"robot_description": robot_urdf}

kinematics_yaml = load_yaml(
package_path, "config/ur/" + robot_type + "/kinematics.yaml"
kinematics_yaml = xacro.load_yaml(
os.path.join(package_path, "config/ur/" + robot_type + "/kinematics.yaml")
)

robot_description_semantic_config = load_file(
Expand All @@ -185,22 +185,21 @@ def spawn_robot(
},
}

ompl_planning_yaml = load_yaml(
package_path, "config/ur/" + robot_type + "/ompl_planning.yaml"
ompl_planning_yaml = xacro.load_yaml(
os.path.join(package_path, "config/ur/" + robot_type + "/ompl_planning.yaml")
)

ompl_planning_pipeline_config["ompl"].update(ompl_planning_yaml)

joint_limits_yaml = load_yaml(
package_path, "config/ur/" + robot_type + "/joint_limits_planning.yaml"
joint_limits_yaml = xacro.load_yaml(
os.path.join(package_path, "config/ur/" + robot_type + "/joint_limits_planning.yaml")
)

joint_limits = {"robot_description_planning": joint_limits_yaml}

# Trajectory Execution Functionality
moveit_simple_controllers_yaml = load_yaml(
package_path,
"config/ur/" + robot_type + "/moveit_controller_manager.yaml"
moveit_simple_controllers_yaml = xacro.load_yaml(
os.path.join(package_path, "config/ur/" + robot_type + "/moveit_controller_manager.yaml")
)

moveit_controllers = {
Expand Down Expand Up @@ -402,12 +401,3 @@ def load_file(package_path, file_path):
return file.read()
except EnvironmentError:
return None

def load_yaml(package_path, file_path):

absolute_file_path = os.path.join(package_path, file_path)
try:
with open(absolute_file_path, "r") as file:
return yaml.safe_load(file)
except EnvironmentError:
return None
Loading