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
| # | Component | Estimated Cost |
|---|---|---|
| 1 | Laptop | Already have one |
| 2 | Old RC car | Destined for science — we'll gut it but leave it alone until Part 3C |
| 3 | Arduino Nano | ~$12 for 2 on Amazon |
| 4 | L298N H-Bridge Motor Driver | ~$7 for 2 on Amazon |
| 5 | HC-06 Bluetooth Module | ~$9 on Amazon |
| 6 | Small Breadboard | ~$4 on Amazon |
| 7 | Jumper Wires | All 3 types: M-F, M-M, F-F |
| 8 | 4×AA Battery Holder | ~$5 on Amazon |
| 9 | Small cardboard boxes, glue, screws | Whatever'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 D109. 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 D610. 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.pywith 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
| Problem | Cause | Fix |
|---|---|---|
| Pin conflict — motor and Bluetooth fighting over same pin | ENB and HC-06 TX both assigned to D10 | Move ENB to D6; keep Bluetooth on D10/D11 |
| Upload fails with "not in sync" error | HC-06 plugged into D0/D1 during upload | Unplug HC-06 before uploading, replug after |
| Motors make a clicking sound but don't spin | Old or weak batteries | Replace 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.













