/* * car.ino — Arduino Bluetooth: Make It Connect, chapter 9 * * A Bluetooth-driven two-motor car. Command handling from chapter 8, motion * from chapter 9. * * PINS — these match the real car this book is drawn from. * * ENA 5 ENB 6 <- MUST be PWM pins. On an Uno that is 3, 5, 6, 9, 10, 11. * IN1 12 IN3 10 * IN2 11 IN4 9 * * ⚠️ The enables are the trap. analogWrite() only produces PWM on pins that * have the hardware for it. Anywhere else it silently degrades to a digital * write — above 127 is HIGH, below is LOW — so the car drives perfectly at * exactly one speed and never reports an error. The car this book is drawn * from had its enables on pins 13 and 8 for ten years and nobody noticed the * speed control had never once worked. * * ⚠️ Also pull the jumper caps off the L298N's ENA/ENB headers. Fitted, they * tie the enables to +5V and override the Arduino entirely — same one-speed * symptom, different cause. * * POWER — battery + to the L298N's +12V AND to the Arduino's Vin. * battery - to the L298N's GND AND the Arduino's GND. * The Arduino needs feeding too; this is the step people miss. * * The Bluetooth module goes on pins 2 and 3 here, leaving the hardware serial * port free so you can watch what arrives while the car is connected. * Module TXD -> pin 2 * Module RXD -> pin 3, through the 1k/2k divider * * troniction.com/code/ */ #include SoftwareSerial bt(2, 3); // RX, TX — from the Arduino's point of view const int ENA = 5, IN1 = 12, IN2 = 11; const int ENB = 6, IN3 = 10, IN4 = 9; int speed = 200; // 0-255. 'S' stops; '0'-'9' set this. void setup() { pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); Serial.begin(9600); bt.begin(9600); halt(); Serial.println(F("Car ready. F B L R S, or 0-9 for speed.")); } // ---- motion --------------------------------------------------------------- // Which way is "forward" depends on how the motors are mounted and wired. If a // wheel turns the wrong way, swap that motor's two wires at the terminal block // or swap its two pins here. Both are correct fixes — test it, don't reason // about it. void drive(bool aFwd, bool bFwd) { digitalWrite(IN1, aFwd ? HIGH : LOW); digitalWrite(IN2, aFwd ? LOW : HIGH); digitalWrite(IN3, bFwd ? HIGH : LOW); digitalWrite(IN4, bFwd ? LOW : HIGH); analogWrite(ENA, speed); analogWrite(ENB, speed); } void forward() { drive(true, true); } void backward() { drive(false, false); } void left() { drive(false, true); } // one side reverses to turn on the spot void right() { drive(true, false); } void halt() { analogWrite(ENA, 0); analogWrite(ENB, 0); digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, LOW); } // ---- commands ------------------------------------------------------------- void loop() { if (!bt.available()) return; char c = bt.read(); if (c >= '0' && c <= '9') { // Map 0-9 onto the usable part of the range. Below about 60 most cheap // gear motors will not start turning at all, so 0 is stop and 1 is the // slowest speed that actually moves. speed = (c == '0') ? 0 : map(c - '0', 1, 9, 60, 255); Serial.print(F("speed ")); Serial.println(speed); if (speed == 0) halt(); return; } switch (c) { case 'F': forward(); break; case 'B': backward(); break; case 'L': left(); break; case 'R': right(); break; case 'S': halt(); break; default: break; } }