ROBROS

Human First,

line

Always

Dev Center

Last Updated On: 2026-07-10

ControlMode

This page reorganizes the former "Low Level Control" page into Control Mode, summarizing the meaning and switching methods of each control mode supported by IGRIS-C, as well as the message interfaces required for low-level control.

  • IGRIS-C's behavior hierarchy is switched via Control Mode. Mode-switch commands are sent to the controller through the SDK's IgrisC_Client::SendControlModeCommand() (internally a ControlModeCommandRequest Request/Response), and the controller maps this to an internal RobotControlMode to change the control loop's behavior.

struct ControlModeCommandRequest {
  Header                  header;
  string                  request_id;    // ID for matching requests
  ControlModeCommandType  command_type;  // Mode to switch to (see list below)
  string                  preset_id;     // MOTION_PRESET only
  boolean                 is_cyclic;     // MOTION_PRESET_CYCLIC_TOGGLE only
};
// Response: ServiceResponse { request_id, success, message, error_code(0=success) }

1. List of Control Modes

ControlModeCommandType (19 types total, values 0–18). Controller behavior is based on robotHandler dispatch.

#

command_type

Controller mapping/behavior

Layer

0

MOTION_PRESET

startMotionPreset(preset_id)

High-Level

1

MOTION_PRESET_CYCLIC_TOGGLE

setMotionPresetCyclic(is_cyclic)

High-Level

2

JOINT_POSITION_HOLD

→ JOINT_HOLD_MODE

-

3

MOTION_STOP

holdCurrentPosition()

High-Level

4

WALKMODE_ON

→ WALK_MODE

-

5

LOW_LEVEL_JOINT_CONTROL

→ LOW_LEVEL_MODE

Low-Level

6

LOW_LEVEL_WALKMODE_ON

→ LOW_LEVEL_WALK_MODE

Low-Level

7

HIGH_LEVEL_WALKMODE_ON

→ HIGH_LEVEL_WALK_MODE

High-Level

8

HIGH_LEVEL_JOINT_CONTROL

→ HIGH_LEVEL_MODE

High-Level

9–18

CUSTOM_MODE_1 – CUSTOM_MODE_10

(internal use only)

Not provided

command_type values follow the format igris_c::msg::dds::ControlModeCommandType::CONTROL_MODE_CMD_<NAME> (e.g., CONTROL_MODE_CMD_MOTION_PRESET).

⚠️ CUSTOM_MODE_1–CUSTOM_MODE_10 (9–18) are not currently provided to users. These are internal/extension-only entries with reserved slots in the enum only — do not use them when working with the SDK.

2. Description of Each Mode

Low-Level Control

The SDK directly commands each motor's targets (q·dq·tau·kp·kd) via rt/lowcmd. In this mode, control loop responsibility resides externally (with the SDK). (See c.5 for the message interface.)

  • LOW_LEVEL_JOINT_CONTROL (5) — LOW_LEVEL_MODE. Direct joint control via SDK LowCmd.

  • LOW_LEVEL_WALKMODE_ON (6) — LOW_LEVEL_WALK_MODE. Walking mode based on low-level control.

High-Level Control

The controller's built-in logic receives higher-level commands and generates/maintains motion. Motion preset execution is only possible at this layer.

  • HIGH_LEVEL_JOINT_CONTROL (8) — HIGH_LEVEL_MODE. Controller's high-level joint control.

  • HIGH_LEVEL_WALKMODE_ON (7) — HIGH_LEVEL_WALK_MODE. High-level walking mode.

Walk

  • WALKMODE_ON (4) — WALK_MODE. Enters walking mode.

Motion Preset

  • MOTION_PRESET (0) — Plays back a predefined motion specified by preset_id (startMotionPreset). Can only be started from HIGH_LEVEL_MODE or HIGH_LEVEL_WALK_MODE (rejected in other modes). Populate the preset_id argument in the request.

  • MOTION_PRESET_CYCLIC_TOGGLE (1) — Toggles whether the preset repeats cyclically (setMotionPresetCyclic). Uses the is_cyclic argument in the request.

Stop / Hold

  • JOINT_POSITION_HOLD (2) — JOINT_HOLD_MODE. Maintains (holds) the current joint positions.

  • MOTION_STOP (3) — Stops the ongoing motion and maintains the current posture (holdCurrentPosition). Only supported from HIGH_LEVEL_MODE/HIGH_LEVEL_WALK_MODE.

Custom — Currently Not Provided

  • CUSTOM_MODE_1–CUSTOM_MODE_10 (9–18) — Internal/extension-only slots not currently provided to users. These are defined in the enum but are not modes callable by SDK users, so do not use them in normal control.

3. Mode Switching API (SDK)

Mode switching is performed via the single method IgrisC_Client::SendControlModeCommand().

ServiceResponse SendControlModeCommand(
    ControlModeCommandType command_type,
    const std::string&     preset_id = "",     // MOTION_PRESET only
    bool                   is_cyclic = false,  // MOTION_PRESET_CYCLIC_TOGGLE only
    int                    timeout_ms = 5000);

Usage example (based on examples/cyclonedds/cyclonedds_service.cpp):

using igris_c::msg::dds::ControlModeCommandType;

// Execute motion preset "HOME" (at the HIGH_LEVEL layer)
res = client.SendControlModeCommand(
    ControlModeCommandType::CONTROL_MODE_CMD_MOTION_PRESET, "HOME", false, 60000);

// Hold current position
res = client.SendControlModeCommand(
    ControlModeCommandType::CONTROL_MODE_CMD_JOINT_POSITION_HOLD, "", false, 60000);

// Stop ongoing motion
res = client.SendControlModeCommand(
    ControlModeCommandType::CONTROL_MODE_CMD_MOTION_STOP, "", false, 60000);

// Switch to low-level joint control mode (use rt/lowcmd afterward)
res = client.SendControlModeCommand(
    ControlModeCommandType::CONTROL_MODE_CMD_LOW_LEVEL_JOINT_CONTROL, "", false, 60000);

Check the result via the returned ServiceResponse's success / error_code (0=success) / message.

4. Service Topics Summary

Request/Response service channels used by the SDK client:

Function

Service Topic

SDK Method

BMS/motor initialization

rt/service/bms_init

InitBms()

Torque ON/OFF

rt/service/torque

SetTorque()

Hand initialization

rt/service/hand_init

InitHand()

Control mode switching

rt/service/control_mode

SendControlModeCommand()

Mujoco simulation control (sim only)

rt/service/mujoco_sim

SendMujocoSimCmd()

Each service operates as a pair: <topic>/request (publishes the request) · <topic>/response (subscribes to the response). Example: rt/service/bms_init/request · rt/service/bms_init/response. (The table above shows the base topic.)

Low-level streams: rt/lowcmd (LowCmd, commands) / rt/lowstate (LowState, status).

5. Low-Level Control Message Interface

IGRIS-C Topic List

  • Low-level Cmd & State (high frequency): rt/lowcmd / rt/lowstate

  • Service State (low frequency)

Common (igris_c::msg::dds)

const uint32 N_JOINTS = 31; // Fixed DOF Num

// Kinematic Space (MS=Motor Space/AB, PJS=Parallel Joint Space/PR)
enum KinematicMode { MS, PJS };

// Motor control is HYBRID mode only. (The former MotorMode { CURRENT, HYBRID } enum has been removed.)

Command Side

struct MotorCmd {            // HYBRID only
  uint16 id;   // MS: motor index / PJS: virtual joint index
  float  q;    // Position (rad)
  float  dq;   // Velocity (rad/s)
  float  tau;  // Feedforward Torque (Nm)
  float  kp;   // kP
  float  kd;   // kD
};

struct LowCmd {
  Header        header;
  KinematicMode kinematic_modes[5];  // Per parallel-link group: waist / L_ankle / R_ankle / L_wrist / R_wrist
  MotorCmd      motors[31];          // Fixed length, 31 DOF
};
// Usage example: set all groups to the same mode
cmd.kinematic_modes().fill(KinematicMode::PJS);

State Side

struct IMUState {
  float quaternion[4];     // w, x, y, z
  float gyroscope[3];      // rad/s
  float accelerometer[3];  // m/s^2
  float rpy[3];            // rad (intrinsic ZYX)
};

struct MotorState {
  float  q;             // Position (rad)
  float  dq;            // Velocity (rad/s)
  float  tau_est;       // Estimated Torque (Nm)
  int16  temperature;   // Motor Temperature (°C)
  uint32 status_bits;   // Status Bits (fault/limit, see separate document)
};

struct JointState {
  float  q;            // PJS Position (rad)
  float  dq;           // PJS Velocity (rad/s)
  float  tau_est;      // PJS Estimated Torque (Nm)
  uint32 status_bits;  // Status Bits
};

struct LowState {
  Header     header;
  IMUState   imu_state;               // Base IMU state
  MotorState motor_state[N_JOINTS];   // MS raw state
  JointState joint_state[N_JOINTS];   // PJS derived state
};

All types are defined in the igris_c::msg::dds namespace (the IDL's module). In actual use, reference them as igris_c::msg::dds::TypeName.

6. System & Mode Control API (Initialization / Torque / Hand)

#include <igris_c_sdk/channel_factory.hpp>
#include <igris_c_sdk/igris_c_client.hpp>
using namespace igris_c_sdk;
using namespace igris_c::msg::dds;

int main() {
    int domain_id = 0;
    ChannelFactory::Instance()->Init(domain_id, "igris_c_IG01");  // domain + robot unit namespace (see b.3)
    if (!ChannelFactory::Instance()->IsInitialized()) { return 1; }

    IgrisC_Client client;
    client.Init();
    client.SetTimeout(10.0f);  // 10-second timeout
    // ... subsequent service calls
}

BMS / Motor Initialization

ServiceResponse res = client.InitBms(BmsInitType::BMS_INIT, 30000);           // BMS power ON
res = client.InitBms(BmsInitType::MOTOR_INIT, 30000);                         // Motor initialization only
res = client.InitBms(BmsInitType::BMS_AND_MOTOR_INIT, 30000);                 // Power ON + motor (full sequence)
res = client.InitBms(BmsInitType::BMS_INIT_NONE, 30000);                      // BMS power OFF
  • init_type (BmsInitType) — Values actually handled by the bridge:

    • BMS_INIT_NONE (0) — BMS power OFF (setBmsPowerAsync(false))

    • BMS_INIT (1) — BMS power ON

    • MOTOR_INIT (2) — Motor initialization

    • BMS_AND_MOTOR_INIT (3) — Power ON + motor initialization (full sequence)

    • BMS_OFF (4) — Defined in the enum but currently unhandled by the bridge (error_code -2) → do not use

  • timeout_ms — Timeout in ms (default 5000)

  • Returned ServiceResponse — request_id, success, message, error_code (0=success)

Torque Control

ServiceResponse res = client.SetTorque(TorqueType::TORQUE_ON, 30000);
res = client.SetTorque(TorqueType::TORQUE_OFF, 30000);
  • torque (TorqueType) — TORQUE_NONE(0, reserved) / TORQUE_ON(1) / TORQUE_OFF(2)

  • timeout_ms — Timeout in ms (default 5000)

Hand Initialization

ServiceResponse res = client.InitHand(30000);   // End-effector calibration/homing

(For detailed hand control, see the e. Hand page)

BMS Status Query (rt/bmsstate, low frequency)

tick, body_power(RELAY_OFF/ON), legs_power, estop, connect, battery(voltage), bms_init_state

7. Python Binding

Installing the dist/*.whl from the igris_c_sdk_public repository into a Python environment allows usage with the same getter/setter pattern as C++. Examples are located in the examples/python folder.

import igris_c_sdk as igc_sdk

channel_instance = igc_sdk.ChannelFactory.Instance()
channel_instance.Init(0, "igris_c_IG01")   # domain_id + robot unit namespace (see b.3)

client = igc_sdk.IgrisC_Client()
client.Init()
client.SetTimeout(20.0)

Real-time lowstate Subscription

lowstate_subscriber = igc_sdk.LowStateSubscriber("rt/lowstate", igc_sdk.QosProfile.SensorData())

def lowstate_callback(msg):
    imu = msg.imu_state()
    q   = imu.quaternion(); gyro = imu.gyroscope(); acc = imu.accelerometer(); rpy = imu.rpy()
    m0  = msg.motor_state()[0]
    print(m0.q(), m0.dq(), m0.tau_est(), m0.temperature(), m0.status_bits())

lowstate_subscriber.init(lowstate_callback)

Service Calls (init / torque / control mode)

# BMS / Motor
client.InitBms(igc_sdk.BmsInitType.BMS_INIT, 5000)
client.InitBms(igc_sdk.BmsInitType.BMS_AND_MOTOR_INIT, 5000)

# Torque
client.SetTorque(igc_sdk.TorqueType.TORQUE_ON, 5000)

# Control mode (same as C++ SendControlModeCommand)
client.SendControlModeCommand(
    igc_sdk.ControlModeCommandType.CONTROL_MODE_CMD_MOTION_PRESET, "HOME", False, 60000)
client.SendControlModeCommand(
    igc_sdk.ControlModeCommandType.CONTROL_MODE_CMD_JOINT_POSITION_HOLD, "", False, 60000)

# Hand
client.InitHand(5000)

Sending LowCmd (e.g., controlling neck yaw/pitch motors)

lowcmd_publisher = igc_sdk.LowCmdPublisher("rt/lowcmd", igc_sdk.QosProfile.SensorData())
lowcmd_publisher.init()

low_cmd_msg = igc_sdk.LowCmd()
for i in range(0, 31):
    motor_cmd = low_cmd_msg.motors()[i]
    motor_cmd.id(i); motor_cmd.q(0.0); motor_cmd.dq(0.0); motor_cmd.tau(0.0)  # defaults
    if i == 30:          # Neck Pitch
        motor_cmd.q(0.3); motor_cmd.kp(5); motor_cmd.kd(0.1)
    elif i == 29:
        motor_cmd.kp(2);  motor_cmd.kd(0.05)
    else:
        motor_cmd.kp(0.0); motor_cmd.kd(0.0)

# kinematic_modes is a 5-element array by parallel-link group (waist/L_ankle/R_ankle/L_wrist/R_wrist).
# (C++ example: cmd.kinematic_modes().fill(KinematicMode.PJS))
lowcmd_publisher.write(low_cmd_msg)

The full example can be found in the GitHub repository.