Lab 3: ToF

Ananya Jajodia

Lab 3: Time of Flight Sensors

This lab explores adding two time of flight sensors to an RC car (Meep). We explore how to handle I2C communication when devices share the same address, the pros and cons of different configuration modes, and the various sensitivities of infared sensors.

Time of Flight Setup

Vehicle Planning

First, we need to chose where we will be placing our ToF sensors on the car (Meep). I chose to place one sensor in the front and one sensor on the right of the car. This will allow Meep to see if there is something in front of it and avoid a collision. At the same time, having a sensor to the right gives potenital for Meep to follow a wall to help it determine if it is drifting in any direction. This also give for potential for maze naviagtion in the future.

The disadvantages of this placement are the sensor will be on the back if the robot flips. For mapping our environment in the future, we would have to spin 270 degrees to get a complete mapping. Meep will also not be able to follow or see obstacles on its left.

car

Soldering and initial testing

We start by soldering the ToF pins to a QWiic connect cable for easy use. As seen in the digram above, the 4 pins of the qwiic connect are soldered to their corresponding pins. Note that red is power, black is ground, blue is SDA (I2C data wire), and yellow is SCL (I2C clock wire).

soldering job battery

By running the Apollo Example05_wire_I2C demo code, we can see the I2C addresses of our devices. The I2C address is the memory location where sensor data will be written on our Artemis as determined by the sensor manufacturer.

i2c address of tof and imu

We can see that the IMU is on 0x69 and that the ToF is on 0x029. An important note is that both ToFs are on the same I2C address by default. This means that the information from the time of flights will conflict and likely corrupt eachother if we allow both to try to write at the same time. We fix this by using the XSHUT pin and the setI2CAddress function. The XSHUT pin allows us to turn on and off the ToF sensors. By keeping one of the ToF sensors off, we can change the I2C address of the other sensor without conflict. We change the I2C address of the second sensor to 0x30 since we see that it is not in use. This allows us to have both sensors on the same I2C bus without conflict.

// Create Objects for both ToF sensors
SFEVL53L1X distanceSensor1(Wire, SHUTDOWN_PIN);
SFEVL53L1X distanceSensor2;

pinMode(SHUTDOWN_PIN, OUTPUT); 
digitalWrite(SHUTDOWN_PIN, LOW); // shut down the sensor so we can change its I2C address
distanceSensor1.setI2CAddress(0x30); // Set an address that won't conflict
digitalWrite(SHUTDOWN_PIN, HIGH); // reboot sensor with new address

For futher testing, I taped both ToFs to a box so that they would be in the same position and facing the same direction. This way, we can compare the data from both sensors to see if they are consistent with eachother.

box with both sensors

Distance Modes

Next, we explore the different distance modes of the ToF sensor. The ToF sensor has three different distance modes: short, medium, and long. Each mode has different accuracy and execution speed. I speficially chose to compare the short and long distance modes. The short distance mode has a range of 0.1m to 1.2m and an accuracy of +/- 1mm. The long distance mode has a range of 0.1m to 4m and an accuracy of +/- 3mm. The short distance mode has an execution time of 20ms while the long distance mode has an execution time of 50ms.

I experiemented with this by setting one sensor to short distance mode and the other sensor to long distance mode. I then moved the sensors backwards slowly and recorded the distance data from both sensors.

long vs short distance modes

As shown, the sensors are very accurate in their respective ranges. The short distance mode is more accurate at close distances while the long distance mode is more accurate at longer distances. As soon as the range is exceeded, the sensors become noisy before spitting out erroneous data. This could be a problem in the future since these erroneous data look like valid data so Meep might think it is close to or colliding with an object when it is not.

The long distance mode is also much slower than the short distance mode. This would be a problem for Meep since it needs to be able to react quickly to its environment.

long vs short distance modes

With this in mind, we expect Meep to only need to see objects that are close to it in order to avoid collisions. Meep can also drive close to walls for mapping in the future. With this in mind, I will be using the short distance mode for both sensors.

Accuracy

Using both sensors, we can determine how accurate the sensors are in short distance mode. I measured the distance from the sensor to a wall using a tape measure and compared it to the distance reported by the sensor. I did this for distances of 0.2m, 0.5m, 0.75m, 1m, and 1.51m. We can see that the sensors output different values for the same distance. This is likely due to a difference in facing angle of the sensor to the wall. Overall, we see the sensors are very accurate with a maximum percent error of 8.57% for sensor 2 at 0.2m. Sensor 1 is more accurate than sensor 2 at all distances. This could be due to a difference in the quality of the sensors or a difference in the facing angle of the sensors to the wall.

Real Value (mm) Sensor 1 (mm) Sensor 2 (mm) Difference Percent Error 1 Percent Error 2
200.0 193.51 217.14 -23.63 -0.0325 0.0857
500.0 494.00 522.64 -28.64 -0.0120 0.04528
750.0 747.37 772.05 -24.68 -0.0035 0.0294
1000.0 994.37 1024.96 -30.59 -0.0056 0.02496
1510.0 1517.00 1548.50 -31.50 0.0046 0.0255
distance measurement setup distance measurement setup

Execution Time

Next, I attempted to see how quickly I could get data from one of the sensors to print to the Serial Monitor. I decided to have the sensor print data as fast as possible and using the built in time stamps on the serial monitor to determine the execution time so that recoding the time would not slow it down. The average time between serial prints was 3.87 ms.

serial monitor times
void loop(void)
{
  if (distanceSensor1.checkForDataReady())
  {
    distance = distanceSensor1.getDistance();

    Serial.print("TOF1: ");
    Serial.print(distance);
    Serial.println();
  }
}

Integration with IMU and Bluetooth

Finally, I integrated the ToF sensors with the IMU and Bluetooth. I created the command SENSOR_START for the Artemis to begin saving and the transmitting the data from the sensors. I then used the SENSOR_STOP command to stop transmitting data. I demonstrate this by sldiing a box with the sensors taped on back and forth in front of a wall. The data is read and saved by a notification handler (see previous labs for more details on this).

The average time bewtween data points was 6.41 ms.

tof readings imu readings
// This function is called in loop when the SENSOR_START command has been sent
void transmit_sensor_data(){
    int dropped_data = 0;
    int j = 0;
    time_stamps[0] = (int) millis();

    for (i = 0; i < TIME_ARR_SIZE; i++) {
        if (myICM.dataReady()) {
          myICM.getAGMT();
          time_stamps[i] = (int) millis();
          roll_readings[i] = roll_calc_accel(&myICM);
          pitch_readings[i] = pitch_calc_accel(&myICM);
          gyro_roll_readings[i] = myICM.gyrX();
          gyro_pitch_readings[i] = myICM.gyrY();
          gyro_pitch_readings[i] = myICM.gyrY();
          gyro_yaw_readings[i] = myICM.gyrZ();
        }
        else{
          dropped_data++;
        }
        if (distanceSensor2.checkForDataReady()) {
          tof2_readings[i] = distanceSensor2.getDistance();
        }
        else{
          tof2_readings[i] = -100;
          dropped_data++;
        }
        if (distanceSensor1.checkForDataReady()) {
          tof1_readings[i] = distanceSensor1.getDistance();
        }
        else{
          tof1_readings[i] = -100;
          dropped_data++;
        }
        read_data(); // check if the SENSOR_STOP command is sent
        if (!sensor_trans){
          break;
        }
    }         
    // Transmit the data when the buffer is full or when the SENSOR_STOP command is sent  
    for (j = 0; j < i; j++) {
        tx_estring_value.clear();
        tx_estring_value.append(time_stamps[j]);
        tx_estring_value.append(":");
        tx_estring_value.append(roll_readings[j]);
        tx_estring_value.append(":");
        tx_estring_value.append(pitch_readings[j]);
        tx_estring_value.append(":");
        tx_estring_value.append(gyro_roll_readings[j]);
        tx_estring_value.append(":");
        tx_estring_value.append(gyro_pitch_readings[j]);
        tx_estring_value.append(":");
        tx_estring_value.append(gyro_yaw_readings[j]);
        tx_estring_value.append(":");
        tx_estring_value.append(tof1_readings[j]);
        tx_estring_value.append(":");
        tx_estring_value.append(tof2_readings[j]);
        tx_estring_value.append(":");
        tx_estring_value.append(dropped_data);
        tx_characteristic_string.writeValue(tx_estring_value.c_str());
    }       
}

5000: IMU Color and Texture Sensitivity

I tested the IMU’s sensitivity to different colors and textures by placing different materials in front of the IMU at 200 mm and taking the average of the measureuments for a set period of time. I found that the IMU was sensitive to different materials but not overly so. I noticed the most discrepancy with the glass door which was expected since the most light passes through it. Suprisingly, the black garbage bag and the black expomarker also performed poorly. This could indicate a sensitivity to black or a sensitivity to the texture of the materials.

Real Value (mm) Surface Sensor 1 (mm) Sensor 2 (mm) Difference Percent Error 1 Percent Error 2
200.0 door White door 193.51 217.14 -23.63 -0.03245 0.0857
200.0 paperPaper 184.36 200.53 -16.17 -0.0782 0.00265
200.0 white wallWhite Wall 193.46 207.47 -14.01 -0.0327 0.03735
200.0 whiteboardWhiteboard 178.97 194.64 -15.67 -0.10515 -0.0268
200.0 expomarkerExpomarker 167.77 191.2 -23.43 -0.16115 -0.044
200.0 orange tapeOrange Tape 178.89 197.8 -18.91 -0.10555 -0.011
200.0 green microfiberGreen Microfiber 183.18 203.14 -19.96 -0.0841 0.0157
200.0 pink polyesterPink Polyester 175.82 199.84 -24.02 -0.1209 -0.0008
200.0 glass doorGlass Door 118.57 188.69 -70.12 -0.40715 -0.05655
200.0 garbage bagGarbage Bag 169.3 190.86 -21.56 -0.1535 -0.0457

5000: Other Infared Sensors

There are two main types of infared distance sensors. The first is like the time of flight we are using, which measures distance based on the time it takes for a light signal to be recieved back after it is emitted. The second type is a triangulation sensor, which measures distance based on the angle of the reflected light signal. The triangulation sensor is more accurate at close distances but time of flight sensors have a longer range. Time of flights also tend to be faster than triangulation sensors. This makes time of flights better for applications where you need to see objects that are farther away or need to react quickly to your environment. Triangulation sensors seem to be best for when you need a very precise measurement of distance at close range.

Collaboration and Sources

I worked with Shao Stassen and Dyllan Hofflich when soldering the ToF sensors. I worked with Shao when gathering data for accuracy. Aiden Derocher’s lab 3 report was also referenced.

Short vs Long Distance Mode information

Infared Sensor Types