Build a Robot

Build a Robot


Physical Computing Robot #

Today, we are going to build the first Physical Computing Robot (looking for a better name, if you have any suggestions).

Parts #

You need the following parts:

  • 1 x Chassis
  • 2 x TT Motor
  • 2 x Rear Wheels (can be orange or black)
  • 1 x Caster Wheel
  • 1 x Acrylic base plate (you make this with the laser cutter)
  • 1 x 3D Printed Sensor Mount (you make this with the 3D printer)
  • 1 x Battery Pack (5xAA)
  • 1 x Bag of nuts, bolts, screws and other items
  • 1 x Arduino Uno R4 WiFi
  • 1 x Half-sized Breadboard
  • 1 x Distance Sensor
  • 1 x Qwiic cable for the sensor (100 mm)
  • 1 x L293D H-Bridge (Motor Driver)
  • 1 x LDR (light dependent resistor, light sensor)
  • 1 x 10kΩ Resistor
  • Jumper wires

Robot Parts #

Nuts, Bolts and Other Items #

The bag of nuts, bolts and other items should have the following things:

Nuts and Bolts

  • 2 x Googly Eyes
  • 2 x M4x15 Standoff Screws
  • 3 x M3x20 Standoff Screws
  • 2 x M4x12 Machine Screws
  • 4 x M3x25 Machine Screws
  • 2 x M3x10 Machine Screws
  • 8 x M3x8 Machine Screws (Black)
  • 8 x M3 Nuts
  • 2 x 2x16 Brass Screws

The interactive image below shows what each part is.


Click here to view the accessible version of this interactive content
Please return all of these in the plastic bag inside the kit box at the end of the course.
Except the googly eyes, those you can keep.

Assembly #

1. Distance Sensor #

  • 1 x 3D Printed Sensor Mount (you make this with the 3D printer)
  • 2 x Googly Eyes
  • 2 x M4x15 Standoff Screws
  • 2 x M4x12 Machine Screws
  • 2 x M3x8 Machine Screws
  • 2 x M3 Nuts
  • 1 x Distance Sensor
  • 1 x Qwiic cable for the sensor (100 mm)

Distance Sensor Parts

Distance Sensor Mounted

Distance Sensor Mounted Back

Distance Sensor Standoffs

Distance Sensor Chassis

Distance Sensor Ready

2. Motors #

  • 4 x M3x25 Machine Screws
  • 4 x M3 Nuts

Motors

Motors Back

Feed the wires through the L-shaped holes.

Motors Wires

3. Caster Wheel (Front Wheel) #

  • 1 x Caster Wheel
  • 2 x M3x8 Machine Screws

Caster Wheel

Caster Wheel Mounted

3. Batteries #

  • 1 x Battery Pack (5xAA)
  • 1 x M3x8 Machine Screws

Take one battery out of the battery holder and use one of the black M3x8 screws to attach it to the chassis.

Batteries

Batteries

4. Base Plate + Arduino and Breadboard #

  • 3 x M3x20 Standoff Screws
  • 3 x M3x8 Machine Screws
  • 2 x M3x10 Machine Screws
  • 2 x M3 Nuts
  • 1 x Acrylic base plate (you make this with the laser cutter)
  • 1 x Arduino Uno R4 WiFi
  • 1 x Half-sized Breadboard

Base plate Arduino

Base plate back

When you get this far, change the batteries to fresh ones before attaching the acrylic plate.

Base plate

Base plate attached

5. Wheels #

As a final touch, you can use the brass screws to make sure that the wheels will not fall off. I would recommend doing this only after you have tested your wiring and the code, so that you can easily take off the wheels while testing the motors.

Brass Screws


Circuit #

Distance Sensor #

The distance sensor is connected using the Qwiic cable. See the VL53L1X sensor tutorial for a detailed overview of how the sensor works.

H-Bridge L293D #

L293D Pins

L293D Schematic

L293D Breadboard

Light Sensor #

LDR Schematic

LDR Breadboard


Code #

Motor Test #

Use this code first to test out if the motors and the H-Bridge have been connected properly. Uncomment the functions in the loop() one by one and see if the robot does what your code is telling. If not, you might need to check your wiring.

For example, If your code is saying goForward() and your robot moves backwards, the wires of the motors should be changed to be the opposite (swap the black and red wires on both motors.)

Show the Code
#define MR_EN 5
#define MR_C1 6
#define MR_C2 7

#define ML_EN 9
#define ML_C1 10
#define ML_C2 11

void setup() {
  Serial.begin(115200);

  pinMode(MR_EN, OUTPUT);
  pinMode(MR_C1, OUTPUT);
  pinMode(MR_C2, OUTPUT);

  pinMode(ML_EN, OUTPUT);
  pinMode(ML_C1, OUTPUT);
  pinMode(ML_C2, OUTPUT);

  leftSpeed(255);
  rightSpeed(255);
  stopAll();
}

void loop(){
  // test the motor functions here:
  // leftSpeed(255);
  // rightSpeed(255);
  // goForward();
  // goBackward();
  // goLeft();
  // goRight();
  // stopAll();
  // leftMotorForward();
  // leftMotorBackward();
  // rightMotorForward();
  // rightMotorBackward();
}

void goForward() {
  leftMotorForward();
  rightMotorForward();
}

void goBackward() {
  leftMotorBackward();
  rightMotorBackward();
}

void goLeft() {
  rightMotorForward();
  leftMotorBackward();
}

void goRight() {
  leftMotorForward();
  rightMotorBackward();
}

void stopAll() {
  leftMotorStop();
  rightMotorStop();
}

void leftMotorForward() {
  digitalWrite(ML_C1, HIGH);
  digitalWrite(ML_C2, LOW);
}

void leftMotorBackward() {
  digitalWrite(ML_C1, LOW);
  digitalWrite(ML_C2, HIGH);
}

void leftMotorStop() {
  digitalWrite(ML_C1, LOW);
  digitalWrite(ML_C2, LOW);
}

void rightMotorStop() {
  digitalWrite(MR_C1, LOW);
  digitalWrite(MR_C2, LOW);
}

void rightMotorForward() {
  digitalWrite(MR_C1, HIGH);
  digitalWrite(MR_C2, LOW);
}

void rightMotorBackward() {
  digitalWrite(MR_C1, LOW);
  digitalWrite(MR_C2, HIGH);
}

void leftSpeed(int mSpeed) {
  analogWrite(ML_EN, mSpeed);
}

void rightSpeed(int mSpeed) {
  analogWrite(MR_EN, mSpeed);
}

Final Code #

The final code adds the following:

  • Distance sensor configuration
    • ROI 16x8
    • Continuous reading every 33 ms
  • Distance sensor reading
  • Light Sensor

The region of interest is set in the following way to reduce the amount of issues with the sensor seeing the floor while still keeping as wide as possible view horizontally.

ROI

Show the Code

Note that I have separated the code into two tabs. The second tab motors.ino has all of the functions dealing with the motors.

You can also download the code.

Code Screenshot

#define MR_EN 5
#define MR_C1 6
#define MR_C2 7

#define ML_EN 9
#define ML_C1 10
#define ML_C2 11

#include <Wire.h>
#include <VL53L1X.h>

VL53L1X sensor;
int rawDistance;
int distance;
int sensorStatus;

int light;
int lightThreshold = 800;

void setup() {
  Serial.begin(115200);

  pinMode(MR_EN, OUTPUT);
  pinMode(MR_C1, OUTPUT);
  pinMode(MR_C2, OUTPUT);

  pinMode(ML_EN, OUTPUT);
  pinMode(ML_C1, OUTPUT);
  pinMode(ML_C2, OUTPUT);

  leftSpeed(255);
  rightSpeed(255);
  stopAll();

  // Setup the sensor
  Wire1.begin();
  Wire1.setClock(400000);  // use 400 kHz I2C
  sensor.setBus(&Wire1);
  sensor.setTimeout(500);
  if (!sensor.init()) {
    Serial.println("Failed to detect and initialize sensor!");
    while (1)
      ;
  }

  // ROI settings
  // 195 is the center of the array
  sensor.setROICenter(195);
  int center = sensor.getROICenter();
  Serial.print("ROI center: ");
  Serial.println(center);
  // the smallest size for the ROI is 4x4
  sensor.setROISize(16, 8);

  // Start continuous readings at a rate of one measurement every 33 ms (the
  // inter-measurement period). This period should be at least as long as the
  // timing budget.
  sensor.setDistanceMode(VL53L1X::Long);
  sensor.setMeasurementTimingBudget(33000);  // time is in microseconds
  sensor.startContinuous(33); // time is in milliseconds
}

void loop() {
  readLight();
  readDistance();
  if(light > 400){
    if (rawDistance > 300) {
      goForward();
    } else {
      goLeft();
    }
  }else{
    stopAll();
  }
}

void readLight() {
  light = analogRead(A0);
  Serial.print("light: ");
  Serial.println(light);
}

void readDistance() {
  sensor.read();
  rawDistance = sensor.ranging_data.range_mm;
  sensorStatus = sensor.ranging_data.range_status;

  // only save the reading to distance if the status is valid
  if (sensorStatus == 0 ||sensorStatus == 2 ) {
    distance = rawDistance;
  }

  Serial.print(rawDistance);
  Serial.print(" ");
  Serial.print(sensorStatus);
  Serial.print(" ");
  Serial.print(distance);
  Serial.println();
}
void goForward() {
  leftMotorForward();
  rightMotorForward();
}

void goBackward() {
  leftMotorBackward();
  rightMotorBackward();
}

void goLeft() {
  rightMotorForward();
  leftMotorBackward();
}

void goRight() {
  leftMotorForward();
  rightMotorBackward();
}

void stopAll() {
  leftMotorStop();
  rightMotorStop();
}

void leftMotorForward() {
  digitalWrite(ML_C1, HIGH);
  digitalWrite(ML_C2, LOW);
}

void leftMotorBackward() {
  digitalWrite(ML_C1, LOW);
  digitalWrite(ML_C2, HIGH);
}

void leftMotorStop() {
  digitalWrite(ML_C1, LOW);
  digitalWrite(ML_C2, LOW);
}

void rightMotorStop() {
  digitalWrite(MR_C1, LOW);
  digitalWrite(MR_C2, LOW);
}

void rightMotorForward() {
  digitalWrite(MR_C1, HIGH);
  digitalWrite(MR_C2, LOW);
}

void rightMotorBackward() {
  digitalWrite(MR_C1, LOW);
  digitalWrite(MR_C2, HIGH);
}

void leftSpeed(int mSpeed) {
  analogWrite(ML_EN, mSpeed);
}

void rightSpeed(int mSpeed) {
  analogWrite(MR_EN, mSpeed);
}