Skip to main content

Lab 04. Distance Measurement

Measuring your robot's position is both one of the most simple and difficult things you can do. This lab is about using sensors to model your robot's position. Recording live data on your robot's position is called telemetry. Figuring out where your robot is on a map is called localization.

A map has many reference points: places that you can measure from. The reference point could be a doorway or a wall. The measurement could be ten paces South from Doorway 1. Localizing yourself would mean finding the doorway on a map, and measuring out ten paces. In the same way that "paces" is a form of measurement full of inaccuracies, robot motion is full of similar errors.

Without external sensors, robots can only refer to themselves for measurement. Using encoders, we can measure how much a wheel has turned. The encoders, as you have seen, have low spatial resolution, which is one source of error. But, there are many other sources of error, such as wheels slipping, or the shape of the tire making the robot wobble.

We will try to both measure the robot's position and localize on a very simple 1D map.


Pre-lab​


Lab​

The point of today's lab is to introduce you to encoders, common errors with localization, and remote telemetry. We'll go through these piece-by-piece, so, as with previous labs, you may choose to split the effort in your group.

1. Add encoders to your robot​

Add two encoders to your robot. They should consist of wheel with holes in it, and sensor module that wraps around it. The encoder wheel should go on the other side of your robot's drive wheel (the one that has a tire). You should have two encoders: one for each wheel.

Wire your encoders and test. You can simply use a digitalRead(pin), the same as with a button read. Think through how you will use the digitalRead to determine the encoder speed.

warning

Your encoder has an analog out and a digital out. You can experiment with it, but the digital out is really all you need.

2. Print accurate telemetry to your Serial Monitor​

Once you have the encoder reliably working, print your telemetry to the Serial Monitor. You should design a good enough Serial Monitor print output that you can debug what's wrong with your robot. Format the output nicely and use good delimiting, e.g., always printing a value after a comma.

Optionally, you might want to start streaming this data to your computer using Processing. Although you technically could copy and paste Serial Monitor output, it's going to be annoying pretty quickly.

For example, your Arduino code could look like this:

const int D1 = 2, D2 = 3;

void setup() {
pinMode(D1, INPUT_PULLUP); // use pullups; pressed/LOW = 0
pinMode(D2, INPUT_PULLUP);
Serial.begin(115200);
}

void loop() {
int v1 = digitalRead(D1); // 0 or 1
int v2 = digitalRead(D2); // 0 or 1
Serial.print(v1); Serial.print(',');
Serial.println(v2); // newline-terminated
delay(5); // ~200 Hz (adjust as needed)
}

And your Processing.org code could look like this:

import processing.serial.*;

Serial port;
PrintWriter out;

void setup() {
println(Serial.list());
String portName = Serial.list()[0]; // <-- change to your port index
port = new Serial(this, portName, 115200);
port.bufferUntil('\n');

String fn = nf(year(),4)+nf(month(),2)+nf(day(),2)+"_"+nf(hour(),2)+nf(minute(),2)+nf(second(),2);
out = createWriter("arduino_log_"+fn+".csv");
out.println("t_ms,d1,d2");
}

void serialEvent(Serial p) {
String line = trim(p.readStringUntil('\n'));
if (line == null || line.length() == 0) return;

String[] parts = split(line, ',');
if (parts.length == 2) {
int d1 = int(parts[0]);
int d2 = int(parts[1]);
out.println(millis()+","+d1+","+d2);
out.flush(); // <--- force write to disk immediately
}
}

void keyPressed() { out.flush(); out.close(); exit(); }
void draw() {}
warning

We do not guarantee that the above code will "just work." These are examplesβ€”you need to design your own logging system.

It is worth spending some time really designing the telemetry and measuring its real-world accuracy. Set up some experiments. For example, you might be tempted to "just" record every tick and the time between ticks, and assume that this will translate directly to wheel distance travelled. And, although the logic makes sense, robots rarely play nicely with logic due to the many errors in the system.

3. Add a photocell to the bottom of your robot​

Following the photocell example from lecture, add a photocell to measure the amount of light that bounces from the floor. Using a piece of white tape or a piece of white paper, create a start and end point. Put the robot overtop of the start point and take note of the photocell reading. Then, put the robot inbetween the start and end point and take note of the photocell reading. These are your calibration points to measure the darkness of the floor.

Using a "threshold filter", i.e., an if statement, create behaviour logic for your robot. You will have to amend this example for your own robot's wiring and your own driving logic:

int threshold = 500;
int photocell = A0;
int state = 0; // 0 means starting state

void setup() {}
void loop() {
int measurement = analogRead(A0);
if (state == 0) {
if (measurement > threshold) {
driveForwards(); // you will have to define this on your own
state = 1;
}
}
if (state == 1) {
stop(); // you will have to define this on your own
}

// TODO: put any other measurement code here
}

Now, design a function that drives your robot from the start point to the end point.

4. Create an experiment to compare telemetry to actual driving conditions (homework)​

Eventually, this robot will have to solve a maze using line-following logic. For this week, you can start practicing by creating an experiment that demonstrates the (un)reliability of the onboard telemetry and sensing.

Using your driving framework from last class, drive your robot from a start position to a goal. Start with a straight line, then add in at least one 90 degree turn. You may experiment with more turns. Use white tape or paper to denote your turns.

The robot should navigate first entirely by "remote control". Drive your robot using the ideal path using keyboard controls. You can set up a Processing sketch to control your robot from your computer. This will look very similar to the code we saw in the first class where you controlled LED brightness using Processing. Your robot should accept driving commands while connected by a wire to your computer.

As a stretch goal (not required), you may consider making this truly remote. Although it will be a few weeks before we discuss how to do this in class, your Arduino R4 has the ability to connect via Bluetooth or Wifi to a computer. If you're getting tired of wires, go wireless. See the Arduino Bluetooth examples here.

Record your driving commands alongside your telemetry. If you "replay" your commands to the robot with the same timing, does the robot actually follow the same path? Why or why not? Come up with a way to characterize the error.

Next, add some sensing using the photocell. Does the robot work better if you add in a sensor? It should, but you will inevitably run into design issues. Be ready to characterize the errors you get from using both telemetry and the photocell next week in lab.

Submit a video on Piazza of your work before next lab, even if you're not happy with the results. People will be interested to know!

Ideas for going above and beyond:

  • A detailed characterization of error with an experiment demonstration
  • A very good and robustly tested telemetry recording process
  • A very good remote driving framework that makes it fun and easy to drive
  • Bluetooth telemetry control (this will be difficult and we haven't taught you it)

As usual, you will be marked on the following scale:

  • 5: Exceptional demonstration of lab concepts (exceeds requirements)
  • 4: Good demonstration of lab concepts (meets requirements)
  • 3: Reasonable demonstration of lab concepts (one or two requirements unclear)
  • 2: Missing one or two lab concepts
  • 1: Missing most lab concepts
  • 0: No attendance/no completion.