Skip to main content

Interfacing

This page documents the communication interface between the high-level control software and the motor controllers. The system uses CAN bus as the primary communication protocol, bridging ROS2 nodes running on a laptop with embedded motor controllers (STM32-based FOC drivers and commercial actuators).

Architecture Overview

The interfacing layer consists of three main components:

┌─────────────────────────────────────────────────────────────┐
│ ROS2 Control Layer │
│ (joint_command, trajectory planning, IK/FK) │
└─────────────────────┬───────────────────────────────────────┘
│ ROS2 topics (MotorCmd, MotorFeedback)
┌─────────────────────▼───────────────────────────────────────┐
│ CAN Node (ROS2) │
│ • Message encoding/decoding (DBC) │
│ • SocketCAN / SLCAN interface │
│ • Topic-to-CAN mapping │
└─────────────────────┬───────────────────────────────────────┘
│ CAN bus (physical layer)
┌─────────────────────▼───────────────────────────────────────┐
│ Motor Controllers │
│ • STM32 FDCAN (custom FOC controllers) │
│ • Commercial motors (AK80-9, AK10-9, GL40 II) │
└─────────────────────────────────────────────────────────────┘
note

This interface layer bridges the high-level motion planning (ROS2) with low-level motor control, providing real-time command and feedback over CAN bus.

CAN Bus Protocol

Bus Configuration

ParameterValue
Bus typeCAN 2.0 (Classic CAN)
Bitrate500 kbps (configurable: 10k - 1M)
Frame formatStandard (11-bit ID) or Extended (29-bit ID)
Max payload8 bytes per frame
Termination120 Ω resistors at both ends
warning

Always ensure proper CAN bus termination with 120 Ω resistors at both ends to prevent signal reflections and communication errors.

Hardware Interface Options

The system supports two types of CAN interfaces:

  1. SocketCAN (native Linux CAN)

    • Direct CAN interface (e.g., can0, can1)
    • Lowest latency
    • Requires hardware CAN adapter
  2. SLCAN (Serial Line CAN)

    • CAN-over-USB adapter (e.g., CANable via /dev/ttyACM0)
    • Automatically configured via setup script
    • Bitrate mapping to SLCAN codes (see can_core.cpp:262-286)

Message Structure

CAN messages follow the standard CAN 2.0 frame format:

struct CanMessage {
uint32_t id; // CAN message ID (11 or 29 bits)
std::vector<uint8_t> data; // Payload (max 8 bytes)
uint8_t dlc; // Data Length Code
bool is_extended_id; // Extended frame format flag
bool is_remote_frame; // Remote transmission request
uint64_t timestamp_us; // Timestamp in microseconds
}

Reference: humanoid/autonomy/interfacing/can/include/can_core.hpp:8-19

DBC-Based Message Encoding

The CAN node uses DBC (Database CAN) files to define message formats and signal mappings. This allows for:

  • Structured message definition
  • Automatic encoding/decoding of physical values
  • Signal scaling and offset handling
  • Multi-byte signal packing

Reference: humanoid/autonomy/interfacing/can/include/can_node.hpp:32-36

ROS2 CAN Interface

CAN Core (CanCore class)

Low-level CAN interface abstraction that handles:

Initialization (can_core.cpp:21-34)

  • Interface configuration (SocketCAN vs SLCAN)
  • Socket creation and binding
  • Non-blocking I/O setup

Transmission (can_core.cpp:54-117)

  • CAN frame construction
  • Extended ID and RTR flag handling
  • Error checking and logging

Reception (can_core.cpp:119-177)

  • Non-blocking frame reception
  • ID mask extraction (standard vs extended)
  • Timeout handling

Setup Methods

  • setupSocketCan() - Native Linux CAN interface (can_core.cpp:179-236)
  • setupSlcan() - USB CAN adapter via external script (can_core.cpp:238-308)

CAN Node (CanNode class)

ROS2 node that bridges ROS topics and CAN messages:

Key Features:

  • Topic subscription: MotorCmd messages from joint controllers
  • Message publishing: MotorFeedback for motor state
  • DBC integration: Signal encoding/decoding using dbcppp library
  • Periodic reception: Timer-based polling for incoming CAN messages

Message Flow:

  1. Command Path (ROS → CAN):

    MotorCmd topic → motorCMDCallback() → encodeSignal() → sendMessage() → CAN bus
  2. Feedback Path (CAN → ROS):

    CAN bus → receiveMessage() → DBC decode → MotorFeedback topic
tip

Use ros2 topic echo /motor_feedback to monitor real-time motor telemetry during development.

Reference: humanoid/autonomy/interfacing/can/include/can_node.hpp:26-68

ROS2 Message Types

Motor Command (MotorCmd)

  • Position, velocity, torque setpoints
  • Control mode selection
  • Device ID targeting

Motor Feedback (MotorFeedback)

  • Current position, velocity
  • Motor current, temperature
  • Error flags

Reference: humanoid/autonomy/interfacing/can/include/can_node.hpp:18-24

Embedded (STM32) FDCAN Driver

STM32G4 FDCAN Peripheral

The custom FOC motor controllers use the STM32G4's FDCAN peripheral for CAN communication.

Hardware Configuration (FDCAN_STM32.cpp:25-58)

ParameterValue
InstanceFDCAN2
Frame formatClassic CAN
ModeNormal
Nominal bitrate~1 Mbps (calculated from prescaler/segments)
GPIO pinsPB12 (RX), PB13 (TX)
Alternate functionAF9 (FDCAN2)
InterruptsFDCAN2_IT0, FDCAN2_IT1

Bus-Off Recovery (FDCAN_STM32.cpp:7-23)

  • Automatic detection of bus-off state
  • Recovery by clearing INIT bit in CCCR register
  • Error status callback handling

Motor Control Loop Integration

The FDCAN driver is integrated into the FOC control loop:

Setup Phase (foc.cpp:11-16)

  1. Initialize PWM for motor phases
  2. Configure angle encoder (MT6835)
  3. Initialize current sensing
  4. Configure motor driver
  5. Set PID parameters and call motor.initFOC()
  6. Initialize FDCAN and enable RX interrupts

Loop Phase (foc.cpp:25-29)

  1. Call motor.loopFOC() and motor.move()
  2. Check ring buffer for CAN messages
  3. Process motor commands
  4. Send telemetry data back over CAN

Reference: humanoid/embedded/STM32/app/src/foc.cpp

Hardware Setup

Physical Connections

All motors connect to a shared CAN bus with the following topology:

[Laptop] --USB-- [CANable] --CAN_H/CAN_L-- [Motor 1] -- [Motor 2] -- ... -- [Motor 7] --[120Ω]
| | | |
[120Ω termination] XT30 XT30 XT30
note

Each motor has an XT30 connector for CAN data. Power is supplied separately via XT60 (high-voltage motors) or XT30 (low-voltage motors). See Electrical Documentation for details.

See Electrical Documentation for detailed wiring diagrams.

Interface Configuration

Example: SocketCAN setup

CanConfig config;
config.interface_name = "can0";
config.bustype = "socketcan";
config.bitrate = 500000;
config.receive_timeout_ms = 100;

Example: SLCAN setup (CANable)

CanConfig config;
config.interface_name = "can0";
config.device_path = "/dev/ttyACM0";
config.bustype = "slcan";
config.bitrate = 500000; // Maps to "-s6" for slcand

Reference: humanoid/autonomy/interfacing/can/include/can_core.hpp:21-28

Development & Testing

Launch Files

Start the CAN interface node:

ros2 launch can can.launch.py

Reference: humanoid/autonomy/interfacing/can/launch/can.launch.py

Testing Tools

Controller test (test_controller.cpp)

  • Automated testing of CAN message encoding/decoding
  • Validation of DBC signal mapping
  • Performance benchmarking

Reference: humanoid/autonomy/interfacing/can/test/test_controller.cpp

Debugging

Enable verbose logging in can_core.cpp:

  • Uncomment lines 62-75 for transmitted message logging
  • Use RCLCPP_DEBUG level for received messages

Monitor CAN traffic (Linux):

# View raw CAN messages
candump can0

# Send test message
cansend can0 123#DEADBEEF

Future Enhancements

  • CAN-FD support: Increase bandwidth for higher-rate telemetry
  • Multi-bus architecture: Separate buses for different limbs
  • Hardware filtering: Reduce CPU load by filtering messages at hardware level
  • Time-stamping: Precise synchronization with external sensors

References