Community project
Moon Rover Controller
Build a tracked rover controlled by an Arduino that navigates autonomously using ultrasonic distance sensing. This project combines motor control, obstacle detection, and user feedback through an LCD display, 7-segment digit display, and buzzer to create a small autonomous vehicle that can drive, pause, and turn based on what it detects ahead.
The guide provides a complete wiring diagram, parts list, and step-by-step assembly instructions starting with the caterpillar track chassis and progressing through motor wiring, sensor integration, and display connections. Firmware is included to handle motor speed control via PWM, distance measurement, state management, and user input through push buttons, allowing the rover to operate in multiple modes from startup through autonomous driving.
Wiring diagram
Gather all the parts
Assemble it in 9 steps
1. Maak het rupsonderstel klaar
Print de Desert Planet Exploration Rover en bekijk waar de twee motoren, elektronica en batterijen passen. Monteer de twee gele TT-tandwielmotoren en controleer of de motorhuizen en assen passen. De exacte uitvoering en benodigde kracht zijn niet bevestigd. Maak zo nodig passende steunen of koppelingen. Forceer niets. Zet de Uno, driver en batterijen stevig en geïsoleerd vast, uit de buurt van de rupsen.
- Controleer vóór aansluiten dat beide motoren geschikt zijn voor 6 V en dat hun stroom bij blokkeren binnen de mogelijkheden van de driver en motorvoeding blijft. De voorbeeldmotor trekt ongeveer 1,5 A per motor bij blokkeren; jouw motoren kunnen afwijken. Rijd niet als de aandrijving klemt.
- De rover ziet geen trappen of tafelranden. Gebruik uitsluitend op een vlakke vloer onder toezicht.
2. Bedraad de motoren en afstandssensor
Haal USB los en verwijder alle batterijen. Gebruik de Whadda WPI409 in plaats van de Pololu motorbesturing. Verbind de linkermotor met de twee MOTORA-klemmen en de rechtermotor met de twee MOTORB-klemmen. Verwijder de 5V EN jumper en verbind de 5V-aansluiting van de WPI409 met Uno 5V. Verwijder de ENA- en ENB-jumpers en verbind ENA en ENB allebei met Uno D5. Verbind IN1 met D7, IN2 met D8, IN3 met D9 en IN4 met D10; verbind GND met Uno GND. Laat CSA en CSB elk met hun jumper met GND verbonden voor normaal gebruik zonder stroommeting. Zet de HC-SR04 vooraan en verbind VCC met 5V, GND met GND, TRIG met D2 en ECHO met D3.
- Sluit motoren nooit rechtstreeks op de Uno aan. Zet en isoleer motorverbindingen stevig vast.
3. Plaats je breadboard en drukknoppen
Gebruik het breadboard voor de signalen en verbind de minbaan met Uno GND. Sluit van de startknop één kant op A3 en de andere op GND aan. Sluit van de stopknop één kant op A0 en de andere op GND aan. Bij vierpoots drukknoppen zitten de twee pootjes aan dezelfde kant al aan elkaar; gebruik twee tegenover elkaar liggende zijden en controleer zo nodig met een multimeter. De Uno verzorgt de benodigde interne weerstanden.
4. Sluit beide displays aan
Zet USB en beide batterijhouders uit en haal de batterijen eruit. Gebruik geen I2C-adapter. Sluit het Joy-IT LCD direct aan: pin 1 (VSS) naar GND, pin 2 (VDD) naar 5V, pin 4 (RS) naar D11, pin 5 (RW) naar GND, pin 6 (E) naar D12, pin 11 (D4) naar D13, pin 12 (D5) naar A2, pin 13 (D6) naar A4 en pin 14 (D7) naar A5. Laat LCD-pinnen 7 tot en met 10 leeg. LCD pin 15 gaat via de 220-ohmweerstand naar 5V, pin 16 naar GND. Verbind de twee buitenste pootjes van de 10k-potmeter met 5V en GND en het middelste met LCD pin 3 (VO). Draai voor leesbare tekst.
- Controleer pinnummers op het scherm. Sluit de achtergrondverlichting niet zonder de 220-ohmweerstand aan.
5. Sluit het cijferdisplay aan
Verbind van de Kingbright SC56-11GWA pin 3 (gemeenschappelijke min) met GND. Verbind pin 6 en pin 4 elk via een eigen 1k-ohmweerstand met 5V. Verbind pin 7, 2, 1 en 9 elk via een eigen 1k-ohmweerstand met D6. Sluit de weerstanden aan op de losse pootjes: nooit segmenten zonder weerstand. De overige displaypinnen blijven los. Het display toont 0 bij stoppen en 1 als de rover gestart is.
- De aansluiting van de tweede motor en de schermen kan veranderd zijn; volg het nieuwe schema.
6. Sluit de zoemer aan
Verbind op de ALLNET B27 module +5V met Uno 5V, GND met GND en TTL met A1. De zoemer piept kort bij een obstakel of wanneer er geen betrouwbare echo is.
7. Sluit de twee AA-houders aan
Haal USB los en verwijder alle batterijen. Gebruik voor de motoren je bestaande 4-AA-houder. Verbind de plus via de losse aan-uit-schakelaar met VMS van de motorbesturing en de min met Uno GND en driver GND. Gebruik daarnaast een tweede 4-AA-houder met eigen aan-uit-schakelaar voor de Uno. Verbind de plus van deze tweede houder met VIN van de Pololu S7V8F5-regelaar, en de min met GND van de regelaar en Uno GND. Laat SHDN van de regelaar los. Plaats in elke houder vier AA-alkalinecellen volgens de plus- en mintekens. Zet alleen de tweede houder aan en controleer met een multimeter dat VOUT ten opzichte van GND ongeveer 5 V is. Schakel de houder uit en verbind dan VOUT met de 5V-pin van de Uno.
- Sluit de 4-AA-houder nooit rechtstreeks aan op de 5V-pin of ronde voedingsaansluiting van de Uno. Verwissel plus en min niet; dit kan schade veroorzaken. De regelaar maakt een stabiele 5 V.
- De losse schakelaar schakelt alleen de motoren uit. Schakel de tweede houder ook uit om de Uno uit te zetten. Koppel VOUT van de regelaar volledig los van Uno 5V voordat je USB aansluit; sluit nooit beide voedingen tegelijk aan.
- Gebruik geen breadboard voor de motorstroom. Controleer dat houder, bedrading en schakelaar minstens de motorstroom aankunnen; de schakelaar minimaal 4 A bij 6 V DC. De L298N verliest spanning en wordt warm; met vier AA-cellen kunnen de motoren te weinig kracht hebben. Bij belasting kan de voeding onder de minimale 5 V zakken. Laad alkalinebatterijen nooit op.
8. Test met opgeheven rupsen
Steun de rover zodat beide rupsen vrij hangen. Zet na het installeren van de firmware de Uno-voeding aan en daarna de motorvoeding. Bij inschakelen toont het LCD GESTOPT, het cijferdisplay 0 en blijven motoren uit. Druk op start; het LCD toont START OVER 5 SEC en na vijf seconden kunnen de motoren draaien. Houd een vlak voorwerp eerst op 50 cm en daarna binnen 25 cm voor de sensor. De rover moet eerst vooruit draaien, dan piepen en draaien. Druk op stop en controleer dat de motoren stoppen en GESTOPT verschijnt. Schakel beide voedingen uit en haal de USB-kabel los voordat je iets aanpast. Draait een kant verkeerd, verwissel dan alleen de twee motordraden van die kant.
- De stopknop is geen noodstop of stroomschakelaar. Bij geen echo stopt de rover; druk opnieuw op start om na controle te proberen.
9. Probeer op de vloer
Gebruik een vlakke vrije binnenvloer met brede kartonnen obstakels en houd ruimte rondom vrij. Blijf bij de rover. Schakel beide voedingen uit als iets klemt. Gebruik geen trappen, randen of zachte of smalle obstakels als test.
Review all connections
1. Connections between "driver" and "Arduino"
2. Connections between "motor_switch" and "Arduino"
3. Connections between "motor_battery" and "Arduino"
4. Connections between "logic_battery" and "Arduino"
5. Connections between "logic_regulator" and "Arduino"
6. Connections between "left_motor" and "Arduino"
7. Connections between "right_motor" and "Arduino"
8. Connections between "sonar" and "Arduino"
9. Connections between "buzzer" and "Arduino"
10. Connections between "start_button" and "Arduino"
11. Connections between "stop_button" and "Arduino"
12. Connections between "display" and "Arduino"
13. Connections between "r_a" and "Arduino"
14. Connections between "r_b" and "Arduino"
15. Connections between "r_c" and "Arduino"
16. Connections between "r_d" and "Arduino"
17. Connections between "r_e" and "Arduino"
18. Connections between "r_f" and "Arduino"
19. Connections between "lcd" and "Arduino"
20. Connections between "contrast" and "Arduino"
21. Connections between "lcd_resistor" and "Arduino"
Deploy the firmware
#include <Arduino.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(11, 12, 13, A2, A4, A5);
int lcdShown=-1;
// ENA en ENB delen PWM D5; de vier IN-pinnen bepalen de richting.
constexpr uint8_t TRIG=2, ECHO=3, PWM_ENABLE=5;
constexpr uint8_t AIN1=7, AIN2=8, BIN1=9, BIN2=10;
constexpr uint8_t START_BTN=A3, STOP_BTN=A0, BUZZER=A1;
constexpr uint8_t SEG_ZERO=6; // a,d,e,f via individual resistors; b,c permanently on
int digitShown=-1;
constexpr int SPEED=255, TURN_SPEED=255;
enum class State {Stopped, Startup, Drive, Pause, Turn, Settle};
State state=State::Stopped;
unsigned long since=0, lastPing=0, buzzerUntil=0;
bool turnLeft=false, prevStart=false, prevStop=false;
void stopMotors(){
analogWrite(PWM_ENABLE,0);
digitalWrite(AIN1,LOW); digitalWrite(AIN2,LOW);
digitalWrite(BIN1,LOW); digitalWrite(BIN2,LOW);
}
void drive(int left,int right){
analogWrite(PWM_ENABLE,0);
digitalWrite(AIN1,left>0); digitalWrite(AIN2,left<0);
digitalWrite(BIN1,right>0); digitalWrite(BIN2,right<0);
analogWrite(PWM_ENABLE,max(abs(left),abs(right)));
}
void enter(State next){state=next; since=millis();}
void showLcd(){
if(lcdShown==static_cast<int>(state))return;
lcdShown=static_cast<int>(state);
lcd.setCursor(0,0); lcd.print(F("MOON ROVER "));
lcd.setCursor(0,1);
switch(state){
case State::Stopped: lcd.print(F("GESTOPT ")); break;
case State::Startup: lcd.print(F("START OVER 5 SEC")); break;
case State::Drive: lcd.print(F("RIJDT ")); break;
case State::Pause: lcd.print(F("OBSTAKEL ")); break;
case State::Turn: lcd.print(F("DRAAIT ")); break;
case State::Settle: lcd.print(F("OPNIEUW METEN ")); break;
}
}
unsigned int distanceCm(){digitalWrite(TRIG,LOW); delayMicroseconds(2); digitalWrite(TRIG,HIGH); delayMicroseconds(10); digitalWrite(TRIG,LOW); unsigned long echo=pulseIn(ECHO,HIGH,25000UL); return (echo<116 || echo>23200)?0:echo/58;}
void beep(){digitalWrite(BUZZER,HIGH); buzzerUntil=millis()+150;}
void setup(){
const uint8_t outputs[]={PWM_ENABLE,AIN1,AIN2,BIN1,BIN2};
for(uint8_t p:outputs){digitalWrite(p,LOW); pinMode(p,OUTPUT);} stopMotors();
pinMode(TRIG,OUTPUT); digitalWrite(TRIG,LOW); pinMode(ECHO,INPUT);
pinMode(START_BTN,INPUT_PULLUP); pinMode(STOP_BTN,INPUT_PULLUP);
digitalWrite(BUZZER,LOW); pinMode(BUZZER,OUTPUT);
digitalWrite(SEG_ZERO,LOW); pinMode(SEG_ZERO,OUTPUT);
lcd.begin(16,2); showLcd();
Serial.begin(115200); Serial.println(F("Stopped. Press START; movement begins after 5 seconds."));
}
void loop(){
unsigned long now=millis();
if(buzzerUntil && (long)(now-buzzerUntil)>=0){digitalWrite(BUZZER,LOW); buzzerUntil=0;}
bool start=digitalRead(START_BTN)==LOW, stop=digitalRead(STOP_BTN)==LOW;
// Stop has priority, even if start is held. Require a new press after stopping.
if(stop){stopMotors(); if(!prevStop) Serial.println(F("Stopped")); enter(State::Stopped); digitalWrite(BUZZER,LOW); buzzerUntil=0;}
else if(start && !prevStart && state==State::Stopped){stopMotors(); enter(State::Startup); Serial.println(F("Starting in 5 seconds"));}
prevStart=start; prevStop=stop;
int digit = state==State::Stopped ? 0 : 1;
if(digit!=digitShown){ digitShown=digit; digitalWrite(SEG_ZERO, digit==0 ? HIGH : LOW); }
showLcd();
switch(state){
case State::Stopped: break;
case State::Startup: if(now-since>=5000)enter(State::Drive); break;
case State::Drive:
if(now-lastPing<80)break; lastPing=now;
{unsigned int cm=distanceCm();
if(cm==0){stopMotors(); enter(State::Stopped); beep(); Serial.println(F("No echo: stopped, press start to retry"));}
else if(cm<=25){stopMotors(); beep(); enter(State::Pause);}
else drive(SPEED,SPEED);
} break;
case State::Pause: if(now-since>=200){turnLeft=!turnLeft; drive(turnLeft?-TURN_SPEED:TURN_SPEED,turnLeft?TURN_SPEED:-TURN_SPEED); enter(State::Turn);} break;
case State::Turn: if(now-since>=450){stopMotors(); enter(State::Settle);} break;
case State::Settle: if(now-since>=250)enter(State::Drive); break;
}
}Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace, diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.




