An 18-servo hexapod robot leg controller with dual PWM drivers for smooth, coordinated leg movement and inverse kinematics-based gait planning.
The IK_Hexapod project controls a 6-legged robot (18 servos total: 3 per leg) using PWM servo drivers via I²C communication. The system receives high-level commands and manages individual servo angles for smooth, coordinated locomotion and gait generation. This is a core kinematics controller for hexapod robotics research and development.
Key Features:
- ✅ 18 independent servo channels (6 legs × 3 servos each)
- ✅ Dual I²C PWM drivers (PCA9685) for 16 servos each
- ✅ Smooth PWM-based servo control (not Dynamixel)
- ✅ Per-servo angle control (-75° to +75°)
- ✅ Batch commands for synchronized movement
- ✅ Serial communication at 115200 baud
Each leg has 3 servos:
- Coxa (C) - Base joint, moves leg forward/backward
- Femur (F) - Upper leg, lifts/lowers body
- Tibia (T) - Lower leg, extends/retracts foot
Body
|
[Coxa]° ← Servo 1
|
[Femur]° ← Servo 2
|
[Tibia]° ← Servo 3
|
Foot
Leg 1 (Front-Left): Servos 0, 1, 2
Leg 2 (Mid-Left): Servos 3, 4, 5
Leg 3 (Back-Left): Servos 6, 7, 8
Leg 4 (Front-Right): Servos 9, 10, 11
Leg 5 (Mid-Right): Servos 12, 13, 14
Leg 6 (Back-Right): Servos 15, 16, 17
↑
Total: 18 servos
| Component | Pin | Signal |
|---|---|---|
| I²C SDA | A4 (Arduino Uno) | Data line |
| I²C SCL | A5 (Arduino Uno) | Clock line |
| GND | GND | Common ground |
| 5V | 5V | Power (PWM drivers) |
Two PCA9685 PWM Servo Drivers connected to same I²C bus:
| Driver | I²C Address | Servos Controlled |
|---|---|---|
| PWM1 | 0x40 | Channels 0-15 |
| PWM2 | 0x41 | Channels 16-17 (only 2 used) |
Note: Addresses set via A0-A5 pins on each PWM driver board
- Option 1: Separate 5-6V power supply for servos (RECOMMENDED)
- Option 2: Heavy-duty Arduino power (if rated for high current)
- Avoid: USB power for all 18 servos (will cause voltage drop)
Each servo is mapped to a specific angle range:
#define PULSE_MIN 184 // Corresponds to -75°
#define PULSE_MAX 430 // Corresponds to +75°
#define ANGLE_MIN -75.0 // Minimum angle
#define ANGLE_MAX 75.0 // Maximum anglePulse_Width (units) = (angle - ANGLE_MIN) * (PULSE_MAX - PULSE_MIN) / (ANGLE_MAX - ANGLE_MIN) + PULSE_MIN
For 0° (center):
Pulse = (0 - (-75)) * (430 - 184) / (75 - (-75)) + 184
Pulse = 75 * 246 / 150 + 184 = 307 units
- PWM Frequency: 50 Hz (standard for analog servos)
- Period: 20ms
- Pulse width: 0.5ms to 2.5ms (translates to -75° to +75°)
servo_id,angle
Example: 5,45
Sets servo 5 to 45 degrees
Response: DONE
ALL,angle0,angle1,angle2,...,angle17
Example: ALL,0,0,0,0,0,0,0,45,30,-15,0,0,0,0,0,0,0,0
Sets all 18 servos to their respective angles
Response: DONE
- 115200 baud (high speed for smooth real-time control)
After successful command:
DONE
If error:
ERROR or no response
void setServoAngle(int servoNum, float angle) {
// Constrain angle to valid range
float constrained_angle = constrain(angle, ANGLE_MIN, ANGLE_MAX);
// Convert angle to PWM pulse width
float pulse_width = (constrained_angle - ANGLE_MIN) *
(PULSE_MAX - PULSE_MIN) /
(ANGLE_MAX - ANGLE_MIN) + PULSE_MIN;
int pulse = (int)(pulse_width + 0.5);
// Send to correct PWM driver
if (servoNum < 9) {
pwm1.setPWM(servoNum, 0, pulse); // First driver: servos 0-8
} else {
pwm2.setPWM(servoNum - 9, 0, pulse); // Second driver: servos 9-17
}
}To move all legs simultaneously:
// Example: Forward walking gait frame
setServoAngle(0, 30); // Leg 1 Coxa forward
setServoAngle(1, 20); // Leg 1 Femur up
setServoAngle(2, -40); // Leg 1 Tibia extend
// Continue for all other legs...
setServoAngle(9, -30); // Leg 4 mirror (rear leg)
// etc.3 legs move forward → Body moves forward
3 legs support → Ground contact
Pattern:
Phase 1: Legs 1,3,5 forward; Legs 2,4,6 support
Phase 2: Legs 2,4,6 forward; Legs 1,3,5 support
One leg moves at a time in sequence
Pattern: Leg1 → Leg2 → Leg3 → Leg4 → Leg5 → Leg6 → Leg1...
Requires precise timing but highly stable
Two legs move alternately in sequence
Pattern: Odd legs move → Even legs move → repeat
| Parameter | Value |
|---|---|
| Type | Analog servo (standard SG90/MG90S) |
| Torque | 1.8-2.5 kg·cm typical |
| Speed | 60°/0.1s (60° in 100ms) |
| Angle Range | -75° to +75° (150° total) |
| Operating Voltage | 4.8-6V |
| Current | 10-50mA idle, 200-500mA moving |
| Aspect | Performance |
|---|---|
| Response Time | ~100ms per servo (startup) |
| Synchronization | Within 10ms across servos |
| Max Speed | 6 movements/second (synchronized) |
| Latency | <50ms from serial command to movement |
| Accuracy | ±2° mechanical tolerance |
Idle (all centered): ~300mA
Single leg moving: ~800mA
All legs coordinated: ~2-3A
Peak (rapid movement): ~5A possible
Command: ALL,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Effect: All servos to center (neutral positions)
Response: DONE
Command: 1,45.0
Effect: Servo 1 (Leg 1 Femur) moves up 45°
Response: DONE
Command: ALL,15,30,-20,0,0,0,0,0,0,-15,-30,20,0,0,0,0,0,0
Effect: Left legs move one direction, right legs opposite
Creates body forward motion
Response: DONE
// Basic tripod gait
void tripod_gait_phase1() {
setServoAngle(0, 30); // Leg 1 forward
setServoAngle(1, 20);
setServoAngle(2, -40);
// Legs 3, 5 same...
setServoAngle(9, -30); // Legs 2, 4, 6 stay grounded
setServoAngle(12, -30);
setServoAngle(15, -30);
}
void tripod_gait_phase2() {
setServoAngle(0, 0); // Leg 1 back to ground
// All servos return to support positions
}
void walk() {
for (int steps = 0; steps < 10; steps++) {
tripod_gait_phase1();
delay(500);
tripod_gait_phase2();
delay(500);
}
}Causes:
- I²C communication failure
- PWM address mismatch
- Servo power disconnected
- Angle values out of range
Solutions:
- Verify I²C address with scanner:
i2c_scanner.ino - Check servo power supply voltage (should be 5-6V)
- Test with center angle first:
setServoAngle(0, 0.0) - Ensure angle between -75° and +75°
Causes:
- Low power supply (brownout)
- Too many servos moving simultaneously
- I²C bus conflicts
- Serial buffer overflow
Solutions:
- Use dedicated power supply for servos
- Stagger servo commands (move 3 legs, then 3 legs)
- Reduce command frequency (100ms minimum between commands)
- Verify baud rate is 115200
Causes:
- Noisy power supply
- Poor servo winding balance
- Mechanical friction
Solutions:
- Add capacitors (100µF) near servo power
- Center servos and check for mechanical binding
- Apply slight damping (lubricant) to joints
On each PWM driver board, address pins (A0-A5) set the I²C address:
By default:
- PCA9685 #1: All pins LOW → Address 0x40
- PCA9685 #2: A0 HIGH, others LOW → Address 0x41
To change: Solder A0-A5 pins to VCC or GND as needed
Address Formula:
Base (0x40) + (A5×32 + A4×16 + A3×8 + A2×4 + A1×2 + A0×1)
For each leg, given a desired foot position (x, y, z):
Calculate: Coxa angle, Femur angle, Tibia angle
Such that: Foot reaches exactly (x, y, z)
This project implements forward kinematics display (servo angles → foot position).
Full IK would add:
Given (x, y, z) → Calculate servo angles needed
- ✨ Onboard IK solver algorithm
- ✨ Real-time gait generation
- ✨ Force feedback from servo load detection
- ✨ Wireless remote control (WiFi/Bluetooth)
- ✨ Sensor integration (IMU for balance)
- ✨ Terrain adaptation algorithm
- PCA9685 Datasheet: Adafruit PWM Driver
- Hexapod Design: IEEE Robotics & Automation publications
- Gait Analysis: Boston Dynamics research papers
- I²C Protocol: I²C Specification
| Parameter | Value |
|---|---|
| Total Servos | 18 (3 per leg × 6 legs) |
| Servo Type | Analog PWM |
| Angle Range | -75° to +75° per servo |
| Control | PWM drivers via I²C |
| Baud Rate | 115200 |
| Frequency | 50 Hz (servo standard) |
| Power | 5-6V dedicated supply recommended |
| Max Current | 5A peak |
Status: Functional hexapod leg controller ready for gait research Last Updated: February 2026