Dev Center
Dev Center
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 aControlModeCommandRequestRequest/Response), and the controller maps this to an internalRobotControlModeto 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 |
|
| High-Level |
1 |
|
| High-Level |
2 |
| → | - |
3 |
|
| High-Level |
4 |
| → | - |
5 |
| → | Low-Level |
6 |
| → | Low-Level |
7 |
| → | High-Level |
8 |
| → | High-Level |
9–18 |
| (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 bypreset_id(startMotionPreset). Can only be started fromHIGH_LEVEL_MODEorHIGH_LEVEL_WALK_MODE(rejected in other modes). Populate thepreset_idargument in the request.MOTION_PRESET_CYCLIC_TOGGLE(1) — Toggles whether the preset repeats cyclically (setMotionPresetCyclic). Uses theis_cyclicargument 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 fromHIGH_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 |
|
|
Torque ON/OFF |
|
|
Hand initialization |
|
|
Control mode switching |
|
|
Mujoco simulation control (sim only) |
|
|
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/lowstateService 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::ddsnamespace (the IDL'smodule). In actual use, reference them asigris_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 OFFinit_type(BmsInitType) — Values actually handled by the bridge:BMS_INIT_NONE(0) — BMS power OFF (setBmsPowerAsync(false))BMS_INIT(1) — BMS power ONMOTOR_INIT(2) — Motor initializationBMS_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.
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 aControlModeCommandRequestRequest/Response), and the controller maps this to an internalRobotControlModeto 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 |
|
| High-Level |
1 |
|
| High-Level |
2 |
| → | - |
3 |
|
| High-Level |
4 |
| → | - |
5 |
| → | Low-Level |
6 |
| → | Low-Level |
7 |
| → | High-Level |
8 |
| → | High-Level |
9–18 |
| (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 bypreset_id(startMotionPreset). Can only be started fromHIGH_LEVEL_MODEorHIGH_LEVEL_WALK_MODE(rejected in other modes). Populate thepreset_idargument in the request.MOTION_PRESET_CYCLIC_TOGGLE(1) — Toggles whether the preset repeats cyclically (setMotionPresetCyclic). Uses theis_cyclicargument 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 fromHIGH_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 |
|
|
Torque ON/OFF |
|
|
Hand initialization |
|
|
Control mode switching |
|
|
Mujoco simulation control (sim only) |
|
|
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/lowstateService 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::ddsnamespace (the IDL'smodule). In actual use, reference them asigris_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 OFFinit_type(BmsInitType) — Values actually handled by the bridge:BMS_INIT_NONE(0) — BMS power OFF (setBmsPowerAsync(false))BMS_INIT(1) — BMS power ONMOTOR_INIT(2) — Motor initializationBMS_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.

