The code is listed below. More information about the project is on Codewerkplaats Les 6 (LED-strip en lijnvolger) – CodeKids.
The project uses one ultrasonic sensor. The sensors we tested are from different batches. In the function functieModeUltrasoon() both sensors work. In the function functieModeLijnvolger() only one of the sensors work. When I disable the linesensors the 'bad' sensor still does not work (so there seems not to be any interference between the sensors)
Thanks for everyones help!
// Versie 2024-04-09_1600
// Dit is de code die we gaan gebruiken bij de Codewerkplaats op 12-4-2024
// Geschreven door Chris Dorna, met dank aan Paul van Deelen die me hielp
// bij het oplossen van het probleem dat de rechter motor niet meer bestuurd
// kon worden als de bibliotheek IRremote werd gebruikt.
#include <L298N.h> // We gebruiken de library L298N voor de motordriver
// Dit programma is getest met versie 2.0.3 van deze bibliotheek
#include <IRremote.hpp> // We gebruiken de library IRremote voor de afstandsbediening
// Dit programma is getest met versie 4.3.0 van deze bibliotheek
unsigned long ontvangenCode; // Variabele om code uit afstandsbediening in op te slaan
int gemetenAfstand = 0; // Wordt gebruikt om de afstand in op te slaan
#include <Adafruit_NeoPixel.h> // Bibliotheek voor aansturen LED-strip
// Dit programma is getest met versie 1.12.0 van deze bibliotheek
Adafruit_NeoPixel ledstrip = Adafruit_NeoPixel(8, 12); // 8 pixels op pin 12
unsigned long huidigeMillis = 0; // Om huidige tijd op te slaan
unsigned long vorigeMillis = 0; // Om laatste tijd op te slaan dat de LED werd bijgewerkt
int currentPixel = 0; // Houdt bij welke pixel momenteel is bijgewerkt
int ledstripPatroon = 1;
#define pinLampRechts 6 // Nummer van de pin waarop de koplamp rechts is aangesloten
#define pinLampLinks 7 // Nummer van de pin waarop de koplamp links is aangesloten
#define pinZoemer 8 // Nummer van de pin waarop de zoemer is aangesloten
#define pinSensorLinks 14 // Pinnen van de lijnvolgers
#define pinSensorRechts 15
// Maak L298N-object voor de rechter motor
L298N motorRechts(5, 4, 3); // ENA, IN1, IN2
// Draad van pin 3 naar IN2 is bruin
// Draad van pin 4 naar IN1 is rood
// Draad van pin 5 naar ENA is bruin
// Maak L298N-object voor de linker motor
L298N motorLinks(9, 10, 11); // ENB, IN3, IN4
// Draad van pin 9 naar ENB is bruin
// Draad van pin 10 naar IN4 is rood
// Draad van pin 11 naar IN3 is oranje
boolean modeUltrasoon = false; // Variabele om aan te geven of robotkarretje
// in de mode 'Ultrasoon' moet werken
boolean modeLijnvolger = false; // Variabele om aan te geven of robotkarretje
//in de mode 'Lijnvolger moet werken
int basissnelheidLinks; // omdat de motoren niet allemaal even snel draaien
int basissnelheidRechts; // slaan we de basissnelheid op in deze variabelen
int snelheidLinks; // Variabelen om actuele snelheid van de motoren in
int snelheidRechts; // op te slaan
void setup() {
pinMode(13, OUTPUT); // LED op de Arduino
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
pinMode(pinLampRechts, OUTPUT);
pinMode(pinLampLinks, OUTPUT);
Serial.begin(9600); // Hiermee kunnen we informatie van de Arduino naar de laptop sturen.
// Dit is handig om fouten in het programma op te sporen
Serial.println("Communicatie tussen Arduino en Serial Monitor van IDE gestart");
IrReceiver.begin(2); // Start IR-ontvanger (aangesloten op pin 2)
digitalWrite(pinLampRechts, HIGH); // Koplamp Rechts AAN
digitalWrite(pinLampLinks, HIGH); // Koplamp Links AAN
basissnelheidLinks = 125; // pas één van deze twee aan als een motor sneller
basissnelheidRechts = 125; // draait als de andere
snelheidLinks = basissnelheidLinks;
snelheidRechts = basissnelheidRechts;
motorLinks.setSpeed(snelheidLinks); // Instellen snelheid (kan van 0 tot 255)
motorRechts.setSpeed(snelheidRechts);
ledstrip.begin();
}
void loop() {
if (IrReceiver.decode()) { // Kijken of we een IR-signaal hebben ontvangen
ontvangenCode = IrReceiver.decodedIRData.decodedRawData;
Serial.println("--------------------"); // Stuur informatie naar de laptop,
Serial.print("DEC: "); // dit werkt alleen als de USB-kabel is aangesloten
Serial.println(ontvangenCode); //
if (ontvangenCode != 0) { // != betekent NIET gelijk
switch (ontvangenCode) {
case 3125149440: // Knop CH- [ULTRASOON]
Serial.println("*** Knop CH- ***");
modeUltrasoon = true; // Hiermee zet je de robot in de stand 'Ultrasoon'
modeLijnvolger = false;
break;
case 3108437760: // Knop CH [LIJNVOLGER]
Serial.println("*** Knop CH ***");
modeLijnvolger = true; // Hiermee zet je de robot in de stand 'Lijnvolger'
modeUltrasoon = false;
break;
case 3091726080: // Knop CH+ [Geluid afspelen]
Serial.println("*** Knop CH+ ***");
functieSpeelToon(pinZoemer, 500, 100); // 500 Hz 500 ms
functieSpeelToon(pinZoemer, 750, 100); // 750 Hz 500 ms
functieSpeelToon(pinZoemer, 1000, 100); // 500 Hz 500 ms
functieSpeelToon(pinZoemer, 1250, 100); // 750 Hz 500 ms
break;
case 4077715200: // Knop 1
Serial.println("*** Knop 1 ***");
break;
case 3877175040: // Knop 2 [RECHTDOOR]
Serial.println("*** Knop 2 [RECHTDOOR)] ***");
modeUltrasoon = false;
modeLijnvolger = false;
motorLinks.forward(); // vooruit
motorRechts.forward(); // vooruit
break;
case 2707357440: // Knop 3
Serial.println("*** Knop 3 ***");
break;
case 4144561920: // Knop 4 [LINKS]
Serial.println("*** Knop 4 [LINKS] ***");
modeUltrasoon = false;
modeLijnvolger = false;
motorLinks.stop();
motorRechts.forward(); // vooruit
break;
case 3810328320: // Knop 5 [STOP en RESET]
Serial.println("*** Knop 5 [STOP en RESET] ***");
modeUltrasoon = false;
modeLijnvolger = false;
motorLinks.stop(); // stop
motorRechts.stop(); // stop
snelheidLinks = basissnelheidLinks; // terug naar de basissnelheid
snelheidRechts = basissnelheidRechts;
break;
case 2774204160: // Knop 6 [RECHTS]
Serial.println("*** Knop 6 [RECHTS] ***");
modeUltrasoon = false;
modeLijnvolger = false;
motorLinks.forward(); // vooruit
motorRechts.stop();
break;
case 3175284480: //Knop 7
Serial.println("*** Knop 7 ***");
break;
case 2907897600: //Knop 8 [ACHTERUIT]
Serial.println("*** Knop 8 [ACHTERUIT] ***");
modeUltrasoon = false;
modeLijnvolger = false;
motorLinks.backward(); // achteruit
motorRechts.backward(); // achteruit
break;
case 3041591040: //Knop 9
Serial.println("*** Knop 9 ***");
break;
case 3910598400: //knop 0
Serial.println("*** Knop 0 ***");
break;
case 4127850240: // Knop EQ [LAMPEN AAN/UIT]
Serial.println("*** Knop EQ ***");
// Als de koplampen AAN zijn, gaan ze UIT en andersom
// Eerder hebben we tegen de Arduino gezegd dat de pinnen 6
// (pinLampLinks) en 7 (pinLampRechts) worden gebruikt als OUTPUT.
// met de digitalRead() hieronder kijken we of de lamp AAN of
// UIT is. Met het uitroepteken geef je aan dat de waarde moet
// worden omgekeerd.
// Deze 'omkeertruc'is getest op een Arduino Nano
digitalWrite(pinLampRechts, !digitalRead(pinLampRechts)); // Koplamp Rechts
digitalWrite(pinLampLinks, !digitalRead(pinLampLinks)); // Koplamp Links
break;
case 4161273600: // knop MIN [GA LANGZAMER]
Serial.println("*** Knop MIN ***");
Serial.print("Snelheid Links: ");
Serial.println(snelheidLinks);
Serial.print("Snelheid Rechts: ");
Serial.println(snelheidRechts);
if (snelheidLinks > 25) {
snelheidLinks = snelheidLinks - 25;
motorLinks.setSpeed(snelheidLinks); // Instellen snelheid
motorRechts.setSpeed(snelheidRechts);
motorLinks.forward(); // De nieuwe snelheid wordt pas gebruikt
motorRechts.forward(); // als je opnieuw een opdracht geeft
}
break;
case 3927310080: // knop PLUS [GA SNELLER]
Serial.println("*** Knop PLUS ***");
Serial.print("Snelheid Links: ");
Serial.println(snelheidLinks);
Serial.print("Snelheid Rechts: ");
Serial.println(snelheidRechts);
if (snelheidLinks < 225) {
snelheidLinks = snelheidLinks + 25;
snelheidRechts = snelheidRechts + 25;
motorLinks.setSpeed(snelheidLinks); // Instellen snelheid
motorRechts.setSpeed(snelheidRechts);
motorLinks.forward(); // De nieuwe snelheid wordt pas gebruikt
motorRechts.forward(); // als je opnieuw een opdracht geeft
}
break;
case 3158572800: // knop >|| [LEDSTRIP]
Serial.println("*** knop >|| ***");
ledstripPatroon = ledstripPatroon + 1;
if (ledstripPatroon > 3) {
ledstripPatroon = 0;
}
Serial.print("Patroon: ");
Serial.println(ledstripPatroon);
break;
}
}
IrReceiver.resume(); // IrReceiver weer starten
//(deze stopt nadat deze een code heeft ontvangen)
}
functieLedstrip(ledstripPatroon); // Laat gekozen patroon zien
if (modeUltrasoon == true) {
functieUltrasoon(); // Naar de mode 'Ultrasoon'
}
if (modeLijnvolger == true) {
functieLijnvolger(); // Naar de mode 'Lijnvolger'
}
}
void functieUltrasoon() {
// We beginnen met het meten we de afstand en zetten deze in
// de variabele gemetenAfstand.
gemetenAfstand = functieMeetAfstand(16, 17, 40);
// pin Trigger = 16
// pin Echo = 17
// Maximale afstand = 40
if (gemetenAfstand > 0 && gemetenAfstand < 10) {
// De gemeten afstand is kleiner dan 10 cm
// - De twee is gelijk tekens '==' geven aan dat er twee dingen met
// elkaar worden vergeleken.
// - De twee rechte streepjes '&&', geven EN aan.
functieSpeelToon(pinZoemer, 1000, 500); // Laat een toon horen (1000 Hz, 500 ms)
digitalWrite(13, HIGH); // LED op Arduino AAN
motorLinks.stop(); // motor eerst stoppen vóór je richting omkeert
motorRechts.stop(); // motor eerst stoppen vóór je richting omkeert
motorLinks.backward(); // achteruit
motorRechts.backward(); // achteruit
delay(500);
motorLinks.stop();
delay(500);
motorRechts.stop();
} else {
// De gemeten afstand is groter dan 10 cm
digitalWrite(13, LOW); // LED op Arduino UIT
motorLinks.forward(); // vooruit
motorRechts.forward(); // vooruit
}
}
void functieLijnvolger() {
if ((digitalRead(pinSensorLinks) == LOW) && (digitalRead(pinSensorRechts) == LOW)) {
Serial.println("RECHTDOOR");
// Beide sensors zien zwart (ga rechtdoor)
gemetenAfstand = functieMeetAfstand(16, 17, 40); // Maar we kijken wel eerst of er niets
// in de weg staat. In de functie
// functieMeetAfstand() staat hoe dit werkt.
if (gemetenAfstand > 0 && gemetenAfstand < 10) {
motorLinks.stop(); // stop
motorRechts.stop(); // stop
functieSpeelToon(pinZoemer, 1000, 200); // Laat een toon horen (1000 Hz, 200 ms)
} else {
motorLinks.forward(); // vooruit
motorRechts.forward(); // vooruit
}
} else if ((digitalRead(pinSensorLinks) == HIGH) && (digitalRead(pinSensorRechts) == HIGH)) {
Serial.println("ACHTERUIT");
//Beide sensors zien wit (ga achteruit)
motorLinks.backward(); // achteruit
motorRechts.backward(); // achteruit
} else if (digitalRead(pinSensorLinks) == HIGH) {
Serial.println("NAAR RECHTS");
// Links ziet geen zwarte lijn (ga naar rechts)
motorLinks.forward(); // vooruit
motorRechts.stop(); // stop
} else if (digitalRead(pinSensorRechts) == HIGH) {
Serial.println("NAAR LINKS");
//Rechts ziet geen zwarte lijn (ga naar links)
motorLinks.stop(); // stop
motorRechts.forward(); // vooruit
}
}
void functieLedstrip(int patroon) {
huidigeMillis = millis(); // Hebben we nodig om tijd vast te leggen
if (huidigeMillis - vorigeMillis >= 100) { // 100 milliseconde
vorigeMillis = huidigeMillis; // Sla de laatste update tijd op
// Hieronder stel je bij ledstrip.Color met de laatste drie getallen de kleur in
// (rood, groen, blauw)
// Deze kan je een waarde geven tussen 0 en 255
// Er zitten 8 ledstrip op de strip, deze hebben in het programma de nummers
// 0, 1, 2, 3, 4, 5, 6, 7
switch (patroon) {
// Hier worden de verschillende patronen klaargezet, maar nog niet getoond
case 0: // Alle LED's uit
ledstrip.clear();
break;
case 1: // Opbouwende lichtbalk
ledstrip.setPixelColor(currentPixel, ledstrip.Color(100, 0, 0));
currentPixel = currentPixel + 1;
if (currentPixel >= 9) {
currentPixel = 0; // Begin opnieuw bij de eerste pixel
ledstrip.clear(); // Zet alle pixels uit
}
break;
case 2: // Lopende led
ledstrip.clear(); // Zet alle pixels uit
ledstrip.setPixelColor(currentPixel, ledstrip.Color(100, 0, 0));
currentPixel = currentPixel + 1;
if (currentPixel >= 9) {
currentPixel = 0; // Begin opnieuw bij de eerste pixel
}
break;
case 3: // Van binnen naar buiten
if (currentPixel == 1) {
ledstrip.setPixelColor(3, ledstrip.Color(0, 50, 0));
ledstrip.setPixelColor(4, ledstrip.Color(0, 50, 0));
}
if (currentPixel == 2) {
ledstrip.setPixelColor(2, ledstrip.Color(0, 50, 0));
ledstrip.setPixelColor(5, ledstrip.Color(0, 50, 0));
}
if (currentPixel == 3) {
ledstrip.setPixelColor(1, ledstrip.Color(0, 50, 0));
ledstrip.setPixelColor(6, ledstrip.Color(0, 50, 0));
}
if (currentPixel == 4) {
ledstrip.setPixelColor(0, ledstrip.Color(0, 50, 0));
ledstrip.setPixelColor(7, ledstrip.Color(0, 50, 0));
}
ledstrip.show();
currentPixel = currentPixel + 1;
if (currentPixel >= 8) {
currentPixel = 0; // Begin opnieuw bij de eerste pixel
ledstrip.clear(); // Zet alle pixels uit
}
break;
}
ledstrip.show(); // Laat het patroon zien
}
}
int functieMeetAfstand(int pinTrigger, int pinEcho, int maxAfstand) {
// Deze functie bepaalt de afstand tussen de ultrasoonsensor en een
// obstakel.
// In de Codewerkplaats gaan we niet uitleggen hoe dit werkt en het advies
// is om niet te gaan sleutelen aan deze code.
// Bereken de maximale wachttijd op basis van de maximale afstand
unsigned long maxDuur = (maxAfstand * 2 * 1000000L) / 34300; // in microseconden
// Zorg dat de triggerPin laag is en wacht voor stabiliteit
pinMode(pinTrigger, OUTPUT);
digitalWrite(pinTrigger, LOW);
delayMicroseconds(2);
// Genereer een korte ultrasone puls
digitalWrite(pinTrigger, HIGH);
delayMicroseconds(10); // Ultrasone puls duurt 10 microseconden
digitalWrite(pinTrigger, LOW);
// Zet echoPin als INPUT nadat de puls is verzonden
pinMode(pinEcho, INPUT);
// Meet de duur van de teruggekeerde echo pulse met een time-out op basis van de maximale afstand
long duur = pulseIn(pinEcho, HIGH, maxDuur);
if (duur == 0) {
// Als er geen echo is gedetecteerd binnen de time-out, geef -1 terug
return -1;
}
// Bereken de afstand gebaseerd op de duur van de echo
int afstand = duur * 0.0343 / 2;
return afstand; // Geef de gemeten afstand terug
}
void functieSpeelToon(uint8_t pin, unsigned long frequentie, unsigned int duur) {
// Deze functie is gebaseerd op de bibliotheek TimerFreeTone van Tim Eckel
// (https://bitbucket.org/teckel12/arduino-timer-free-tone/wiki/Home)
// Samen met ChatGPT is de code aangepast voor de Codewerkplaats
// In de Codewerkplaats gaan we niet uitleggen hoe dit werkt en het advies
// is om niet te gaan sleutelen aan deze code
frequentie = 500000 / frequentie; // Bereken de helft van de periode van de vierkante golf (in microseconden).
// Zet pin in uitgangsmodus.
uint8_t pinBit = digitalPinToBitMask(pin);
volatile uint8_t *pinOutput = (uint8_t *)portOutputRegister(digitalPinToPort(pin));
*(uint8_t *)portModeRegister(digitalPinToPort(pin)) |= pinBit;
uint32_t startTime = millis(); // Begintijd van de noot.
while (millis() - startTime < duur) { // Lus voor de duur.
*pinOutput |= pinBit; // Zet pin hoog.
delayMicroseconds(frequentie); // Duur van vierkante golf (hoe lang de pin hoog blijven).
*pinOutput &= ~pinBit; // Zet pin laag.
delayMicroseconds(frequentie); // Duur van vierkante golf (hoe lang de pin laag blijven).
}
}