Back

Unpredictable Robot

2024

Assignment

The assignment was to create a 'precarious' robot – a robot that, in my interpretation, would exude a sense of uncertainty and unpredictability. To achieve this, I created a robot that is deliberately 'erratic' in its behavior. Using an Arduino, I programmed a small robot where the robot ignores a command with a 70% probability and executes it with a 30% probability. The robot can move in four directions (L, F, B, R) based on commands like 'L5' or 'F2', contributing to its unpredictable and dynamic character.


Code Explanation

Libraries (#include):

    #include <WiFi.h>: This line imports the library needed to connect to a WiFi network. With this, you can connect the Arduino to your home or work network.

    #include <WiFiUdp.h>: This library is needed for UDP (User Datagram Protocol) communication via WiFi. UDP is a protocol for sending messages (packets) that are not guaranteed to arrive, but this makes communication fast.

    #include <Servo.h>: This library controls servo motors. You can use it to position servo motors at specific angles, which then result in a certain speed.

WiFi settings:

const char* ssid = "x";
const char* password = "x";

These lines define the constant strings for the SSID (name) and password of your WiFi network. You need to replace the x with your own network name and password.

Servo objects and pins:

Servo leftServo;
Servo rightServo;
const int leftServoPin = 9;
const int rightServoPin = 10;

Here, objects (leftServo and rightServo) are created from the Servo class. You use these objects to control the servo motors. The pins where the servo motors are connected are also defined.

UDP settings:

WiFiUDP Udp;
unsigned int localPort = 4210;
char incomingPacket[255];

WiFiUDP Udp;: Maakt een object aan voor de UDP-communicatie.

unsigned int localPort = 4210;: Specificeert de poort waarop de Arduino luistert naar UDP-berichten (4210 is een voorbeeld, je kunt dit aanpassen).

char incomingPacket[255];: Maakt een buffer aan om de inkomende berichten op te slaan.

Snelheidsinstellingen:

const int LEFT_FORWARD_SPEED = 0;
const int LEFT_BACKWARD_SPEED = 180;
const int RIGHT_FORWARD_SPEED = 180;
const int RIGHT_BACKWARD_SPEED = 0;
const int STOP_SPEED = 90;

Deze variabelen zijn constanten en definiëren de posities van de servo's die overeenkomen met vooruit, achteruit en stoppen. De exacte getallen kunnen variëren afhankelijk van de servo's die je gebruikt. Je kunt zelf experimenteren wat de juiste standen zijn voor jouw setup. De standen bepalen hoe de servo draait (snelheid en richting).

setup() functie:

void setup() {
  Serial.begin(9600);
  Serial.println("Verbinden met WiFi...");

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  // ... (rest van de setup code)
}

Serial.begin(9600);: Start seriële communicatie voor het printen van debug informatie.

Serial.println("Verbinden met WiFi...");: Print een bericht om aan te geven dat de verbinding met WiFi wordt gestart.

WiFi.begin(ssid, password);: Start de WiFi verbinding met de opgegeven ssid en password.

    while (WiFi.status() != WL_CONNECTED) { ... }: Wacht tot de verbinding tot stand is gebracht.

delay(1000);: Wacht 1 seconde.

Serial.print(".");: Print een punt om te laten zien dat het nog steeds bezig is met verbinden.

Udp.begin(localPort);: Start de UDP server op het lokale poortnummer.

loop() functie:

int packetSize = Udp.parsePacket();
  if (packetSize) {
    int n = Udp.read(incomingPacket, 255);
    if (n > 0) {
      incomingPacket[n] = 0;
    }
    Serial.print("Ontvangen commando: ");
    Serial.println(incomingPacket);

    int packetSize = Udp.parsePacket();: Controleert of er een nieuw pakket is binnengekomen en slaat de grootte ervan op.

    if (packetSize): Als er een pakket is ontvangen.

    int n = Udp.read(incomingPacket, 255);: Leest de data in de buffer.

    if (n > 0) { incomingPacket[n] = 0; }: Voegt een null-terminator (\0) toe aan het einde van de buffer om er een geldige C-string van te maken. Dit is nodig voor functies zoals atoi() die C-strings verwachten.

    Serial.print(...) en Serial.println(...): Print debug informatie.

      
if (incomingPacket[0] == 'V') {
        int duration = atoi(&incomingPacket[1]);
        moveForward(duration);
      // ... (andere commando's)
      }

Hier wordt de ontvangen string gecontroleerd. incomingPacket[0] is de eerste letter die de actie aangeeft (V voor vooruit, A voor achteruit, etc.).

int duration = atoi(&incomingPacket[1]);: De functie atoi() (ASCII to integer) wordt gebruikt om het deel van de string na de eerste letter, die de duur in seconden aangeeft, om te zetten in een getal.

Bewegingsfuncties (moveForward, moveBackward, turnLeft, turnRight):

Deze functies stellen de servo's in op de juiste posities, zodat de robot beweegt of draait in de gewenste richting, voor de gespecificeerde tijd, en roepen vervolgens de stopfunctie aan.

stopMoving() functie:

Deze functie zet beide servo's naar de stop positie en wacht een halve seconde zodat het volledig tot stilstand komt.

Arduino code:

#include <WiFi.h>
#include <WiFiUdp.h>
#include <Servo.h>

// WiFi-instellingen
const char* ssid = "x";
const char* password = "x";

// Maak servo-objecten voor beide servo's
Servo leftServo;
Servo rightServo;

// Definieer de pinnen voor de servo's
const int leftServoPin = 9; // Verander indien nodig
const int rightServoPin = 10; // Verander indien nodig

// UDP-instellingen
WiFiUDP Udp;
unsigned int localPort = 4210;      // Lokale poort waarop de Arduino luistert
char incomingPacket[255];            // Buffer voor inkomende packets

// Snelheidsinstellingen
const int LEFT_FORWARD_SPEED = 0;   // Pas dit aan voor linker servo snelheid
const int LEFT_BACKWARD_SPEED = 180;
const int RIGHT_FORWARD_SPEED = 180; // Pas dit aan voor rechter servo snelheid
const int RIGHT_BACKWARD_SPEED = 0;
const int STOP_SPEED = 90;            // Stoppositie

void setup() {
  Serial.begin(9600);
  Serial.println("Verbinden met WiFi...");

  // Verbind met WiFi-netwerk
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }

  // Verbinding is gemaakt
  Serial.println("\nVerbonden met WiFi!");

  // Toon het IP-adres
  Serial.print("IP-adres: ");
  Serial.println(WiFi.localIP()); // Toon het IP-adres
  Udp.begin(localPort); // Begin met het luisteren naar UDP-pakketten op de lokale poort
  Serial.print("Luisteren op UDP-poort ");
  Serial.println(localPort);

  // Verbind de servo's met hun pinnen
  leftServo.attach(leftServoPin);
  rightServo.attach(rightServoPin);
}

void loop() {
  // Controleer of er een nieuw pakket is ontvangen
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    // Lees het pakket in
    int n = Udp.read(incomingPacket, 255);
    if (n > 0) {
      incomingPacket[n] = 0; // Voeg een null-terminator toe
    }
    Serial.print("Ontvangen commando: ");
    Serial.println(incomingPacket); // Gebruik println om de ontvangen gegevens weer te geven
    
    // Verwerk de ontvangen commando's
    if (incomingPacket[0] == 'V') { // Vooruit
      int duration = atoi(&incomingPacket[1]); // Haal de tijd op
      moveForward(duration);
    } else if (incomingPacket[0] == 'A') { // Achteruit
      int duration = atoi(&incomingPacket[1]); // Haal de tijd op
      moveBackward(duration);
    } else if (incomingPacket[0] == 'L') { // Links draaien
      int duration = atoi(&incomingPacket[1]); // Haal de tijd op
      turnLeft(duration);
    } else if (incomingPacket[0] == 'R') { // Rechts draaien
      int duration = atoi(&incomingPacket[1]); // Haal de tijd op
      turnRight(duration);
    } else {
      Serial.println("Ongeldig commando. Gebruik V, A, L, of R gevolgd door de tijd.");
    }
  }
}

// Functie om vooruit te bewegen
void moveForward(int seconds) {
  leftServo.write(LEFT_FORWARD_SPEED);
  rightServo.write(RIGHT_FORWARD_SPEED);
  delay(seconds * 1000);
  stopMoving();
}

// Functie om achteruit te bewegen
void moveBackward(int seconds) {
  leftServo.write(LEFT_BACKWARD_SPEED);
  rightServo.write(RIGHT_BACKWARD_SPEED);
  delay(seconds * 1000);
  stopMoving();
}

// Functie om links te draaien
void turnLeft(int seconds) {
  leftServo.write(LEFT_BACKWARD_SPEED);
  rightServo.write(RIGHT_FORWARD_SPEED);
  delay(seconds * 1000);
  stopMoving();
}

// Functie om rechts te draaien
void turnRight(int seconds) {
  leftServo.write(LEFT_FORWARD_SPEED);
  rightServo.write(RIGHT_BACKWARD_SPEED);
  delay(seconds * 1000);
  stopMoving();
}

// Functie om te stoppen
void stopMoving() {
  leftServo.write(STOP_SPEED);
  rightServo.write(STOP_SPEED);
  delay(500);
}
;

Code om de commando's uit te voeren:

import socket

# Vervang dit door het IP-adres van je Arduino
UDP_IP = "....."  
UDP_PORT = 4210

# Maak een UDP-socket aan
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:
    command = input("Voer een commando in (bijv. 'V2' voor vooruit 2 seconden, 'A2' voor achteruit 2 seconden): ")
    if command:  # Zorg ervoor dat er een invoer is
        sock.sendto(command.encode(), (UDP_IP, UDP_PORT))
        print(f"Verzonden commando: {command}")

Videos: