Robopost Les 3 – Programmeren

25 juni 2025

l

Yilmaz Tamer

Onderdeel van de lessenserie: RoboPost – Bouw je eigen slimme postmelder
Voor wie: MBO Techniek/ICT studenten (niveau 3/4) – beginnersniveau
Tijdsduur: ± 45 minuten

Aansluiting op eerdere lessen

In Les 1 heb je geleerd hoe je met een Arduino, breadboard en LEDs een schakeling bouwt. In Les 2 heb je hier een drukknop en afstandssensor aan toegevoegd, en heb je geleerd waarom weerstanden nodig zijn.
Misschien heb je toen al met code gewerkt – maar hoe werkt die code eigenlijk?

In deze les gaan we de gebruikte code van Les 2 stap voor stap uitleggen én zelf programmeren.

Leerdoelen

Na deze les kun jij als student:

  • Uitleggen wat een Arduino sketch is en waar deze uit bestaat
  • Het verschil begrijpen tussen setup() en loop()
  • Digitale input en output toepassen via digitalRead() en digitalWrite()
  • If-else gebruiken om eenvoudige logica te programmeren
  • De seriële monitor gebruiken om waarden te controleren
  • Simpele programmeerfouten herkennen en oplossen

Wat is een sketch?

Een sketch is het programma dat je schrijft in de Arduino IDE. Elke sketch bestaat altijd uit:

void setup() {
  // Hier zet je alles klaar
}

void loop() {
  // Hier herhaalt alles zich
}

Wat gebeurt er precies?

  • setup(): wordt één keer uitgevoerd zodra je Arduino start.
  • loop(): wordt eindeloos herhaald zolang de Arduino aan staat.

Voorbeeld uit Les 2: Knop en LED

Dit was een stukje code uit Les 2:

int knopPin = 7;
int ledPin = 9;

void setup() {
  pinMode(knopPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  int knopStatus = digitalRead(knopPin);

  if (knopStatus == LOW) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }
}

Wat gebeurt hier?

  • De knop zit op pin 7, en is verbonden met GND.
  • Omdat we INPUT_PULLUP gebruiken, is de waarde normaal HIGH.
  • Als je drukt, wordt het LOW → de LED gaat aan.

Let op: in Les 2 heb je deze code misschien al gekopieerd. In deze les gaan we begrijpen hoe en waarom het werkt.

Uitleg: variabelen

Een variabele is een plek waarin je gegevens opslaat, zoals de status van een knop.

int knopStatus = digitalRead(knopPin);
  • int is een variabele (geheel getal).
  • De Arduino gebruikt int om bijvoorbeeld te onthouden of een knop aan (1) of uit (0) is.
  • Hiermee sla je de waarde op die je in een later if-statement gebruikt.

Seriële monitor gebruiken

Via de seriële monitor kun je zien wat je Arduino “ziet”:

void setup() {
  Serial.begin(9600); // start communicatie
}

void loop() {
  int knop = digitalRead(7);
  Serial.println(knop); // toont 1 of 0
}

Open de seriële monitor via het vergrootglas rechtsboven in de Arduino IDE. Zo kun je checken of je knop werkt. De seriële monitor is je digitale ‘oog’ om te zien wat de Arduino meet of doet. Als iets niet werkt, is dit het eerste wat je opent.

Opdracht: Begrijp de code van de sensor (Les 2)

In Les 2 gebruikte je deze regel om de afstand te meten:

long duur = pulseIn(echoPin, HIGH, 30000);
float afstand = duur * 0.034 / 2;

Maar wat betekent dat?

De getallen in de formule zijn gebaseerd op de snelheid van geluid (343 m/s). Vandaar de 0.034 in de berekening.

  • pulseIn() meet hoe lang een echo-signaal onderweg is.
  • Daarmee bereken je de afstand in cm.
  • Deze formule gebruikten we in Les 2 al. Je hoeft hem nog niet volledig te snappen – in Les 4 gaan we dit uitgebreider bespreken.

RoboPost Basislogica: van schakeling naar code

In Les 1 en 2 heb je stap voor stap de schakeling gebouwd:

  • 2 LED’s → geven status aan (post gezien / in beweging)
  • Sensor 1 → detecteert post (start)
  • Sensor 2 → detecteert aankomst postbak (stop)
  • Drukknop → bevestigt dat je post wilt ontvangen
  • DC-motor met H-brug → beweegt de postbak

In deze les programmeren we de logica van dat systeem.

We gebruiken nog niet alle onderdelen (Sensor 3 komt in Les 4), maar wél al het grootste deel van de schakeling.

Opdracht 2 – RoboPost-basisscript

Wat deze code doet:

  • LED’s gaan aan bij postdetectie via Sensor1
  • Druk op knop(leds uit) → motor draait vooruit
  • Sensor 2 detecteert aankomst → motor stopt
  • Korte pauze → motor draait achteruit
  • Daarna weer standby

Let op: Deze uitgebreide code hoef je nog niet volledig te begrijpen. In deze les kijk je naar de opbouw, in Les 4 leer je hoe je deze test en debugt.

/* ─────────────────────────────────────────────────────────────
   2× HC-SR04  •  2 LED’s  •  Drukknop  •  L293D  •  DC-motor
   Debug-editie 2025-06-26
───────────────────────────────────────────────────────────────
   Sensor 1  Trig → D4   | Echo → D3
   Sensor 2  Trig → D12  | Echo → D11
   LEDs      LED1 → D9   | LED2 → D8
   Drukknop  → D7  (naar GND, INPUT_PULLUP)

   L293D  Enable1 → D5   IN1 → D6   IN2 → D10
──────────────────────────────────────────────────────────────*/

const int trig1 = 4,  echo1 = 3;        // HC-SR04 #1
const int trig2 = 12, echo2 = 11;       // HC-SR04 #2

const int led1  = 9,  led2  = 8;
const int knop  = 7;                    // drukknop (INPUT_PULLUP)

// L293D
const int en1 = 5, in1 = 6, in2 = 10;

// Instellingen
const int  drempel1   = 20;             // cm – LED-trigger
const int  drempel2   = 10;             // cm – stop-trigger
const unsigned long wachttijd = 10000;  // ms – pauze vóór terug
const unsigned long terugTijd = 2000;   // ms – duur achteruit
const unsigned long fwdTimeout = 8000;  // ms – failsafe vooruit

// Status-flags
bool ledsAan = false, motorFwd = false, motorRev = false;
unsigned long timer = 0;                // algemeen timer
unsigned long motorFwdStart = 0;        // starttijd vooruit

void setup() {
  pinMode(trig1, OUTPUT);  pinMode(echo1, INPUT);
  pinMode(trig2, OUTPUT);  pinMode(echo2, INPUT);

  pinMode(led1, OUTPUT);   pinMode(led2, OUTPUT);
  pinMode(knop, INPUT_PULLUP);

  pinMode(en1, OUTPUT); pinMode(in1, OUTPUT); pinMode(in2, OUTPUT);
  digitalWrite(en1, LOW);

  Serial.begin(9600);
  Serial.println(F("\n--- RoboPost debug-sketch gestart ---"));
}

void loop() {
  // 60 ms rust tussen metingen → ~16 Hz
  static unsigned long meetTijd = 0;
  if (millis() - meetTijd < 60) return;
  meetTijd = millis();

  // 1) Afstanden meten
  float d1 = meetAfstand(trig1, echo1);
  float d2 = meetAfstand(trig2, echo2);

  Serial.print(F("d1=")); Serial.print(d1, 1);
  Serial.print(F(" cm  |  d2=")); Serial.print(d2, 1);
  Serial.println(F(" cm"));

  /* ── Fase-overgangen ────────────────────────────────────── */

  // A. Sensor 1 → LED’s aan
  if (d1 > 0 && d1 <= drempel1 && !motorFwd && !motorRev && !ledsAan) {
    digitalWrite(led1, HIGH); digitalWrite(led2, HIGH);
    ledsAan = true;
    Serial.println(F("Sensor 1 gezien → LED’s AAN"));
  }

  // B. Knop ingedrukt → motor vooruit
  if (digitalRead(knop) == LOW && ledsAan && !motorFwd) {
    digitalWrite(led1, LOW); digitalWrite(led2, LOW);
    ledsAan = false;
    motorFwd = true;
    motorFwdStart = millis();
    setMotorVooruit(true);              // rechtsom
    Serial.println(F("Knop! → Motor VOORUIT"));
  }

  // C. Sensor 2 → motor stopt
  if (motorFwd && d2 > 0 && d2 <= drempel2) {
    setMotorVooruit(false);
    motorFwd = false;
    timer = millis();                  // start wachttijd
    Serial.println(F("Sensor 2 geraakt → Motor STOP"));
  }

  // D. Fail-safe: motor te lang vooruit
  if (motorFwd && millis() - motorFwdStart > fwdTimeout) {
    setMotorVooruit(false);
    motorFwd = false;
    timer = millis();
    Serial.println(F("! FAILSAFE: motorFwd te lang → STOP"));
  }

  // E. Wachttijd voorbij → motor achteruit
  if (!motorFwd && !motorRev && timer && millis() - timer >= wachttijd) {
    motorRev = true;
    timer = millis();                  // start terug-timer
    setMotorAchteruit(true);           // linksom
    Serial.println(F("10 s voorbij → Motor ACHTERUIT"));
  }

  // F. Terugruit klaar
  if (motorRev && millis() - timer >= terugTijd) {
    setMotorAchteruit(false);
    motorRev = false;
    timer = 0;
    Serial.println(F("Motor achteruit KLAAR → systeem reset"));
  }
}

/* ───────── helpers ───────── */

float meetAfstand(int trig, int echo) {
  // maximaal 3 pogingen → reduceert valse '-1' waarden
  for (uint8_t i = 0; i < 3; i++) {
    digitalWrite(trig, LOW); delayMicroseconds(2);
    digitalWrite(trig, HIGH); delayMicroseconds(10);
    digitalWrite(trig, LOW);
    long us = pulseIn(echo, HIGH, 30000);  // timeout 30 ms ~ 5 m
    if (us > 0) return us * 0.0343f / 2.0f;
  }
  return -1.0f;                          // geen echo
}

/* Motor rechtsom (vooruit) */
void setMotorVooruit(bool aan) {
  digitalWrite(in1, LOW);                // IN1 LOW
  digitalWrite(in2, HIGH);               // IN2 HIGH
  digitalWrite(en1, aan ? HIGH : LOW);
}

/* Motor linksom (achteruit) */
void setMotorAchteruit(bool aan) {
  digitalWrite(in1, HIGH);               // IN1 HIGH
  digitalWrite(in2, LOW);                // IN2 LOW
  digitalWrite(en1, aan ? HIGH : LOW);
}
Reflectievragen
  • Wat is het verschil tussen digitalRead() en digitalWrite()?
  • Waarom gebruik je een if-statement in de loop()?
  • Wat doet INPUT_PULLUP precies?
  • Wat zie je gebeuren in de seriële monitor als je de knop indrukt?
  • Probeer de if om te keren: laat de LED aangaan als de knop niet wordt ingedrukt. Wat verandert er in de code?

Noteer je antwoorden of bespreek ze met een klasgenoot.

Vooruitblik op Les 4 – Testen & Fouten Oplossen

In de volgende les leer je:

  • Hoe je systematisch test of je schakeling goed werkt
  • Wat je kunt doen als een LED of knop niet reageert
  • Hoe je fouten opspoort in je code (debuggen)
  • Hoe je de seriële monitor gebruikt bij foutopsporing

Kun jij alvast bedenken wat je moet controleren als je knop wél stroom krijgt, maar je LED niets doet?

Geschreven door Yilmaz Tamer

Comments

0 reacties

Een reactie versturen

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *