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
7 changes: 4 additions & 3 deletions .github/workflows/ros-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ jobs:
echo "--- Updating rosdep definitions ---"
rosdep update
echo "--- Installing system dependencies for ROS 2 ${{ matrix.ros_distribution }} ---"
rosdep install --from-paths ros_ws/src --ignore-src -y -r --rosdistro ${{ matrix.ros_distribution }}
rosdep install --from-paths ros_ws/src --ignore-src -y -r --rosdistro ${{ matrix.ros_distribution }} --skip-keys dynamixel_hardware_interface
echo "--- Performing rosdep check for ROS 2 ${{ matrix.ros_distribution }} ---"
if rosdep check --from-paths ros_ws/src --ignore-src --rosdistro ${{ matrix.ros_distribution }}; then
if rosdep check --from-paths ros_ws/src --ignore-src --rosdistro ${{ matrix.ros_distribution }} --skip-keys dynamixel_hardware_interface; then
echo "--- rosdep check passed ---"
else
echo "--- rosdep check failed: Missing system dependencies or unresolvable keys. ---"
Expand All @@ -71,8 +71,9 @@ jobs:

with:
target-ros2-distro: ${{ matrix.ros_distribution }}
vcs-repo-file-url: ""
vcs-repo-file-url: "https://raw.githubusercontent.com/ROBOTIS-GIT/dynamixel_hardware_interface_demos/${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }}/dynamixel_hardware_interface_demos_ci.repos"
package-name: |
dynamixel_hardware_interface_demos
dynamixel_hardware_interface_example
dynamixel_hardware_interface_example_1
dynamixel_hardware_interface_example_2
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# dynamixel_hardware_interface_demos

This repository collects example packages and resources for working with Dynamixel hardware using the ros2_control framework.
This repository collects example packages and resources for working with Dynamixel hardware using the ros2_control framework.

## Overview
This repository is intended to help users get started with Dynamixel hardware integration in ROS 2. It provides example configurations, launch files, and scripts to demonstrate how to use the `dynamixel_hardware_interface` with ros2_control and controller_manager.
Expand All @@ -11,6 +11,8 @@ This repository is intended to help users get started with Dynamixel hardware in
- Example package with configuration files, launch files, and scripts for setting up and running a Dynamixel-based robot system using ros2_control.
- [dynamixel_hardware_interface_example_1](dynamixel_hardware_interface_example_1/README.md)
- Example package demonstrating a dual Dynamixel system (two buses) with separate ros2_control configurations and a dedicated launch file for running both systems together.
- [dynamixel_hardware_interface_example_2](dynamixel_hardware_interface_example_2/README.md)
- Example package demonstrating a system with an Dynamixel Protocol compatible IMU sensor using the dynamixel_hardware_interface.

## Getting Started

Expand Down
3 changes: 2 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ RUN mkdir -p ${COLCON_WS}/src && \
git clone -b jazzy https://github.com/ROBOTIS-GIT/dynamixel_hardware_interface.git && \
git clone -b jazzy https://github.com/ROBOTIS-GIT/dynamixel_interfaces.git && \
git clone -b jazzy https://github.com/ROBOTIS-GIT/DynamixelSDK.git && \
git clone -b jazzy https://github.com/ROBOTIS-GIT/dynamixel_hardware_interface_demos.git
git clone -b jazzy https://github.com/ROBOTIS-GIT/dynamixel_hardware_interface_demos.git && \
git clone -b jazzy https://github.com/ros2/rmw_zenoh.git

RUN cd ${COLCON_WS} && \
apt-get update && \
Expand Down
4 changes: 4 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ services:
rttime: -1
memlock: 8428281856
network_mode: host
ipc: host
pid: host
environment:
- DISPLAY=${DISPLAY}
- QT_X11_NO_MITSHM=1
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented-out RMW_IMPLEMENTATION environment variable lacks documentation explaining when or why a user should uncomment it. Consider adding a comment above this line explaining the purpose and usage of rmw_zenoh.

Suggested change
- QT_X11_NO_MITSHM=1
- QT_X11_NO_MITSHM=1
# Uncomment the line below to use the Zenoh-based ROS 2 RMW implementation (rmw_zenoh_cpp)
# instead of the default middleware, if rmw_zenoh_cpp is installed in the image.

Copilot uses AI. Check for mistakes.
# - RMW_IMPLEMENTATION=rmw_zenoh_cpp
volumes:
- /dev:/dev
- /dev/shm:/dev/shm
- ./workspace:/workspace
- /tmp/.X11-unix:/tmp/.X11-unix:rw
- /tmp/.docker.xauth:/tmp/.docker.xauth:rw
Expand Down
5 changes: 5 additions & 0 deletions dynamixel_hardware_interface_demos/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
Changelog for package dynamixel_hardware_interface_demos
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0.0.4 (2025-12-15)
------------------
* Introduced dynamixel_hardware_interface_example_2 package for using the dynamixel_hardware_interface with imu sensor
* Contributors: Woojin Wie

0.0.3 (2025-09-12)
------------------
* Updated package.xml to include dynamixel_hardware_interface_example_1
Expand Down
1 change: 1 addition & 0 deletions dynamixel_hardware_interface_demos/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<buildtool_depend>ament_cmake</buildtool_depend>
<exec_depend>dynamixel_hardware_interface_example</exec_depend>
<exec_depend>dynamixel_hardware_interface_example_1</exec_depend>
<exec_depend>dynamixel_hardware_interface_example_2</exec_depend>
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package.xml version is 0.0.3, but the CHANGELOG indicates this is version 0.0.4. The package version should be updated to 0.0.4 to match the changelog entry and the new functionality being added.

Copilot uses AI. Check for mistakes.
<export>
<build_type>ament_cmake</build_type>
</export>
Expand Down
5 changes: 5 additions & 0 deletions dynamixel_hardware_interface_demos_ci.repos
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
repositories:
utils/dynamixel_hardware_interface:
type: git
url: https://github.com/ROBOTIS-GIT/dynamixel_hardware_interface.git
version: main
4 changes: 4 additions & 0 deletions dynamixel_hardware_interface_example/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Changelog for package dynamixel_hardware_interface_example
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0.0.4 (2025-12-15)
------------------
* None

0.0.3 (2025-09-12)
------------------
* Introduced xacro arguments for port_name and baud_rate
Expand Down
8 changes: 5 additions & 3 deletions dynamixel_hardware_interface_example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ You can generate custom XACRO files for your robot using the provided script and
```bash
ros2 launch dynamixel_hardware_interface_example generate_xacros.launch.py \
num_joints:=4 \
baudrate:=4000000 \
baud_rate:=4000000 \
port_name:=/dev/ttyUSB0
```
- `num_joints`: Number of joints/motors in your robot
- `baudrate`: Baudrate for the Dynamixel port
- `baud_rate`: Baudrate for the Dynamixel port
- `port_name`: Serial port for the Dynamixel device

This will generate new XACRO files in the `config/` directory.
Expand All @@ -48,7 +48,9 @@ This will generate new XACRO files in the `config/` directory.
After generating the XACRO files, launch the hardware interface and controller manager:

```bash
ros2 launch dynamixel_hardware_interface_example hardware.launch.py
ros2 launch dynamixel_hardware_interface_example hardware.launch.py \
baud_rate:=4000000 \
port_name:=/dev/ttyUSB0
```

## Configuration Files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@


# Generate the .ros2_control.xacro file
def generate_ros2_control_xacro(num_joints, filename, baudrate, port_name, command_interface):
def generate_ros2_control_xacro(num_joints, filename, baud_rate, port_name, command_interface):
# Determine the appropriate interface names based on command_interface
if command_interface == 'position':
joint_command_interface = 'position'
Expand Down Expand Up @@ -101,13 +101,13 @@ def generate_ros2_control_xacro(num_joints, filename, baudrate, port_name, comma


# Generate the .urdf.xacro file
def generate_urdf_xacro(num_joints, filename, baudrate, port_name):
def generate_urdf_xacro(num_joints, filename, baud_rate, port_name):
with open(filename, 'w') as f:
f.write('<?xml version="1.0"?>\n')
f.write('<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="dynamixel_system">\n')
f.write(' <xacro:arg name="prefix" default="" />\n')
# Provide xacro args for baud_rate and port_name with defaults from CLI
f.write(f' <xacro:arg name="baud_rate" default="{baudrate}" />\n')
f.write(f' <xacro:arg name="baud_rate" default="{baud_rate}" />\n')
f.write(f' <xacro:arg name="port_name" default="{port_name}" />\n')
f.write(' <xacro:include filename="dynamixel_system.ros2_control.xacro" />\n')
f.write('\n')
Expand All @@ -134,33 +134,33 @@ def generate_urdf_xacro(num_joints, filename, baudrate, port_name):
def main():
if len(sys.argv) < 2:
print('Usage: python generate_dynamixel_xacros.py <number_of_joints> '
'[output_dir] [baudrate] [port_name] [command_interface]')
'[output_dir] [baud_rate] [port_name] [command_interface]')
sys.exit(1)
try:
num_joints = int(sys.argv[1])
except ValueError:
print('First argument must be an integer (number of joints)')
sys.exit(1)
config_dir = os.path.join(os.path.dirname(__file__), 'config')
baudrate = '4000000'
baud_rate = '4000000'
port_name = '/dev/ttyUSB0'
command_interface = 'position' # Default value
if len(sys.argv) >= 3:
config_dir = sys.argv[2]
if len(sys.argv) >= 4:
baudrate = sys.argv[3]
baud_rate = sys.argv[3]
if len(sys.argv) >= 5:
port_name = sys.argv[4]
if len(sys.argv) >= 6:
command_interface = sys.argv[5]
os.makedirs(config_dir, exist_ok=True)
ros2_control_path = os.path.join(config_dir, 'dynamixel_system.ros2_control.xacro')
urdf_xacro_path = os.path.join(config_dir, 'dynamixel_system.urdf.xacro')
generate_ros2_control_xacro(num_joints, ros2_control_path, baudrate,
generate_ros2_control_xacro(num_joints, ros2_control_path, baud_rate,
port_name, command_interface)
generate_urdf_xacro(num_joints, urdf_xacro_path, baudrate, port_name)
generate_urdf_xacro(num_joints, urdf_xacro_path, baud_rate, port_name)
print(f'Generated xacro files for {num_joints} joints in {config_dir}. '
f'Baudrate: {baudrate}, Port: {port_name}, Command Interface: {command_interface}')
f'baud_rate: {baud_rate}, Port: {port_name}, Command Interface: {command_interface}')


if __name__ == '__main__':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def generate_launch_description():
description='Directory to save generated xacro files.'
),
DeclareLaunchArgument(
'baudrate',
'baud_rate',
default_value='4000000',
description='Baudrate for the Dynamixel port.'
),
Expand All @@ -60,7 +60,7 @@ def generate_launch_description():

num_joints = LaunchConfiguration('num_joints')
output_dir = LaunchConfiguration('output_dir')
baudrate = LaunchConfiguration('baudrate')
baud_rate = LaunchConfiguration('baud_rate')
port_name = LaunchConfiguration('port_name')
command_interface = LaunchConfiguration('command_interface')

Expand All @@ -69,7 +69,7 @@ def generate_launch_description():
executable='generate_xacros',
name='generate_xacros',
output='screen',
arguments=[num_joints, output_dir, baudrate, port_name, command_interface],
arguments=[num_joints, output_dir, baud_rate, port_name, command_interface],
)

return LaunchDescription(declared_arguments + [generate_xacros_node])
2 changes: 1 addition & 1 deletion dynamixel_hardware_interface_example/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

setup(
name=package_name,
version='0.0.3',
version='0.0.4',
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version in setup.py has been updated to 0.0.4, but the corresponding package.xml file still has version 0.0.3. These versions should be synchronized to avoid confusion during package distribution and dependency resolution.

Suggested change
version='0.0.4',
version='0.0.3',

Copilot uses AI. Check for mistakes.
packages=find_packages(exclude=['test']),
data_files=[
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
Expand Down
4 changes: 4 additions & 0 deletions dynamixel_hardware_interface_example_1/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Changelog for package dynamixel_hardware_interface_example_1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0.0.4 (2025-12-15)
------------------
* None

0.0.3 (2025-09-12)
------------------
* Introduced dynamixel_hardware_interface_example_1 package for dual ros2_control
Expand Down
2 changes: 1 addition & 1 deletion dynamixel_hardware_interface_example_1/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

setup(
name=package_name,
version='0.0.3',
version='0.0.4',
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version in setup.py has been updated to 0.0.4, but the corresponding package.xml file still has version 0.0.3. These versions should be synchronized to avoid confusion during package distribution and dependency resolution.

Suggested change
version='0.0.4',
version='0.0.3',

Copilot uses AI. Check for mistakes.
packages=find_packages(exclude=['test']),
data_files=[
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
Expand Down
8 changes: 8 additions & 0 deletions dynamixel_hardware_interface_example_2/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Changelog for package dynamixel_hardware_interface_example_2
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0.0.4 (2025-12-15)
------------------
* Added example package for using the dynamixel_hardware_interface with imu sensor
* Contributors: Woojin Wie
19 changes: 19 additions & 0 deletions dynamixel_hardware_interface_example_2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Dynamixel Hardware Interface Example 2 (IMU ros2_control)

This example shows a single `ros2_control` system that uses `dynamixel_hardware_interface` to read an IMU (ID 1) and publish its data through an `imu_sensor_broadcaster`. The robot description is built from `config/dynamixel_system.urdf.xacro`, which wraps the ros2_control configuration defined in `config/dynamixel_system.ros2_control.xacro`.

## Usage

Build and source your workspace, then launch:

```bash
ros2 launch dynamixel_hardware_interface_example_2 hardware.launch.py \
port_name:=/dev/ttyUSB0 \
baud_rate:=4000000
```

### Launch arguments
- `port_name` (default `/dev/ttyUSB0`): Serial port connected to the Dynamixel IMU.
- `baud_rate` (default `4000000`): Baud rate for the port.
- `description_file` (default `dynamixel_system.urdf.xacro`): Xacro to generate the robot description.
- `prefix` (default empty): Optional prefix for joint/frame names.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:macro name="dynamixel_system_ros2_control" params="name port_name baud_rate">
<ros2_control name="${name}" type="system">
<hardware>
<plugin>dynamixel_hardware_interface/DynamixelHardware</plugin>
<param name="port_name">${port_name}</param>
<param name="baud_rate">${baud_rate}</param>
<param name="dynamixel_model_folder">/param/dxl_model</param>
<param name="number_of_joints">0</param>
<param name="number_of_transmissions">0</param>
<param name="disable_torque_at_init">true</param>
<param name="error_timeout_ms">1000</param>
<param name="dynamixel_state_pub_msg_name">dynamixel_hardware_interface/dxl_state</param>
<param name="get_dynamixel_data_srv_name">dynamixel_hardware_interface/get_dxl_data</param>
<param name="set_dynamixel_data_srv_name">dynamixel_hardware_interface/set_dxl_data</param>
<param name="reboot_dxl_srv_name">dynamixel_hardware_interface/reboot_dxl</param>
<param name="set_dxl_torque_srv_name">dynamixel_hardware_interface/set_dxl_torque</param>
</hardware>

<sensor name="imu">
<state_interface name="linear_acceleration.x"/>
<state_interface name="linear_acceleration.y"/>
<state_interface name="linear_acceleration.z"/>
<state_interface name="angular_velocity.x"/>
<state_interface name="angular_velocity.y"/>
<state_interface name="angular_velocity.z"/>
<state_interface name="orientation.w"/>
<state_interface name="orientation.x"/>
<state_interface name="orientation.y"/>
<state_interface name="orientation.z"/>
</sensor>

<gpio name="imu">
<param name="type">sensor</param>
<param name="ID">1</param>
<state_interface name="linear_acceleration.x"/>
<state_interface name="linear_acceleration.y"/>
<state_interface name="linear_acceleration.z"/>
<state_interface name="angular_velocity.x"/>
<state_interface name="angular_velocity.y"/>
<state_interface name="angular_velocity.z"/>
<state_interface name="orientation.w"/>
<state_interface name="orientation.x"/>
<state_interface name="orientation.y"/>
<state_interface name="orientation.z"/>
<param name="Return Delay Time">0</param>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The parameter name Return Delay Time contains spaces, which is unconventional for ROS parameters. The standard convention is to use snake_case (e.g., return_delay_time). If the dynamixel_hardware_interface plugin supports it, please consider renaming this parameter for consistency and improved maintainability.

</gpio>
</ros2_control>
</xacro:macro>
</robot>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="dynamixel_system">
<xacro:arg name="prefix" default="" />
<xacro:arg name="baud_rate" default="4000000" />
<xacro:arg name="port_name" default="/dev/ttyUSB0" />
<xacro:include filename="dynamixel_system.ros2_control.xacro" />

<xacro:dynamixel_system_ros2_control name="dynamixel_system" port_name="$(arg port_name)" baud_rate="$(arg baud_rate)"/>

<link name="$(arg prefix)base_link"/>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

To resolve the missing imu_link TF frame required by ros2_controllers.yaml, you need to define the link and a joint connecting it to the robot's structure, for example, base_link.


  <link name="$(arg prefix)imu_link"/>

  <joint name="imu_joint" type="fixed">
    <parent link="$(arg prefix)base_link"/>
    <child link="$(arg prefix)imu_link"/>
    <origin xyz="0 0 0.1" rpy="0 0 0"/>
  </joint>

</robot>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**:
controller_manager:
ros__parameters:
update_rate: 500 # Hz

joint_state_broadcaster:
type: joint_state_broadcaster/JointStateBroadcaster

imu_sensor_broadcaster:
type: imu_sensor_broadcaster/IMUSensorBroadcaster

/**:
imu_sensor_broadcaster:
ros__parameters:
sensor_name: "imu"
frame_id: imu_link
Comment on lines +1 to +16

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This YAML file is invalid because the /**: key is duplicated. YAML does not allow duplicate keys at the same level, which will cause parsing errors. Please structure the parameters under their respective node and controller names.

controller_manager:
  ros__parameters:
    update_rate: 500  # Hz

    joint_state_broadcaster:
      type: joint_state_broadcaster/JointStateBroadcaster

    imu_sensor_broadcaster:
      type: imu_sensor_broadcaster/IMUSensorBroadcaster

imu_sensor_broadcaster:
  ros__parameters:
    sensor_name: "imu"
    frame_id: imu_link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The frame_id is set to imu_link, but this link is not defined in the dynamixel_system.urdf.xacro file. This will lead to TF (Transform) errors at runtime because the transform for imu_link will not be published. Please add the imu_link and a corresponding joint to your URDF.

Loading
Loading