Inleiding

Tijdens een bezoek aan Technolopis ontdekte onze zoon Arjen, 5 jaar, de Bee Bot. Een zeer eenvoudige, programmeerbare, zelf-rijdende robot.

Via enkele knoppen kan deze robot geprogrammeerd worden om rond te rijden: rechtdoor, rechts/links draaien,… Op die manier kunnen kinderen eenvoudig leren om via elementaire ruimtelijke instructies de robot een parcours af te laten leggen.

Je kan deze bots kopen, voor ongeveer 80 euro, maar… je kan dit ook vrij eenvoudig zelf maken. Er bestaan zelfs veel kits van gelijkaardige robots, maar… je kan dit ook vrij eenvoudig zelf maken :-)

Dit project is bedoeld om te tonen hoe je dit kan doen en hoe je dus naast veel plezier met de robot zelf, ook heel veel plezier kan hebben om te leren hoe je dit zelf kan bouwen.

Er zijn verschillende aspecten aan: enerzijds de constructie van de robot en anderzijds de programmatie om hem echt tot leven te brengen.

Deze pagina vertelt het verhaal. De bijhorende repository bevat alle design bestanden en software om deze robot te bouwen.

Versie 1

A-Bot

Versie 1 zag het levenslicht op 10 april 2017, één dag voor de 6e verjaardag van Arjen :-)

Belangrijk : Versie 1 is zeker niet de finale versie van dit project ;-) Versie 1 is duidelijk een eerste versie waar we onze eerste ideeën getest en samengebracht hebben tot een eerste werkend geheel. Sommige van die ideeën bleken goed te zijn, andere wat minder. Met die wetenschap werken we nu verder naar versie 2. Ook de notities op deze pagina zijn voorlopig een snel samenraapsel van verschillende aspecten en kunnen nog wat liefde gebruiken. Ook deze worden nog verder uitgewerkt tot volledige en gedetailleerde instructies.

Onderdelen

Voor de eerste versie van de A-Bot vertrekken we van een Particle Photon. Dit is een Arduino-achtige microcontroller met WiFi en een fantastisch online platform om er mee te werken.

Als aandrijving vertrekken we van een paar eenvoudige DC motoren. Om deze makkelijk aan te sturen, gebruiken we een bijkomende chip: de L293DNE. Om de motoren iets beter te kunnen controleren, voegen we ook een encoder toe.

Een balwiel, enkele knoppen en een batterijbox, maken onze onderdelen lijst compleet.

Chassis Design

Om al deze onderdelen samen te brengen tot een robotje, snijden we uit hout (of plexi) enkele delen met behulp van een laser cutter:

Design

Design

In één van de vele hacker- en makerspaces, vind je zeker iemand die je kan helpen om de stukken te laser cutten.

De aller eerste stap bestaat uit het controleren dat we onze centrale verwerkingseenheid, de Particle Photon kunnen aanspreken en programmeren. Dit doen we met een klein programmaatje dat de ingebouwde blauwe LED van de Photon laat pinken. Dé manier voor onze Photon om te zeggen “Hallo Wereld, ik ben er klaar voor!”.

Voor je aan de slag kan met je Photon, moet je deze registreren bij je eigen Particle account. De Particle documentatie is uitgebreid en volledig, maar ook in het Engels. We proberen weldra een eigen Knutselba(a)r pagina te maken omtrent de Photon en hoe je er mee aan de slag gaat.

Alle software kan op een Unix-achtige machine, zoals Linux of macOS, aangestuurd worden via Makefiles. Deze automatiseren enkele commando’s om de software op de juiste manier te compileren en naar de Photon te versturen. We proberen dit weldra voor Windows gebruikers ook wat aangenamer te maken.

De code die hiervoor nodig is, is uiterst eenvoudig, maar is zo essentieel dat we alles later ook nodig zullen hebben voor het grotere werk:

#define LED    D7      // dit is de standaard led die op pin D7 verbonden is

void setup() {
  // configureer de LED pin voor uitvoer
  pinMode(LED, OUTPUT);
}

void loop() {
  digitalWrite(LED, HIGH);   // zet LED pin hoog
  delay(1000);               // wacht voor 1000ms = 1 sec
  digitalWrite(LED, LOW);    // zet LED pin laag
  delay(1000);               // en wacht opnieuw 1 sec
}

Drie belangrijke dingen gebeuren hier:

  1. We definiëren welke pin we gaan gebruiken om stroom naartoe te sturen. Elke actie op een microcontroller, dus ook het laten branden van een LED, bestaat feitelijk uit het doorlaten van stroom naar één van de pinnen die aangesloten zijn op de chip. In dit geval hebben de mensen van Particle zelf al een LED aangesloten op pin D7.
  2. We configureren de pin als een uitvoer pin (OUTPUT). Bijna alle pinnen van de Photon kunnen gebruikt worden om zowel stroom naar buiten te sturen, als te meten of er stroom naar binnen kan vloeien. In dit geval willen we stroom naar buiten sturen.
  3. We zetten de pin tot slot HIGH of LOW. Elektrische stroom vloeit van een “hoge” potentiaal, naar een “lage” potentiaal. Er bestaat een zgn. spanning tussen twee plaatsen met verschillende potentiaal. Als we de pin dus “hoog” zetten, zal er stroom naar buiten kunnen vloeien en sturen we dus stroom door de LED, die daarom gaat branden. Omgekeerd zal een “lage” pin geen stroom door de LED laten en zal deze dus niet branden.

Vanuit de src/ directory van de repository gaan we aan de slag:

$ PROJECT=blink make
*** Compileren en flashen van blink
particle flash 370026000447333436363331 blink
Including:
    /Users/xtof/Workspace/knutselbaar/a-bot/src/blink/blink.ino
attempting to flash firmware to your device 370026000447333436363331
Flash device OK:  Update started

Als de blauwe LED blinkt: proficiat. Nu kunnen we aan het echte werk beginnen :-)

Motor

Het belangrijkste zijn natuurlijk de motoren, dus laat ons daar maar mee beginnen.

Design

Design

De batterijen voorzien de opstelling van iets meer dan 5V. Hiermee wordt (via de rode draden) enerzijds de Photon van stroom voorzien, als ook de L293D.

De L293D wordt aangestuurd met drie draden per motor: 2 draden dienen om de draai-richting aan te geven (oranje) en 1 draad om de snelheid te bepalen (blauw).

De twee draden waarmee we de draai-richting kunnen aangeven, kunnen samen 4 verschillende situaties aangeven: stilstaan, linksom draaien, rechtsom draaien en remmen.

In de software zie je één functie die alle logica bevat om een motor aan te sturen:

void motor_update(int16_t snelheid) {
  // houd snelheid binnen grenzen
  if(abs(snelheid) < MIN_SNELHEID) { snelheid = 0; }
  if(abs(snelheid) > MAX_SNELHEID) {
    snelheid = MAX_SNELHEID * (snelheid/abs(snelheid));
  }

  // bepaal draairichting
  if(snelheid == 0) {
    // stop
    digitalWrite(MOTOR1_1A, LOW);
    digitalWrite(MOTOR1_2A, LOW);
  } else if(snelheid < 0) {
    // achterwaarts
    digitalWrite(MOTOR1_1A, HIGH);
    digitalWrite(MOTOR1_2A, LOW);
  } else {
    // voorwaarts
    digitalWrite(MOTOR1_1A, LOW);
    digitalWrite(MOTOR1_2A, HIGH);
  }
  // PWM
  analogWrite(MOTOR1_EN, abs(snelheid));
}

Vanuit de src/ folder, geef je weer het commando make:

$ PROJECT=motor make
*** Compileren en flashen van motor
particle flash 370026000447333436363331 motor
Including:
    /Users/xtof/Workspace/knutselbaar/a-bot/src/motor/motor.ino
attempting to flash firmware to your device 370026000447333436363331
Flash device OK:  Update started
*** Start van console uitvoer. Beëindig met 'Ctrl+a k y'.
    Druk op een toets om verder te gaan...

Encoder

We bouwen voort op het voorbeeld voor de motor. Op de wiki van DFRobot vind je informatie hoe je de encoder op de motor kan aansluiten.

De gebruikte motoren verschillen echter een beetje en vragen wat knutselwerk. De opstelling van het chassis laat echter toe om de encoder op de vertikale steunen te bevestigen nadat de motoren langs de andere kant van de steun bevestigd is.

(foto’s volgen)

Een encoder bestaat uit een getand wieltje en een lichtsensor. Wanneer het wieltje met de as van de motor ronddraait zullen de tandjes het licht afwisselend doorlaten of tegenhouden. De encoder vraagt een 5V voeding en geeft een digitaal signaal terug dat aangeeft of de encoder licht detecteert of niet. Zo kunnen we het aantal tandjes dat ronddraaien tellen.

In software moeten we nu een ander belangrijk aspect van microcontrollers gebruiken: interrupts:

#define ENCODER D2

void setup() {
  attachInterrupt(ENCODER, encoder_verandering, CHANGE);
}

volatile uint16_t stappen = 0;

void encoder_verandering() {
  stappen++;
}

We weten al dat we langs de pinnen van de microcontroller stroom kunnen laten vloeien. We kunnen ook detecteren of er stroom langs kan vloeien. Interrupts, of onderbrekingen laten ons toe om zonder zelf heel de tijd te kijken naar de staat van een (invoer) pin, te weten wanneer een pin verandert van hoog naar laag of omgekeerd.

In de setup functie vragen we om bij wijzigingen (CHANGE) aan de ENCODER (D2) pin, de functie encoder_verandering op te roepen. Daarin verhogen we een variabele, zodat we feitelijk tellen hoeveel tandjes van de encoder er doorgedraaid zijn.

Het is belangrijk om de stappen variabele als volatile te definiëren, anders kan het wel eens goed fout lopen, omdat de compiler kan denken dat de variabele feitelijk niet gebruikt wordt en deze stilletjes gewoon weggooit ;-)

Vanuit de src/ folder, geef je het commando make:

$ PROJECT=encoder make
*** Compileren en flashen van encoder
particle flash 2b002f001147333439313830 encoder
Including:
    encoder/encoder.ino
attempting to flash firmware to your device 2b002f001147333439313830
Flash device OK:  Update started
*** Start van console uitvoer. Beëindig met 'Ctrl+a k y'.
    Druk op een toets om verder te gaan...

Op de console toont de applicatie telkens het aantal stappen dat geteld werd gedurende 2 seconden.

Keypad

We zouden kunnen werken met een vijftal knoppen, maar dit Gravity keypad heeft alles aan boord en vraagt maar 1 pin om de 5 knoppen te kunnen onderscheiden.

Het keypad wordt aangesloten met drie draden: 2 daarvan dienen voor de stroomvoorziening en de derde geeft een signaal terug dat aangeeft welke knop ingeduwd wordt.

Volgens de documentatie van het keypad, werkt dit op 5V. De Photon wordt wel gevoed met 5V, maar werkt voor de rest hoofdzakelijk op 3.3V. Als we naar de samenstelling van het keypad kijken, zien we dat de knoppen met verschillende weerstanden zorgen voor verschillende spanningen over de uitgaande, derde draad.

Voor dit voorbeeld, sluiten we het keypad dus aan op pinnen 3.3V, GND en A4.

In de code bevindt zich 1 functie die de uitgaande spanning van het keypad leest en omzet tot een numerieke aanduiding voor de ingedrukte knop:

#define KNOPPEN A4

uint8_t lees_knoppen() {
  int invoer = 4095 - analogRead(KNOPPEN);
  if(invoer < 200) { return 0; }
  if(invoer < 300) { return 5; }
  if(invoer < 500) { return 4; }
  if(invoer < 645) { return 1; }
  if(invoer < 675) { return 3; }
  if(invoer < 800) { return 2; }
  return 0; // geen knop
}

Vanuit de src/ folder, geef je het commando make:

$ PROJECT=keypad make
*** Compileren en flashen van keypad
particle flash 2b002f001147333439313830 keypad
Including:
    keypad/keypad.ino
attempting to flash firmware to your device 2b002f001147333439313830
Flash device OK:  Update started
*** Start van console uitvoer. Beëindig met 'Ctrl+a k y'.
    Druk op een toets om verder te gaan...

Op de console toont de applicatie de knoppen die ingedrukt worden.

A-Bot

Als we nu 2 motoren, 2 encoders en 1 keypad samenbrengen en zelf eventueel een gaatjesprint maken, bekom je de volledige electronica die je nodig hebt:

A-Bot PCB

A-Bot PCB layout

Als je andere pinnen van de Photon gebruikt, kan je dit in config.h configureren.

Vanuit de src/ folder, geef je het commando make:

$ PROJECT=a-bot make
*** Compileren en flashen van a-bot
particle flash 2b002f001147333439313830 a-bot
Including:
    a-bot/config.h
    a-bot/a-bot.ino
attempting to flash firmware to your device 2b002f001147333439313830
Flash device OK:  Update started
*** Start van console uitvoer. Beëindig met 'Ctrl+a k y'.
    Druk op een toets om verder te gaan...

Het resultaat

De eerste versie van de A-Bot rijdt en volgt de bevelen van zijn eerste meester/programmeur, Arjen, fijntjes op. Dankzij de encoders worden verschillen in de snelheid tussen de twee wielen redelijk goed opgevangen, maar voorlopig nog iets te eenvoudig, waardoor de resultaten niet altijd even nauwkeurig zijn.

Voor de volgende versie gaan we daarom o.a. kijken hoe we een heuse PID controller introduceren.

Wordt vervolgd…