Software System¶
Overview¶
The PI Plus software system is built on ROS2 and follows a modular, layered architecture. Each layer has a clearly defined responsibility, enabling flexibility, scalability, and safe control.
The system is composed of the following layers:
- Bringup Layer – System initialization and configuration loading (
hightorque_bringup) - Middleware Layer – Motor control abstraction and arbitration (
hightorque_midware) - Driver Layer – Hardware interfaces (motors, IMU, power, OLED, and related devices)
- Teleoperation Layer – Manual control via joystick input and input mapping
- Policy Runtime Layer – High-level control such as reinforcement learning policies, scripts, and onboard inference
The key design principle of the software system is:
The robot is never controlled directly at the motor level. All control flows through the middleware abstraction layer.
System Architecture¶
The PI Plus software stack can be understood as a layered runtime pipeline:
[ Teleoperation / Policy / Script ]
↓
/request_control
↓
/control_command
↓
hightorque_midware_node
↓
Motor Driver (CAN)
↓
Robot
Feedback:
Robot → /joint_states → Controller / Policy
In this structure:
- Higher-level modules do not communicate with motors directly
- All motion commands must be submitted through the middleware
- Robot state is published back to the upper layers through standard feedback topics
Teleoperation Pipeline¶
The teleoperation input chain is organized as follows:
joy_linux_node
↓
joy_input
↓
joy_mapper_node.py
↓
hightorque_joy
↓
/control_command
This pipeline separates raw controller input from robot-specific control semantics.
Core Components¶
1. hightorque_bringup¶
hightorque_bringup is the software entry point used to initialize the robot runtime environment.
Its responsibilities include:
- Constructing
robot_typedynamically from launch parameters - Resolving the correct configuration directory
- Loading robot configuration files
- Launching all required base runtime nodes
A typical startup command is:
ros2 launch hightorque_bringup pi_plus_rknn.launch.py
The launch system uses parameters such as:
model_typeleg_typelegarmclawheadwaist
These are combined into a robot_type, for example:
pi_plus-S-12L8A0G2H0W
The corresponding configuration directory is:
hightorque_bringup/config/robot_config/<robot_type>/
This directory usually contains:
robot_param.yamljoints.yamlcustom_action.yaml
2. hightorque_midware_node¶
hightorque_midware_node is the core control component of the software system.
It is responsible for:
- Abstracting low-level motor control
- Managing control ownership between multiple clients
- Accepting position, torque, and mixed control commands
- Converting upper-layer commands into motor-level instructions
- Publishing feedback and session state
This node provides the following core interfaces:
Services¶
/get_available_motors/request_control/release_control/reset_zero
Topics¶
/control_command/joint_states/session_status
This node is the central motor-control middleware of the robot. Controllers, test scripts, teleoperation tools, and policy runtimes all communicate with the robot through this node rather than operating motors directly.
3. Driver Nodes¶
The driver layer handles hardware interaction and state acquisition.
Typical nodes include:
humanoid_driver¶
- Motor driver layer
- Responsible for low-level communication with actuators
yesense_imu_node¶
- Reads IMU device data
- Publishes torso orientation, angular velocity, and acceleration
- Provides posture information required by balance control, state estimation, and policy control
power_node¶
- Handles power-related status management
- Reads and publishes battery or supply information
- Serves as the entry point for power monitoring and low-voltage warning behavior
hightorque_oled_node¶
- Drives the onboard OLED screen
- Displays local system information and runtime status
- Provides a direct hardware-level status display during field debugging
4. Teleoperation Components¶
The teleoperation layer is composed of several independent modules:
joy_linux_node¶
- Reads raw joystick input from
/dev/input/js0 - Publishes the raw joystick topic
- Remaps the default joystick topic to
joy_input
This node is responsible only for input collection and does not interpret the control semantics.
joy_mapper_node.py¶
- Subscribes to
joy_input - Converts raw Linux joystick values into the internal control representation
- Publishes
hightorque_joy
This module acts as the joystick protocol translation layer.
humanoid_driver¶
- Used for joystick filtering and related processing in the current stack
Control Model¶
Control Ownership Mechanism¶
Before sending control commands, a client must first request control ownership from the middleware.
The standard workflow is:
- Start
hightorque_midware_node - Call
/request_control - Receive a
uuid - Continuously publish commands to
/control_commandusing thatuuid - Release the control session through
/release_control
The middleware therefore enforces exclusive motor control through a session-based mechanism.
Request and Release Interfaces¶
Request Control¶
Control must be requested through:
/request_control
The returned result includes a session identifier:
uuid
This uuid must be attached to every subsequent command.
Release Control¶
When the control session is no longer needed, it must be explicitly released via:
/release_control
Control Modes¶
The middleware supports three control modes.
1. POSITION Mode¶
- Position-based control
- Positions must be provided
kpandkdare usedtorquesare ignored or treated as zero
This is the default and most commonly used control mode.
2. TORQUE Mode¶
- Torque-based control
torquesmust be providedpositions,kp, andkdare treated as zero
This mode is used for advanced control and policy-based motor output.
3. MIXED Mode¶
- Mixed position and torque control
- Each motor can be controlled independently as either a position-controlled motor or a torque-controlled motor
positions,torques,kp, andkdmust all match the length ofmotor_ids
This mode is useful for hybrid control designs.
Release and Timeout Behavior¶
When a session is released or a timeout occurs, the system can enter one of the following behaviors:
KEEP_MODE– Keep the previous commandDAMPING_MODE– Enter damping modeZERO_TORQUE_MODE– Apply zero torque
From a safety perspective, DAMPING_MODE is recommended during debugging and normal testing.
Zero Calibration¶
The middleware also provides a dedicated zero-calibration service:
/reset_zero
This service sets the current position of all motors as the zero position and writes the result into motor-side persistent storage.
Preconditions¶
Before calling /reset_zero:
hightorque_midware_nodemust be running- No active control session may exist
- All motors must be reachable and communicable
Important Notes¶
- During zero calibration, the motors enter zero-torque mode
- The robot must be placed on a zero-position fixture or a physically safe support structure
- The call is blocking and returns only after calibration is complete or fails
- The default timeout is 10000 ms
- Calibration is considered complete when all motor-reported absolute positions are within 0.1 rad
- Regardless of success or failure, the motor power should be restarted afterward
This mechanism is part of the software stack because it is implemented and managed through the middleware service interface rather than through a manual low-level motor procedure.
Configuration System¶
robot_param.yaml¶
robot_param.yaml contains robot hardware and device-level configuration.
It is mainly used by:
- Driver nodes
- Hardware-dependent runtime modules
- External peripherals
This file is more closely related to hardware connection and device setup.
joints.yaml¶
joints.yaml is the most important control-related configuration file in the software stack.
It is a joint control configuration table located under:
hightorque_bringup/config/robot_config/<robot_type>/joints.yaml
It defines:
name– Configuration namedofs– Number of degrees of freedomsupports_kinematics– Whether kinematics support is enabledmax_power– Maximum power limitmax_power_duration– Maximum duration for peak powerjoint_names– Joint name listmap_index– Mapping from logical joints to motor IDsdirection– Sign correction for each motorlower/upper– Joint limits in radianskp/kd– Default PD gainsurdf_offset– Offset between URDF zero and actual motor zero
How joints.yaml Is Used¶
During startup, hightorque_midware_node uses joints.yaml to:
- Build the mapping from joint names to motor IDs
- Read default
kpandkdvalues as fallback parameters for position control - Read
directionandurdf_offsetto align software coordinates with hardware coordinates - Read
lowerandupperto enforce command clamping
A useful mental model is:
robot_param.yamldefines device and hardware connectionjoints.yamldefines joint semantics and control behavior
custom_action.yaml¶
custom_action.yaml stores custom actions for specific robot configurations.
It is used when a particular mechanical configuration requires preset or special motion behavior that should be loaded together with the robot type.
Bringup Runtime Behavior¶
The bringup system can be understood as providing the base runtime environment of the whole robot.
Its responsibilities are:
- Resolve the correct robot configuration
- Start hardware-related base nodes
- Start the motor middleware (
hightorque_midware_node) - Start the joystick input chain
- Reserve the integration point for higher-level controllers or policy runtimes
Because of this, hightorque_bringup should not be seen as a single algorithm node. It is the startup center of the robot runtime.
Common Launch Parameters¶
The current launch system supports the following commonly used parameters:
robot_idmodel_typeleg_typelegarmclawheadwaistdefault_timeout_mspolicy_name
Namespace Behavior¶
- If
robot_idis empty, no namespace is added - If
robot_idis provided, all nodes are launched under:
robot_<robot_id>
This supports multi-robot deployment and avoids topic collisions.
Runtime Extension¶
The software stack supports higher-level control through policy runtimes and external execution modules.
Example: Instinct Onboard¶
A typical runtime sequence is:
# Start the base robot system
ros2 launch hightorque_bringup pi_plus_rknn.launch.py
# Move the robot to a safe zero posture
ros2 run hightorque_midware move_to_zero.py
# Activate the policy runtime
python scripts/piplus_parkour.py --logdir <policy_dir> --standdir <policy_dir>
In this workflow:
- The bringup layer initializes the robot runtime
- The middleware layer manages safe motor control
- The runtime layer performs policy execution and inference
This design allows the same robot software stack to support:
- Teleoperation
- Test scripts
- Learned policy deployment
- Future agent-based control frameworks
Developer Notes¶
Middleware-Centric Design¶
The software stack is built around a middleware-centered control design:
client → middleware → motor
This is the most important architectural property of the system.
It ensures:
- Safe control arbitration
- Uniform command semantics
- A stable abstraction layer between control logic and hardware execution
Decoupled System Design¶
The stack deliberately separates:
- Hardware drivers
- Control arbitration
- Input devices
- Higher-level control logic
This allows developers to modify controllers, teleoperation nodes, or learned policies without changing the motor driver implementation.
Extensibility¶
Developers can extend the system by:
- Writing custom ROS2 control nodes
- Integrating learned policies
- Modifying
joints.yamlfor new morphologies - Adding network-based or agent-based control interfaces
This makes the stack suitable not only for operation, but also for platform-level robotics development.
Summary¶
The PI Plus software system provides:
- A layered architecture
- Unified control through middleware abstraction
- Clear separation between bringup, control, drivers, and runtime logic
- Strong support for extension, policy deployment, and safe debugging
Its core value lies in turning the robot from a collection of hardware components into a controllable, extensible software platform.