Tuesday, May 19, 2026

Part 3B: Cutting the Cord — Wireless Control via Bluetooth

 After Parts 1, 2, and 3A, we're starting to get a feel for how a robot actually works:

👉 Robots need senses — sensors that let them see, hear, and feel the world around them. Based on what those sensors pick up, the Python "brain" decides what to do next.

Before we get to full autonomy, we need to get comfortable controlling our robot manually — with a keyboard. And just to be clear: controlling a car with a laptop keyboard is fundamentally different from using a remote control. When Python is in charge, that same "brain" can be upgraded to make decisions on its own. A remote control can't learn. Python can.

But before we continue — let's agree on something important.


Our Unofficial Motto

We do the boring stuff first. The simplest, most "pointless-looking" projects first. Then we upgrade, step by step, until we're building things that actually matter in real life.

If you want to jump straight to a "Traffic Light Controller" or "Smart Alarm System" — tutorials for those are everywhere online. You can follow one and have a polished result in an afternoon. No shame in that.

But that's not what we're doing here. We're here because we want to know why each component exists, why each line of code is there. Like the difference between taking your car to a mechanic versus crawling under it yourself, covered in grease, and figuring out what went wrong. One gets the job done. The other gives you a satisfaction that's hard to describe.

Alright. Let's get back under the car.


The Problem with Part 3A

In Part 3A, we gave our robot a brain and taught it to move. Impressive in concept. Terrible in practice.

Picture this: a warehouse full of our "brilliant" robots from Part 3A, each one tethered to a laptop by a cable, hauling boxes around. Within sixty seconds, the entire floor would be a catastrophic tangle of wires, toppled shelves, and regret. That's not automation. That's a disaster.

So in Part 3B, we cut the cord. We'll mount our motors onto an old RC car body and go wireless.


Same Chain of Command, New Communication Method

The structure is exactly the same as Part 3A:

👉 CEO (Python) → Manager (Microcontroller) → Team Leader (Driver Module) → Workers (Motors)

The only difference is how the CEO talks to the Manager.

In Part 3A, the company was too broke for phones — so the CEO had to physically walk over and shout instructions. Now business is good. The CEO stays in the office and just sends a message. The Manager could be anywhere — even outside — and still gets the order instantly.

That "phone" can work two ways:

WiFi — using an ESP8266 or ESP32 module. Laptop and robot on the same network. Longer range, more stable.

Bluetooth — using an HC-05 or HC-06 module. Pairs like a wireless headset. Simpler to set up, shorter range (~10 meters).

We're going with Bluetooth — it's the budget phone option. Does the job, costs less, gets us moving faster.


What You Need

#ComponentEstimated Cost
1LaptopAlready have one
2Old RC carDestined for science — we'll gut it but leave it alone until Part 3C
3Arduino Nano~$12 for 2 on Amazon
4L298N H-Bridge Motor Driver~$7 for 2 on Amazon
5HC-06 Bluetooth Module~$9 on Amazon
6Small Breadboard~$4 on Amazon
7Jumper WiresAll 3 types: M-F, M-M, F-F
84×AA Battery Holder~$5 on Amazon
9Small cardboard boxes, glue, screwsWhatever's lying around

If you finished Part 3A, the only new purchase here is the HC-06 module (~$9) — and one RC car pulled out of a closet or garage. You'll also need some cardboard, glue, and screws to mount everything onto the car and give your robot the ability to stand on its own four wheels in all its glorious, jury-rigged beauty.








Upload the Code to Arduino Nano

Same process as before — quick recap:

1. Software and Driver Download Arduino IDE (free) from the official Arduino website. If your computer doesn't recognize the board, install the CH340 driver (search "CH340 driver").

2. Connect and Configure Plug the Arduino Nano into your laptop via USB Mini-B cable. In Arduino IDE:

  • Tools → Board → Arduino AVR Boards → Arduino Nano
  • Tools → Processor → ATmega328P (or ATmega328P Old Bootloader for older boards)
  • Tools → Port → select the correct COM port (unplug and replug to identify it)

3. Upload Paste the code below, click Verify (✔), then Upload (➔). Wait for "Done uploading."

⚠️ Important: Disconnect HC-06 from D0/D1 before uploading — if it's plugged into those pins, the upload will fail with a "not in sync" error.


#include <SoftwareSerial.h>

// Bluetooth on pins 10, 11 (avoids conflicts)
SoftwareSerial Bluetooth(10, 11); // RX=10, TX=11

// Motor pins
#define IN1 2
#define IN2 3
#define IN3 4
#define IN4 5
#define ENA 9
#define ENB 6

void setup() {
  Bluetooth.begin(9600);
  pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
  pinMode(ENA, OUTPUT); pinMode(ENB, OUTPUT);
  analogWrite(ENA, 200);
  analogWrite(ENB, 200);
}

void moveForward() {
  analogWrite(ENA, 200); analogWrite(ENB, 200);
  digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
}
void moveBackward() {
  analogWrite(ENA, 200); analogWrite(ENB, 200);
  digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
  digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
}
void turnLeft() {
  analogWrite(ENA, 200); analogWrite(ENB, 200);
  digitalWrite(IN1, LOW);  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
}
void turnRight() {
  analogWrite(ENA, 200); analogWrite(ENB, 200);
  digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);  digitalWrite(IN4, HIGH);
}
void stopCar() {
  digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
}

void loop() {
  if (Bluetooth.available()) {
    char cmd = Bluetooth.read();
    if      (cmd == 'w') moveForward();
    else if (cmd == 's') moveBackward();
    else if (cmd == 'a') turnLeft();
    else if (cmd == 'd') turnRight();
    else if (cmd == 'x') stopCar();
  }
}

The Python Code

Same as before, just updated for Bluetooth. Save this as rccar.py. Replace 'COM6' with your actual Bluetooth COM port (instructions below).


import
serial import keyboard import time ser = serial.Serial('COM6', 9600, timeout=1) time.sleep(2) print("W=forward, S=backward, A=left, D=right, X=stop. ESC=quit") while True: try: if keyboard.is_pressed('w'): ser.write(b'w') print("Moving forward...") elif keyboard.is_pressed('s'): ser.write(b's') print("Moving backward...") elif keyboard.is_pressed('a'): ser.write(b'a') print("Turning left...") elif keyboard.is_pressed('d'): ser.write(b'd') print("Turning right...") else: ser.write(b'x') if keyboard.is_pressed('esc'): ser.write(b'x') time.sleep(0.2) break time.sleep(0.1) except Exception as e: print(f"Error: {e}") break ser.close()

Wiring It All Together

Steps 1–6 are identical to Part 3A — we're just repeating them here for completeness.

1. Mount Arduino Nano on Breadboard Make sure the two rows of pins straddle the center gap.



2. Connect D2–D5 to L298N 4× Male-to-Female jumper wires from Arduino to L298N:

Arduino D2  →  L298N IN1  (Motor 1 forward)
Arduino D3  →  L298N IN2  (Motor 1 backward)
Arduino D4  →  L298N IN3  (Motor 2 left)
Arduino D5  →  L298N IN4  (Motor 2 right)



3. Connect GND 1× Male-to-Male wire: Arduino GND → L298N GND.





4. Connect the Motors Motor 1 → OUT1, OUT2. Motor 2 → OUT3, OUT4.




5. Connect Battery Pack Red (+) → L298N 12V terminal. Black (−) → L298N GND.



6. Steps 1–5 are a repeat of Part 3A. Now for the new guest: the HC-06.




7. Mount HC-06 on the Breadboard — horizontally

This matters more than it sounds. Here's why: on a breadboard, holes in the same column (vertical) are connected. Holes in the same row (horizontal) are not.

So if you plug the HC-06 in vertically, you're accidentally shorting all its pins together. Plug it in horizontally, and each pin gets its own isolated column. Also leave at least one column of gap between HC-06 and the Arduino Nano — same reason.




8. Connect HC-06


HC-06 GND  →  Arduino GND
HC-06 VCC  →  Arduino 5V
HC-06 RXD  →  Arduino D11
HC-06 TXD  →  Arduino D10





9. ENA and ENB — remove the jumper caps In Part 3A, we used jumper caps to keep ENA and ENB permanently HIGH. Now we want Python to control motor speed, so we wire them directly:


L298N ENA  →  Arduino D9
L298N ENB  →  Arduino D6


10. Power the Arduino from the L298N Connect Arduino VIN → L298N 12V terminal. Both the Arduino and L298N should light up. The HC-06 LED will blink, waiting for a connection.





Full Wiring Diagram




Connecting HC-06 to Your Laptop

Pair the module:

  • Power up the circuit — HC-06 LED will blink rapidly
  • On Windows: Settings → Bluetooth & devices → Add device → Bluetooth
  • Select HC-06 (may also appear as "Linvar" or "JY-MCU")
  • Enter PIN: 1234 (or 0000)

Find the COM port:

  • Settings → Bluetooth & devices → More Bluetooth settings
  • Go to the COM Ports tab
  • Find HC-06 with Direction = Outgoing — that's your port
  • Update rccar.py with that port number

Run It

Open PyCharm, run rccar.py, and press W, A, S, D to control the motors.

Freedom. No cables. No chaos. Just a robot that actually listens from across the room.


Troubleshooting: Lessons Learned the Hard Way

ProblemCauseFix
Pin conflict — motor and Bluetooth fighting over same pinENB and HC-06 TX both assigned to D10Move ENB to D6; keep Bluetooth on D10/D11
Upload fails with "not in sync" errorHC-06 plugged into D0/D1 during uploadUnplug HC-06 before uploading, replug after
Motors make a clicking sound but don't spinOld or weak batteriesReplace with fresh AA batteries — seriously, check this first

That last one is a classic. We spent a while convinced the code was wrong. It was the batteries.


Next up — Part 3C: we finally operate on the RC car. The motors are waiting. The servo steering is a mystery. Let's find out what's inside.