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:
- 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)
2. Motors #
- 4 x M3x25 Machine Screws
- 4 x M3 Nuts
Feed the wires through the L-shaped holes.
3. Caster Wheel (Front Wheel) #
- 1 x Caster Wheel
- 2 x M3x8 Machine Screws
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.
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
When you get this far, change the batteries to fresh ones before attaching the acrylic plate.
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.
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 #
Light Sensor #
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.
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.
#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);
}