Capstone build
Configuration 5: Multi-Mode Learning Robot
Combine all modules into one switchable robot platform.
The multi-mode robot combines Bluetooth, obstacle avoiding, line following, and RF control into one learning platform. Students can switch behavior without rebuilding the chassis.
What students learn: System design, modular coding, integration testing, and documentation.
Read this before wiring: The schematic shows only the modules required for this configuration. Compare it with the Arduino program pins before connecting the battery.
Mode-specific circuit schematic
Pin and power rules
Power rule
Use the Li-ion pack for motor power through L293D VCC2, and regulated 5V for Arduino Nano logic and modules.
Ground rule
All grounds must be common, otherwise the Arduino signal has no reliable reference.
Pin rule
The Arduino programs on this page match this pin plan: D5/D6 PWM, D8-D11 motor direction, D2-D3 Bluetooth, D4/D7 ultrasonic, D12 servo, A0-A5 sensors/RF.
Step-by-step build
- Finish and test each mode separately.
- Keep one shared motor function library.
- Assign mode letters: B, O, L, R.
- Use Bluetooth command or jumper switch to select mode.
- Document every pin so future students can repair it.
Arduino Nano program
Arduino Nano program
// Arduino Nano Multi-Mode Learning Robot
// Bluetooth commands:
// B = Bluetooth drive mode, O = obstacle mode, L = line follower, R = RF mode
// Drive commands in Bluetooth mode: F, B, L, R, S
#include <SoftwareSerial.h>
#include <Servo.h>
SoftwareSerial BT(2, 3); // HC-05 TX -> D2, HC-05 RX <- D3 through divider
Servo scanner;
char mode = 'B';
const int trigPin = 4, echoPin = 7, servoPin = 12;
const int leftIR = A0, rightIR = A1;
const int rfF = A2, rfB = A3, rfL = A4, rfR = A5;
const int ENA = 5, IN1 = 8, IN2 = 9, ENB = 6, IN3 = 10, IN4 = 11;
int speedValue = 145;
unsigned long lastAutoStep = 0;
void setup() {
pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT);
pinMode(leftIR, INPUT); pinMode(rightIR, INPUT);
pinMode(rfF, INPUT); pinMode(rfB, INPUT); pinMode(rfL, INPUT); pinMode(rfR, INPUT);
pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
BT.begin(9600);
scanner.attach(servoPin);
scanner.write(90);
stopMotors();
}
void loop() {
if (BT.available()) {
char c = BT.read();
if (c == 'B' || c == 'O' || c == 'L' || c == 'R') mode = c;
else handleBluetoothDrive(c);
}
if (millis() - lastAutoStep < 40) return;
lastAutoStep = millis();
if (mode == 'O') obstacleStep();
else if (mode == 'L') lineFollowerStep();
else if (mode == 'R') rfRemoteStep();
// Bluetooth drive is event-based, so it acts only when a command arrives.
}
void handleBluetoothDrive(char c) {
if (mode != 'B') return;
if (c == 'F') forward(speedValue);
else if (c == 'B') backward(speedValue);
else if (c == 'L') left(speedValue);
else if (c == 'R') right(speedValue);
else if (c == 'S') stopMotors();
}
void obstacleStep() {
scanner.write(90);
int front = distanceCm();
if (front > 25) {
forward(135);
return;
}
stopMotors();
backward(125); delay(180); stopMotors();
int leftSpace = look(150);
int rightSpace = look(30);
scanner.write(90);
if (leftSpace > rightSpace) left(135);
else right(135);
delay(260);
stopMotors();
}
int look(int angle) {
scanner.write(angle);
delay(220);
return distanceCm();
}
int distanceCm() {
digitalWrite(trigPin, LOW); delayMicroseconds(2);
digitalWrite(trigPin, HIGH); delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long us = pulseIn(echoPin, HIGH, 30000);
if (us == 0) return 999;
return us / 58;
}
void lineFollowerStep() {
bool leftOnLine = (digitalRead(leftIR) == LOW);
bool rightOnLine = (digitalRead(rightIR) == LOW);
if (leftOnLine && rightOnLine) forward(125);
else if (leftOnLine && !rightOnLine) left(110);
else if (!leftOnLine && rightOnLine) right(110);
else stopMotors();
}
void rfRemoteStep() {
if (digitalRead(rfF)) forward(140);
else if (digitalRead(rfB)) backward(140);
else if (digitalRead(rfL)) left(140);
else if (digitalRead(rfR)) right(140);
else stopMotors();
}
void forward(int s){ drive(HIGH, LOW, HIGH, LOW, s); }
void backward(int s){ drive(LOW, HIGH, LOW, HIGH, s); }
void left(int s){ drive(LOW, HIGH, HIGH, LOW, s); }
void right(int s){ drive(HIGH, LOW, LOW, HIGH, s); }
void stopMotors(){ analogWrite(ENA, 0); analogWrite(ENB, 0); }
void drive(int a1, int a2, int b1, int b2, int s) {
digitalWrite(IN1, a1); digitalWrite(IN2, a2);
digitalWrite(IN3, b1); digitalWrite(IN4, b2);
analogWrite(ENA, s); analogWrite(ENB, s);
}Use Build here to verify this program with the Roboda Arduino compiler.
Do and don't
Do
- Use Arduino Nano as the controller.
- Keep battery negative and all module GND pins connected.
- Test motors with wheels lifted first.
- Use a voltage divider for HC-05 RX if Arduino TX is 5 V.
- Power servo from a stable 5 V source.
Don't
- Do not short Li-ion cells.
- Do not connect motors directly to Arduino Nano pins.
- Do not mix loose wires without labels.
- Do not run high motor speed during first tests.
- Do not assume every RF module has the same pinout.