Overview#
The system middleware adopts the ROS2 architecture and performs performance tuning for FastDDS. Based on the RT-Linux kernel, the process priority is configured, and the microsecond-level parallel solution algorithm and thread pool mechanism are utilized to ensure system real-time performance. This solution achieves 200Hz real-time control of 23 motors across four CAN buses, with the CAN bus load stably around 33% and extremely low packet loss rate. The system supports functions such as zero point setting, fault clearing, status information reading, and motion control, and is designed using the factory pattern, supporting the expansion of communication protocols and sensors.
Based on ONNX Runtime, it implements cross-platform model inference deployment, and uses a one-time loading and context switching mechanism to achieve dynamic switching of multi-strategy runtimes. The system supports reading action data in NPZ format, uses a lock-free structure to ensure real-time performance during the inference process, and supports joystick access and the /cmd_vel standard interface.
Open Source Address: RPO deployment repository
Deployment process (see README.md in the repository for details)#
Master Connection#
The deployment framework has been fully verified on Orange Pi 5 Plus and RDK X5 .
Orange Pi 5 Plus: The system is
Ubuntu 22.04, and the kernel version is5.10RDK X5: The system is
Ubuntu 22.04, and the kernel version is6.1.83
For the connection method and related information about the main controller, refer to Orange Pi 5 Plus Wiki and RDK X5 Doc.
Environment Configuration#
First, install ROS2 Humble, referring to the official ROS for installation.
Deployment also depends on
ccache,fmt,spdlog,eigen3,screenand other libraries. Execute commands in the master control to install them:
sudo apt update && sudo apt install -y ccache libfmt-dev libspdlog-dev libeigen3-dev screen- If you need to use the joystick for control, you also need to install the
joypackage of ROS2:
sudo apt install -y ros-humble-joy- If you need to use Python scripts in the repository (such as
scripts/set_zero.py), you also need to install the corresponding Python dependencies:
sudo apt install -y python3-yaml python3-numpy- Then pull the deployment code:
git clone https://github.com/Roboparty/atom01_deploy.git
cd atom01_deploy
git submodule update --init --recursive- If you are using Orange Pi 5 Plus, execute the following command to install the 5.10 real-time kernel : > Note: RDK X5 does not need to perform this step. Please directly flash the mirroring provided by us, which has the real-time kernel pre-installed.
cd assets
sudo apt install ./*.deb
cd ..- Next, grant the user the permission to set real-time priority:
sudo nano /etc/security/limits.confAdd the following two lines at the end of the file (make sure to replace orangepi with your actual username, for example, the default username of RDK X5 is sunrise):
# Allow user 'orangepi' to set real-time priorities
orangepi - rtprio 98
orangepi - memlock unlimitedRestart the device to make the configuration take effect, and then verify it through the following command:
ulimit -r> Hint: An output of 98 indicates successful configuration.
AP Configuration (Optional)#
To facilitate debugging without a network cable and monitor, you can enable a WiFi hotspot (AP) for the main control board. The configuration files are located in the tools/create_ap directory.
Note: Due to the limitation of a single network card, after enabling AP mode, the built-in WiFi of the main control board will have difficulty connecting to other external networks such as home routers.
- If you need to connect to the external network to load packages or environments , please connect the main control board to a wired network .
- If you want to temporarily resume wireless internet access , you can stop the service using the following command (requires an external monitor or network cable to log in):
sudo systemctl stop create_ap.service
- Execute in the project root directory to install and grant permissions:
sudo cp tools/create_ap/create_ap /usr/bin/
sudo chmod +x /usr/bin/create_ap- Deploy systemd service files:
sudo cp tools/create_ap/create_ap.service /etc/systemd/system/- Copy the configuration file according to your main control board: Orange Pi 5 Plus Please use this configuration:
sudo cp tools/create_ap/create_ap_orangepi.conf /etc/create_ap.confRDK X5 Please use this configuration:
sudo cp tools/create_ap/create_ap_sunrise.conf /etc/create_ap.conf> Description: Under the default configuration, the hotspot name (SSID) is atom, and the connection password (PASSPHRASE) is jujujuju. If you need to customize the hotspot name or password, you can edit the /etc/create_ap.conf file and modify the corresponding fields.
- Enable auto-start on boot and immediately start the hotspot:
sudo systemctl daemon-reload
sudo systemctl enable create_ap.service
sudo systemctl start create_ap.serviceHardware Configuration#
Before connecting, please complete the settings for the motor ID, IMU baud rate, and frequency.
For motor ID , please refer to the definition of motor ID in the product installation manual , and use the Damiao host computer tool for setting. For the usage tutorial, please refer to Damiao Technology Documentation .
For IMU, we default to using 921600 baud rate and 500HZ frequency . For how to modify it using the host computer, refer to HiPNUC Product Manual.
Hint: Other baud rates can also be used, but please ensure the frequency is greater than 200HZ. If using other baud rates, please synchronously modify the
IMU configuration in src/inference/config/robot.yaml.
Hardware Connection#
The default CAN mapping relationship for motor drive is as follows (numbered according to the order in which the USB-to-CAN is inserted into the main controller, with the first inserted being can0) :
can0corresponds to left legcan1corresponds to right leg plus waistcan2corresponds to left handcan3corresponds to right hand
Recommendation: Plug the USB to CAN into the USB 3.0 port of the main controller. If using a USB docking station, please also use a 3.0 port docking station and plug it into a 3.0 port; the IMU and joystick can be plugged into USB 2.0 ports. For details, please refer to the wiring instructions.
Method 1: Manual configuration (not recommended)#
If udev rules are not configured, you need to strictly follow the above order to insert the USB to CAN and manually configure the CAN and IMU serial ports after inserting the IMU:
# CAN Configuration
sudo ip link set canX up type can bitrate 1000000
sudo ip link set canX txqueuelen 1000
# canX includes can0, can1, can2, and can3, and the above two commands need to be entered once for each can.
# IMU Configuration
sudo chmod 666 /dev/ttyUSB0Method 2: Automatically bind using udev rules (recommended)#
Write udev rules to physically bind USB interfaces to corresponding devices, so thatthere is no need to insert devices in order. The example provides99-auto-up-devs-orangepi.rules and 99-auto-up-devs-sunrise.rules. If the wiring method is completely consistent with the wiring instructions, it can be used directly.
If the wiring is inconsistent, you need to modify the KERNELS item in the file to map it to the actually bound USB interface. Enter the following command on the main controller to monitor USB events:
sudo udevadm monitorWhen a device is plugged into a USB port, the terminal will display the KERNELS attribute item of that USB port, such as /devices/pci0000:00/0000:00:14.0/usb3/3-8 . When matching the KERNELS attribute item, simply use 3-8 . If it is a USB port on a dock attached to this USB port, 3-8.x will appear. In this case, use 3-8.x to match the USB port on the dock.
After writing is completed, execute the following in the project root directory:
# RDK X5 uses assets/99-auto-up-devs-sunrise.rules
sudo cp assets/99-auto-up-devs-orangepi.rules /etc/udev/rules.d/
sudo udevadm control --reload
sudo udevadm triggerRestarting the main controller will take effect.
This udev rule also includes IMU serial port configuration. If the rule takes effect properly, all CAN interfaces should be automatically configured and enabled, and you can enter the ip a command in the main controller to view the results.
Software Usage#
Motor Zero Calibration (when first used / zero point is lost)#
Description: Motor zero calibration usually only needs to be performed once during the first use; if the motor has been overhauled, replaced, or the zero point is lost, zero calibration also needs to be re-performed.
Two zero calibration methods are provided in the warehouse, suitable for different scenarios:
ros2 service call /set_zeros std_srvs/srv/TriggerUsed to write the current joint position to the motor zero point when the robot software has been started, the motor has been initialized, and inference is not running.python3 scripts/set_zero.pyIt is used for manual positioning and zero calibration of each motor, making it more suitable for scenarios such as initial installation, recalibration after maintenance, or when only partial motors need to be recalibrated.
When using the /set_zeros service, it is recommended to follow the following sequence of operations:
First source the ROS2 environment and workspace environment in the current terminal.
Run
./tools/start_robot.shto start the software.Call
/init_motorsto initialize the motors.Confirm that the robot is at the target zero position and is not currently running inference.
Call
/set_zerosto write the current zero point.
source /opt/ros/humble/setup.bash
source install/setup.bash
./tools/start_robot.sh
ros2 service call /init_motors std_srvs/srv/Trigger
ros2 service call /set_zeros std_srvs/srv/TriggerWhen using the script scripts/set_zero.py:
First, complete the workspace compilation and ensure that
install/setup.bashhas been generated.Source the ROS2 environment and workspace environment in the current terminal.
Confirm that the CAN interface and udev mapping have taken effect normally.
Check or modify as needed
scripts/config/set_zero.yaml, and confirm that the motor ID, CAN interface, and motor model are consistent with the actual hardware.After running the script in the interactive terminal, manually move the current motor to the zero position as prompted.
Press
Enterto write the zero point of this motor, press Space to skip the current motor.
colcon build --symlink-install
source /opt/ros/humble/setup.bash
source install/setup.bash
python3 scripts/set_zero.pyscripts/set_zero.py will calibrate each motor in the order specified in scripts/config/set_zero.yaml, and switch the motors to damping mode during the calibration process to facilitate manual adjustment of the attitude.
Launch the software#
Warning: Before starting the robot, ensure that the robot has completed zero calibration,please be sure to read the Safety Operation Manual !
In addition, please pay special attention to the zero offset configuration in src/inference/config/robot.yaml:
motor_zero_offset:
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.093,
0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0]If the waist yaw is turned to the limit block for calibration: keep
2.093.If using a printed part to fix the waist yaw for calibration: change
2.093to0.0.
After everything is ready, run the script to start the software:
./tools/start_robot.sh./tools/start_robot.sh will automatically execute colcon build --symlink-install to compile the workspace and start the following two screen sessions in the background:
inference_session: Inference Nodejoy_session: Handle Node
You can use the following command to view the background output:
screen -r inference_session
screen -r joy_sessionYou can use the following command to stop the corresponding background component:
screen -S inference_session -X quit
screen -S joy_session -X quitIf you need to switch between different strategy models, you can first modify the configuration file loaded in src/inference/launch/inference.launch.py:
configs = [
os.path.join(
get_package_share_directory("inference"),
"config",
"inference.yaml",
),
]Simply replace the inference.yaml with the target configuration file name, for example:
inference_amp.yamlinference_attn_enc.yamlinference_beyondmimic.yamlinference_getup.yamlinference_interrupt.yaml
After the modification is completed, re-run ./tools/start_robot.sh , and the corresponding configuration will be loaded during startup, thus using different strategies.
Handle Control#
X Key: Enable / Disable Motor
Key A: Reset Motor
Key B: Start / Pause Inference
Y Key: Switch between joystick control / cmd_vel command control
LB Key: Switch strategy mode (available in beyondmimic / interrupt mode)
RB Key: Switch motion sequence (available in beyondmimic mode)
Right Joystick: Controls forward, backward, left, and right movement
LT/RT: Control steering (left/right rotation)
Service Interface#
ROS2 services can be invoked via the command line to control the robot:
- Initialize the motor:
ros2 service call /init_motors std_srvs/srv/Trigger- Deinitialize the motor:
ros2 service call /deinit_motors std_srvs/srv/Trigger- Start reasoning:
ros2 service call /start_inference std_srvs/srv/Trigger- Stop Inference:
ros2 service call /stop_inference std_srvs/srv/Trigger- Clear Error:
ros2 service call /clear_errors std_srvs/srv/Trigger- Set Zero Point:
ros2 service call /set_zeros std_srvs/srv/TriggerThis service will write the current posture of the robot to the motor zero point. Before calling, please ensure that the current terminal has sourced the ROS2 and workspace environments, the motor has been initialized, the robot has been positioned at the target zero position, and no inference is currently running.
- Reset Joint:
ros2 service call /reset_joints std_srvs/srv/Trigger- Refresh Joint Status:
ros2 service call /refresh_joints std_srvs/srv/Trigger- Read joint state:
ros2 service call /read_joints std_srvs/srv/Trigger- Read IMU Status:
ros2 service call /read_imu std_srvs/srv/TriggerPython SDK#
This repository provides a Python SDK to facilitate users in controlling hardware using Python scripts.
Note:
imu_py,motors_py,robot_pythese three modules come from the workspace compilation products. Before running any Python SDK examples or scripts, please first complete the workspace compilation, and source the ROS2 environment and theinstall/setup.bashof this workspace.
colcon build --symlink-install
source /opt/ros/humble/setup.bash
source install/setup.bashHint: For detailed Python script examples, please refer to the
scripts/directory.
1. IMU SDK ( imu_py )#
Static Method
create_imu(imu_id: int, interface_type: str, interface: str, imu_type: str, baudrate: int = 0) -> IMUDriver: Create an IMU driver instance。
Member Method
get_imu_id() -> int: Get the IMU ID.get_ang_vel() -> List[float]: Get the angular velocity [x, y, z].get_quat() -> List[float]: Get the quaternion [w, x, y, z].get_lin_acc() -> List[float]: Get the linear acceleration [x, y, z].get_temperature() -> float: Get the temperature.
Usage Example
import imu_py
imu = imu_py.IMUDriver.create_imu(8, "serial", "/dev/ttyUSB0", "HIPNUC", 921600)
quat = imu.get_quat()2. Motor SDK ( motors_py )#
provides MotorControlMode enumeration: NONE , MIT , POS , SPD .
Static Method
create_motor(motor_id: int, interface_type: str, interface: str, motor_type: str, motor_model: int, master_id_offset: int = 0, motor_zero_offset: double = 0.0) -> MotorDriver: Create a motor drive instance。
Member Method
init_motor(): Initialize the motor.deinit_motor(): Deinitialize the motor.set_motor_control_mode(mode: MotorControlMode): Sets the control mode.motor_mit_cmd(pos: float, vel: float, kp: float, kd: float, torque: float): MIT mode control command.motor_pos_cmd(pos: float, spd: float, ignore_limit: bool = False): Position mode control command.motor_spd_cmd(spd: float): Speed mode control command.lock_motor() / unlock_motor(): Lock/Unlock the motor.set_motor_zero(): Sets the current position as the zero point.clear_motor_error(): Clears errors.get_motor_pos() -> float: Get position (rad).get_motor_spd() -> float: Get speed (rad/s).get_motor_current() -> float: Get current (A).get_motor_temperature() -> float: Get temperature (°C).get_error_id() -> int: Get the error code.get_motor_id() -> int: Get the motor ID.get_motor_control_mode() -> int: Get the control mode.get_response_count() -> int: Get the response count.refresh_motor_status(): Refresh motor status.
Usage Example
import motors_py
motor = motors_py.MotorDriver.create_motor(1, "can", "can0", "DM", 0, 16)
motor.init_motor()
motor.set_motor_control_mode(motors_py.MotorControlMode.MIT)
motor.motor_mit_cmd(0.0, 0.0, 5.0, 1.0, 0.0)3. Robot SDK ( robot_py )#
RobotInterface class is used to uniformly control the entire robot, reading the configuration file to automatically load motors and IMUs.
constructor function
RobotInterface(config_file: str): Creates an instance based on the configuration file path.
Member Method
init_motors(): Initialize all motors.deinit_motors(): Deinitialize all motors.reset_joints(joint_default_angle: List[float]): Reset all joints to their default angles.apply_action(action: List[float]): Apply control actions (joint target positions/torques, etc., depending on the internal implementation).refresh_joints(): Refresh the status of all joints.set_zeros(): Sets all current joint positions to zero.clear_errors(): Clears all motor errors.get_joint_q() -> List[float]: Get all joint positions.get_joint_vel() -> List[float]: Get the velocities of all joints.get_joint_tau() -> List[float]: Get all joint torques.get_quat() -> List[float]: Get IMU quaternion [w, x, y, z]。get_ang_vel() -> List[float]: Get the angular velocity of the IMU.
Attribute
is_init: (Read-only) Whether the robot has been initialized.
Usage Example
import robot_py
robot = robot_py.RobotInterface("config/robot.yaml")
robot.init_motors()
robot.apply_action([0.0] * 23)