Learn how to integrate Arduino microcontrollers with OctoMY™ using the ArduMY firmware. This tutorial covers advanced configuration and custom actuator types.
Pro Tip
If you're building your first robot, start with the Basic Wheeled Robot tutorial. This advanced guide covers ArduMY configuration in depth for custom projects.
ArduMY is OctoMY™'s firmware for Arduino-compatible boards. It provides:
ArduMY Architecture
┌────────────────────────────────────────┐
│ OctoMY Agent │
│ (Phone/Computer) │
└───────────────┬────────────────────────┘
│ USB Serial
┌───────────────┴────────────────────────┐
│ Arduino + ArduMY │
│ ┌─────────────────────────────────┐ │
│ │ Protocol Parser │ │
│ │ Actuator Manager │ │
│ │ Sensor Reader │ │
│ │ Fail-safe Controller │ │
│ └─────────────────────────────────┘ │
└───────┬───────────┬───────────┬────────┘
│ │ │
[Servos] [Motors] [Sensors]
| Board | Pins | PWM | Analog | Notes |
|---|---|---|---|---|
| Arduino Mega 2560 | 54 | 15 | 16 | Recommended |
| Arduino Uno | 14 | 6 | 6 | Basic projects |
| Arduino Nano | 14 | 6 | 8 | Compact projects |
| ESP32 | 34 | 16 | 18 | WiFi capable |
| Teensy 4.0 | 40 | 31 | 14 | High performance |
Did You Know?
The Arduino Mega is recommended because it has 15 PWM pins - enough for complex robots with multiple servos and motors. The ESP32 adds WiFi, enabling wireless control without a phone connected.
Get the ArduMY source from the OctoMY™ repository:
cd /path/to/OctoMY
ls src/libs/libardumy/arduino/
src/libs/libardumy/arduino/ArduMYMain/ArduMYMain.ino
Edit ArduMYConfig.h:
#ifndef ARDUMY_CONFIG_H
#define ARDUMY_CONFIG_H
// Serial settings
#define SERIAL_BAUD 115200
// Number of actuators
#define NUM_ACTUATORS 8
// Number of sensors
#define NUM_SENSORS 4
// Fail-safe timeout (ms)
#define FAILSAFE_TIMEOUT 1000
// Update rate (Hz)
#define UPDATE_RATE 50
#endif
Define your actuators in ActuatorConfig.h:
#include "ArduMY.h"
ActuatorConfig actuators[NUM_ACTUATORS] = {
// Name Type Pin(s) Min Max Default
{"servo.pan", ACTUATOR_SERVO, {9}, 0, 180, 90},
{"servo.tilt", ACTUATOR_SERVO, {10}, 0, 180, 90},
{"motor.left", ACTUATOR_DC, {5, 6, 7}, -100, 100, 0},
{"motor.right", ACTUATOR_DC, {8, 11, 12}, -100, 100, 0},
// Add more actuators...
};
Define sensors in SensorConfig.h:
#include "ArduMY.h"
SensorConfig sensors[NUM_SENSORS] = {
// Name Type Pin(s)
{"distance.front", SENSOR_ULTRASONIC, {2, 3}}, // trig, echo
{"distance.left", SENSOR_ULTRASONIC, {4, 5}},
{"line.sensors", SENSOR_ANALOG, {A0, A1, A2}},
{"battery.voltage", SENSOR_ANALOG, {A7}},
};
Standard hobby servos (PWM control).
// Single servo
{"arm.shoulder", ACTUATOR_SERVO, {9}, 0, 180, 90}
Servo
┌─────────┐
│ ● ● ● │
│Signal │
│ 5V GND │
└─────────┘
│ │ │
│ │ └── GND
│ └───── 5V (or 6V external)
└──────── Arduino PWM pin
Bidirectional DC motors with H-bridge driver.
// DC motor with L298N (EN, IN1, IN2)
{"motor.left", ACTUATOR_DC, {9, 8, 7}, -100, 100, 0}
The three pins are:
| Speed | EN | IN1 | IN2 | Result |
|---|---|---|---|---|
| 0 | 0 | X | X | Stop |
| 50 | 50% | 1 | 0 | Forward 50% |
| -50 | 50% | 0 | 1 | Reverse 50% |
| 100 | 100% | 1 | 0 | Full forward |
Step/direction control for stepper drivers.
// Stepper with A4988 driver (step, dir)
{"stepper.z", ACTUATOR_STEPPER, {2, 3}, 0, 10000, 0}
A4988 Driver
┌───────────────────┐
│ DIR STEP EN │
│ │ │ │ │
└──┼────┼────┼──────┘
│ │ │
│ │ └── Arduino D4 (optional)
│ └─────── Arduino D3
└──────────── Arduino D2
On/off control for high-power loads.
// Relay (digital output)
{"lights.main", ACTUATOR_RELAY, {13}, 0, 1, 0}
Modified servos for continuous rotation.
// Continuous servo (-100 to 100 speed)
{"wheel.left", ACTUATOR_CONTINUOUS, {9}, -100, 100, 0}
HC-SR04 or similar (trigger + echo pins).
{"distance.front", SENSOR_ULTRASONIC, {2, 3}} // trig=2, echo=3
Generic analog input (potentiometers, IR sensors, etc.).
{"sensor.pot", SENSOR_ANALOG, {A0}}
Limit switches, buttons, etc.
{"limit.left", SENSOR_DIGITAL, {4}} // INPUT_PULLUP used
Sensors on I2C bus (MPU6050, etc.).
{"imu", SENSOR_I2C, {0x68}} // I2C address
Open Serial Monitor (115200 baud):
ArduMY v1.0.0
Board: Arduino Mega
Actuators: 4
Sensors: 3
Fail-safe timeout: 1000ms
Ready. Waiting for commands...
Send commands manually:
# Query status
?
# Set actuator (servo.pan to 90)
A0=90
# Read sensor (distance.front)
S0?
# Enable/disable actuators
E1 # Enable
E0 # Disable
Pro Tip
Use the Arduino Serial Monitor's "No line ending" setting when testing. If commands don't work, try "Newline" or "Both NL & CR" instead.
┌─────────────────────────────────────────────┐
│ Hardware Configuration │
├─────────────────────────────────────────────┤
│ │
│ Controller │
│ ● Arduino Mega at /dev/ttyUSB0 │
│ ArduMY v1.0.0 │
│ Status: Connected │
│ │
│ Actuators Sensors │
│ ├── servo.pan ├── distance │
│ ├── servo.tilt ├── imu │
│ ├── motor.left └── battery │
│ └── motor.right │
│ │
│ [Configure] [Test] [Disconnect] │
│ │
└─────────────────────────────────────────────┘
OctoMY™ auto-imports actuator names from ArduMY. Verify mapping:
┌─────────────────────────────────────────────┐
│ Actuator Mapping │
├─────────────────────────────────────────────┤
│ │
│ ArduMY Name │ OctoMY Name │ Type │
│ ───────────────────────────────────────── │
│ servo.pan │ head.pan │ Servo │
│ servo.tilt │ head.tilt │ Servo │
│ motor.left │ motors.left │ DC │
│ motor.right │ motors.right │ DC │
│ │
│ [Apply Mapping] [Reset to Defaults] │
│ │
└─────────────────────────────────────────────┘
ArduMY includes fail-safe features for robot safety.
Security Consideration
Always configure fail-safe behavior for your robot. A robot that keeps moving when communication is lost can cause damage or injury. The default 1-second timeout is a good starting point.
If communication is lost for FAILSAFE_TIMEOUT milliseconds:
// In ArduMYConfig.h
#define FAILSAFE_TIMEOUT 1000 // 1 second
// Default fail-safe values (in ActuatorConfig)
{"motor.left", ACTUATOR_DC, {5, 6, 7}, -100, 100, 0}, // 0 = stopped
{"servo.pan", ACTUATOR_SERVO, {9}, 0, 180, 90}, // 90 = centered
Override the fail-safe handler:
void onFailsafe() {
// Custom fail-safe behavior
for (int i = 0; i < NUM_ACTUATORS; i++) {
setActuator(i, actuators[i].defaultValue);
}
// Optional: signal failure
digitalWrite(LED_BUILTIN, HIGH);
}
When communication resumes:
// In ArduMY.h
enum ActuatorType {
ACTUATOR_SERVO,
ACTUATOR_DC,
ACTUATOR_STEPPER,
ACTUATOR_RELAY,
ACTUATOR_CONTINUOUS,
ACTUATOR_CUSTOM1, // Your custom type
ACTUATOR_CUSTOM2,
};
void handleCustomActuator(int id, float value) {
ActuatorConfig& cfg = actuators[id];
switch (cfg.type) {
case ACTUATOR_CUSTOM1:
// Your custom control logic
int pwm = map(value, cfg.minVal, cfg.maxVal, 0, 255);
analogWrite(cfg.pins[0], pwm);
// Additional logic...
break;
}
}
| Issue | Solution |
|---|---|
| No USB connection | Check cable (data, not charge-only) |
| Wrong port | Verify COM port in device manager |
| Permission denied | Linux: add user to dialout group |
| Driver missing | Install CH340/FTDI drivers |
| Issue | Solution |
|---|---|
| No response | Check baud rate (115200) |
| Garbled output | Verify serial settings |
| Actuators don't move | Check wiring and power |
| Wrong direction | Swap motor wires or pins |
| Issue | Solution |
|---|---|
| Frequent timeouts | Increase FAILSAFE_TIMEOUT |
| No fail-safe | Verify timeout is enabled |
| Slow recovery | Reduce agent poll interval |
// Increase serial buffer
#define SERIAL_RX_BUFFER_SIZE 256
// Use direct port manipulation for time-critical actuators
PORTD = (PORTD & 0x0F) | (value & 0xF0);
// Stagger servo updates to reduce power spikes
void updateServos() {
for (int i = 0; i < numServos; i++) {
servos[i].write(values[i]);
delayMicroseconds(100); // Stagger
}
}
// Read battery voltage periodically
float readBattery() {
int raw = analogRead(A7);
float voltage = raw * (5.0 / 1023.0) * 3.0; // Voltage divider
return voltage;
}
void loop() {
if (readBattery() < 6.0) {
triggerFailsafe(); // Low battery protection
}
}