Skip to content

Latest commit

 

History

History
364 lines (288 loc) · 11.9 KB

File metadata and controls

364 lines (288 loc) · 11.9 KB

Cyclo Control

This repository provides control packages for the ROBOTIS Physical AI lineup.

Repository Structure

├── cyclo_motion_controller/
│   ├── CMakeLists.txt
│   └── package.xml
├── cyclo_motion_controller_core/
│   ├── include/cyclo_motion_controller_core/
│   │   ├── common/
│   │   │   └── ...
│   │   ├── controllers/
│   │   │   └── ...
│   │   ├── kinematics/
│   │   │   └── ...
│   │   └── optimization/
│   │       └── ...
│   ├── src/
│   │   ├── controllers/
│   │   │   └── ...
│   │   ├── kinematics/
│   │   │   └── ...
│   │   └── retargeting/
│   │       └── ...
│   ├── CMakeLists.txt
│   └── package.xml
├── cyclo_motion_controller_ros/
│   ├── config/
│   │   └── ...
│   ├── include/cyclo_motion_controller_ros/
│   │   ├── nodes/
│   │   │   └── ...
│   │   └── utils/
│   │       └── ...
│   ├── launch/
│   │   └── ...
│   ├── src/
│   │   ├── nodes/
│   │   │   └── ...
│   │   └── utils/
│   │       └── ...
│   ├── CMakeLists.txt
│   └── package.xml
├── cyclo_motion_controller_ros_py/
│   ├── resource/
│   │   └── ...
│   ├── scripts/
│   │   └── ...
│   ├── package.xml
│   ├── setup.cfg
│   └── setup.py
├── cyclo_motion_controller_models/
│   ├── launch/
│   │   └── ...
│   ├── models/
│   │   └── ...
│   ├── CMakeLists.txt
│   └── package.xml
└── osqp_eigen_vendor/
    ├── cmake/
    ├── third_party/
    │   └── osqp-eigen/
    ├── CMakeLists.txt
    ├── THIRD_PARTY_NOTICES.md
    └── package.xml

Directory Description

cyclo_motion_controller/

  • Meta package containing package related to motion control.

cyclo_motion_controller_core/

  • Core package containing kinematics solver, controllers, and retargeting utilities.
  • include/cyclo_motion_controller_core/common/: Shared types and utility functions.
  • include/cyclo_motion_controller_core/optimization/: QP definitions and solver interfaces.
  • src/controllers/: Controller implementations for AI Worker and OpenManipulator.
  • src/kinematics/: Kinematics solver implementation.
  • src/retargeting/: Python retargeting utilities.

cyclo_motion_controller_ros/

  • ROS 2 package containing controller nodes, launch files, and runtime configs.
  • config/: YAML configuration files for AI Worker, OMX, and OMY controllers.
  • launch/: Launch files for running the controller nodes.
  • src/nodes/: ROS 2 node executables organized by robot family.
  • src/utils/: Utility nodes such as interactive markers and reference checking.

cyclo_motion_controller_ros_py/

  • ROS 2 Python package containing retargeting-related scripts and tests.
  • scripts/: Python entrypoints.

cyclo_motion_controller_models/

  • Robot model descriptions and RViz resources package.
  • launch/: Launch files for visualizing robot models.
  • models/: URDF/SRDF robot models used by the controller.

osqp_eigen_vendor/

  • Vendor package that wraps the upstream osqp-eigen source tree for this repository.
  • third_party/osqp-eigen/: Vendored upstream source.

Install (from source)

Prerequisites

  • ROS 2 Jazzy installed
  • vcs is used to import workspace dependencies, and rosdep is used to install system dependencies
  • numpy<2 is required

Build in a ROS 2 workspace

Clone the repository and import workspace dependencies:

cd ~/ros2_ws/src
git clone https://github.com/ROBOTIS-GIT/cyclo_control.git
vcs import . < cyclo_control/cyclo_control_ci.repos

Install dependencies via rosdep, then build:

cd ~/ros2_ws
sudo apt update
rosdep install --from-paths src --ignore-src -r -y --rosdistro jazzy
colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=Release
source install/setup.bash

Run

AI Worker Controllers

Launch AI Worker controllers:

ros2 launch cyclo_motion_controller_ros ai_worker_controller.launch.py

You can switch AI Worker controllers via controller_type:

  • default launch runs ai_worker_movel_controller_node
  • controller_type:=movel runs ai_worker_movel_controller_node
  • controller_type:=movej runs ai_worker_movej_controller_node
  • controller_type:=vr runs vr_controller_node and reference_checker_node; when hand:=true, it also runs retargeting_teleop
  • controller_type:=leader runs leader_controller_node together with vr_controller_node

In vr mode, arm retargeting is enabled by default (arm:=true) and starts arm_retargeting_teleop to map tracked arm motion into follower arm commands.

Example launch commands:

ros2 launch cyclo_motion_controller_ros ai_worker_controller.launch.py controller_type:=movel start_interactive_marker:=true
ros2 launch cyclo_motion_controller_ros ai_worker_controller.launch.py controller_type:=movej
ros2 launch cyclo_motion_controller_ros ai_worker_controller.launch.py controller_type:=vr
ros2 launch cyclo_motion_controller_ros ai_worker_controller.launch.py controller_type:=vr hand:=true
ros2 launch cyclo_motion_controller_ros ai_worker_controller.launch.py controller_type:=vr arm:=false
ros2 launch cyclo_motion_controller_ros ai_worker_controller.launch.py controller_type:=leader
ros2 launch cyclo_motion_controller_ros ai_worker_controller.launch.py disable_gripper_collisions:=true

When controller_type:=movel and start_interactive_marker:=true, ai_worker_controller.launch.py starts two configurable interactive markers:

  • right marker uses right_controlled_link and publishes MoveL commands to right_movel_topic
  • left marker uses left_controlled_link and publishes MoveL commands to left_movel_topic

To disable collision checking only between the two grippers, set disable_gripper_collisions:=true. This helps maintain smooth handover-style motions when the grippers come into contact.

In vr mode, the hand launch argument enables hand teleoperation through the retargeting algorithm. It defaults to false. The arm launch argument controls arm retargeting in vr mode and defaults to true.

Example movel commands:

ros2 topic pub --once /r_goal_move robotis_interfaces/msg/MoveL "{
  pose: {
    header: {frame_id: 'base_link'},
    pose: {
      position: {x: 0.35, y: -0.20, z: 0.85},
      orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}
    }
  },
  time_from_start: {sec: 2, nanosec: 0}
}"
ros2 topic pub --once /l_goal_move robotis_interfaces/msg/MoveL "{
  pose: {
    header: {frame_id: 'base_link'},
    pose: {
      position: {x: 0.35, y: 0.20, z: 0.85},
      orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}
    }
  },
  time_from_start: {sec: 2, nanosec: 0}
}"

Example movej input commands:

ros2 topic pub --once /leader/joint_trajectory_command_broadcaster_right/raw_joint_trajectory trajectory_msgs/msg/JointTrajectory "{
  joint_names: ['arm_r_joint1', 'arm_r_joint2', 'arm_r_joint3', 'arm_r_joint4', 'arm_r_joint5', 'arm_r_joint6', 'arm_r_joint7', 'gripper_r_joint1'],
  points: [
    {
      positions: [0.3, -0.2, 0.1, 0.0, 0.2, -0.1, 0.0, 0.02],
      time_from_start: {sec: 3, nanosec: 0}
    }
  ]
}"
ros2 topic pub --once /leader/joint_trajectory_command_broadcaster_left/raw_joint_trajectory trajectory_msgs/msg/JointTrajectory "{
  joint_names: ['arm_l_joint1', 'arm_l_joint2', 'arm_l_joint3', 'arm_l_joint4', 'arm_l_joint5', 'arm_l_joint6', 'arm_l_joint7', 'gripper_l_joint1'],
  points: [
    {
      positions: [-0.3, 0.2, -0.1, 0.0, -0.2, 0.1, 0.0, 0.02],
      time_from_start: {sec: 3, nanosec: 0}
    }
  ]
}"

ai_worker_movej_controller subscribes to the raw trajectory topics and republishes filtered trajectories while preserving gripper values from the input message.

OMX Controllers

Launch the OMX follower controller:

ros2 launch cyclo_motion_controller_ros omx_controller.launch.py start_interactive_marker:=true

You can switch OMX controllers via controller_type:

  • default launch runs omx_movel_controller_node
  • controller_type:=movej runs omx_movej_controller_node
  • controller_type:=movel runs omx_movel_controller_node

When controller_type:=movel and start_interactive_marker:=true, omx_controller.launch.py starts one configurable interactive marker that publishes to marker_goal_topic.

Example movel command:

ros2 topic pub --once /omx_movel_controller/movel robotis_interfaces/msg/MoveL "{
  pose: {
    pose: {
      position: {x: 0.20, y: 0.00, z: 0.18},
      orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}
    }
  },
  time_from_start: {sec: 3, nanosec: 0}
}"

movel interpolation duration is supplied per command via time_from_start.

Example movej command:

ros2 topic pub --once /omx_movej_controller/movej trajectory_msgs/msg/JointTrajectory "{
  joint_names: ['joint1', 'joint2', 'joint3', 'joint4', 'joint5', 'gripper_joint_1'],
  points: [
    {
      positions: [0.0, -0.5, 0.8, 0.0, 0.3, 0.02],
      time_from_start: {sec: 3, nanosec: 0}
    }
  ]
}"

omx_movej_controller_node republishes a patched copy of the input movej message, so gripper commands included in the input remain in the published trajectory.

OMY Controllers

Launch the OMY follower controller:

ros2 launch cyclo_motion_controller_ros omy_controller.launch.py start_interactive_marker:=true

You can switch OMY controllers via controller_type:

  • default launch runs omy_movel_controller_node
  • controller_type:=movej runs omy_movej_controller_node
  • controller_type:=movel runs omy_movel_controller_node

When controller_type:=movel and start_interactive_marker:=true, omy_controller.launch.py starts one configurable interactive marker that publishes to marker_goal_topic.

Example movel command:

ros2 topic pub --once /omy_movel_controller/movel robotis_interfaces/msg/MoveL "{
  pose: {
    pose: {
      position: {x: 0.30, y: -0.20, z: 0.5},
      orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}
    }
  },
  time_from_start: {sec: 3, nanosec: 0}
}"

movel interpolation duration is supplied per command via time_from_start.

Example movej command:

ros2 topic pub --once /omy_movej_controller/movej trajectory_msgs/msg/JointTrajectory "{
  joint_names: ['joint1', 'joint2', 'joint3', 'joint4', 'joint5', 'joint6', 'rh_r1_joint'],
  points: [
    {
      positions: [0.0, -0.5, 0.8, 0.0, 0.3, 0.0, 1.0],
      time_from_start: {sec: 3, nanosec: 0}
    }
  ]
}"

omy_movej_controller_node also republishes a patched copy of the input movej message, preserving gripper values when the gripper joint is included in the input.

Model Visualization

You can visualize the robot models used by the controllers with the launch files below.

Examples:

ros2 launch cyclo_motion_controller_models view_ffw_sg2_follower.launch.py
ros2 launch cyclo_motion_controller_models view_omx_f.launch.py
ros2 launch cyclo_motion_controller_models view_omy_f3m.launch.py

Acknowledgements

This repository builds on several excellent open-source projects. The core motion controller implementations are derived from and informed by dyros_robot_controller, a project researched at Seoul National University. The retargeting modules in this repository are derived from and informed by dex-retargeting. The robot kinematics used throughout the controller stack are based on pinocchio, and the optimization layer uses osqp-eigen for the Eigen-based OSQP solver interface.