Lab 3: ToF Sensors

02.11.2025 - 02.25.2025

Setup

The objective of Lab 3 was to configure the time of flight sensors, which measure distance to aid with obstacle detection and navigation. Lab tasks included soldering components to the Artemis and analyzing data and communication speed.

wiring_diagram

Before beginning the lab, I planned out how I was going to wire the components together, which can be seen in the figure above. I decided to place one ToF sensor on the front of the car, and the other on the side of the car. This would be helpful when detecting obstacles, as this placement would allow the robot to see in front and to the side. Because we are using two ToF sensors, they will have the same I2C address by default. In order to measure data using both of the sensors, I used the XSHUT pin on one of the sensors in order to temporarily shut off one of the sensors and change the I2C address of the other.

Soldering

In this lab, I had to solder a connector to the battery, two QWIIC connectors to the ToF sensors, and the XSHUT pin of one of the sensors to one of the GPIO pins on the Artemis.

Battery

First, I soldered the battery wires to the JST jumper wires. I checked the polarity on the Artemis port to ensure that I was connecting the wires correctly, and then tested the battery by sending BLE data from the Arduino IDE to my computer (using previous lab code).

battery_solder

ToF Sensors

Following my wiring diagram plan, I soldered the ToF sensors to two QWIIC connectors. For the second sensor, I soldered a green wire from the XSHUT pin to pin 6 on the Artemis.

tof_solder

I2C Address

I installed the SparkFun VL53L1X 4m laser distance sensor library in Arduino IDE. Next, I ran Example05_Wire_I2C and found that the address was 0x29. This is different from the address listed in the datasheet, 0x52, because the address is shifted right one bit (0x52 >> 1 = 0x29) to account for the rightmost bit being used to identify if data is being read or written.

imu_setup

Three Modes

The ToF sensors have three modes: short, medium, and long. I looked into the pros and cons of each mode, and made a decision about which mode to use.

Discussion

Short: The short distance mode has a maximum distance of 1.3 meters and is the least susceptible to ambient light. Overall, this mode has greater accuracy and less noise than the other modes.

Long: The long distance mode has a maximum distance of 4 meters but is the most susceptible to ambient light.

Medium: This mode is only available with the Polulu VL53L1X Library, and therefore I did not take this mode into consideration. It has a detection distance between the short and long, and also has noise resistance between short and long.

I chose to use short mode for my robot because 1.3 meters is enough distance to detect obstacles, and the better resistance to noise will be greatly beneficial for when I run the car in different settings.

Testing

To test the ToF sensors at short mode, I taped one of the sensors flat on my laptop and used a tape measure to set up different distances from the wall. I decided to take 10 sensor measurements at six different distances:

tof_10in

10 in (254 mm)

tof_20in

20 in (508 mm)

tof_30in

30 in (762 mm)

tof_40in

40 in (1016 mm)

tof_50in

50 in (1270 mm)

tof_60in

60 in (1524 mm)

To check the accuracy of the sensors, I plotted the average values I calculated against the actual distances, shown below. From the plot, it can be seen that the measured distance has the greatest deviation from the actual distance at 1524 mm, which is outside of the short mode range. I also observed that the measured values were consistently less than the actual values, which could indicate a human error that remained throughout the data measurements. Because the experiment was manually set up, there was a lot of room for error, such as my laptop screen not being exactly aligned with the measuring tape distance due to a small angle deviation.

av_dist_plot

Next, in order to determine repeatability, I took the standard deviations of the measured sensor data and plotted it against the actual distances, shown in the figure below. Similar to the trend in the plotted average measurements, I observed that the standard deviation was its highest at 1524 mm, which is outside of the short mode range. The other standard deviation values remained close to 1.

std_plot

In order to measure ranging time, I took the start and end times at the beginning and end of each iteration of the data collection loop. From one test run, I noted that the ranging time hovered around the 90s (data shown below). These values were higher than I was expecting, which indicated that there was room for optimization within the data collection.

ranging_times

Two Sensors Working

The next task was to modify our code to collect data from both sensors instead of just one. To set this up, I switched between LOW and HIGH to set the address of the first sensor. The code to do this is shown below.

digitalWrite(XSHUT, LOW);
distanceSensor1.setI2CAddress(ADDRESS);
Serial.print("Distance Sensor 1 Address: 0x");
Serial.println(distanceSensor1.getI2CAddress(), HEX);

if (distanceSensor1.begin() != 0) // Begin returns 0 on a good init
{
    Serial.println("Sensor 1 failed to begin. Please check wiring. Freezing...");
    while (1)
        ;
}
distanceSensor1.setDistanceModeShort();
digitalWrite(XSHUT, HIGH);

Serial.print("Distance Sensor 2 Address: 0x");
Serial.println(distanceSensor2.getI2CAddress(), HEX);

if (distanceSensor2.begin() != 0) // Begin returns 0 on a good init
{
    Serial.println("Sensor 2 failed to begin. Please check wiring. Freezing...");
    while (1)
        ;
}
Serial.println("Sensors 1 and 2 online!");
distanceSensor2.setDistanceModeShort();

I also changed the code in the case statement in order to collect data from both sensors instead of just one. I then set up the second ToF sensor, also on my laptop, and collected data to ensure that they were functional. I did this by holding my laptop and rotating it and moving it around near a wall to get varied data.

Sensor Speed

The next task focused on optimizing our code to send data as fast as possible. To speed up my data collection loop, I moved the startRanding(), clearInterrupt(), and stopRanging() functions outside of the loop. My optimized code is shown below:

distanceSensor1.startRanging();
distanceSensor2.startRanging();

int st = millis();

for(int i = 0; i < array_size; i++)
{

    while (!distanceSensor1.checkForDataReady())    {
        delay(1);
    }
    distance1[i] = distanceSensor1.getDistance();

    while (!distanceSensor2.checkForDataReady())    {
        delay(1);
    }
    distance2[i] = distanceSensor2.getDistance();

    times[i] = millis();

}

int et = millis();

distanceSensor1.clearInterrupt();
distanceSensor1.stopRanging();
distanceSensor2.clearInterrupt();
distanceSensor2.stopRanging();

The variables st and et were used for me to check how quickly the loop executed. I ran this implementation, and also measured the time that an empty loop with the same amount of iterations took. As can be seen from the measurements in the photo below, it took 1296 ms to collect 500 sensor readings from each of the sensors (500 iterations of the loop, 1000 total messages). From this measurement, I calculated that it took an average of 2.592 ms per iteration of the loop. This is an immense improvement over the previously measured values of 90s. The increased speed is due to not having to continuously start, clear, and stop ranging.

loop_times

Data Collection

I used this optimized code to send over ToF sensor data to my python notebook and graphed that data over time. I used the same Python code logic as in Lab 2.

tof_vs_time

I also printed out the number of messages sent, as well as the time elapsed. These came out to be 1000 messages in 2783 ms, which is a sampling rate of 359.32 messages/second.

tof_data

I then graphed IMU pitch data using my code from Lab 2, and also printed out all IMU data to analyze the speed.

roll_comp_filter_plot imu_all_data

In comparison to collecting IMU data, the ToF sensors have a much faster sampling rate. Sending IMU data took 6.112 seconds for 1000 messages, which comes out to be a sampling rate of 163.61 messages/second. This could be due to the IMU sending over more data, as I had to send over measurements from the accelerometer, gyroscope, and also the filtered values.

References

I referenced Mikayla Lahr and Nila Narayan's past Lab 3 reports. Furthermore, I used the same hardware and corresponding set up as Sana Chawla (sc2347), but we each implemented our own software.