Lab 03

Objective

The goal of this lab was to connect the Artemis board to two VL53L1X Time-of-Flight Distance Sensors. This involved soldering wires to the ToF (Touch-of-Flight) sensors and connecting the sensors to the Artemis board by headers and a QWIIC breakout board. Distance sensors will allow our robot to detect and react to obstacles in future tasks.

Prelab

The user manual and datasheet of the VL53L1X were studied prior to the lab. There are a few decisions to decide upon regarding the ToF sensors:

  • The final robot will use two ToF sensors, but since the address of the sensor is hardwired on the Artemis board, the two sensors can not be addressed individually without some changes. Possible solutions include changing the address by programming or enabling the sensors seperately by their shutdown pins. I chose to solve the issue by changing the address of the second ToF sensor so that the sensors could be used in parallel without being turned on and off. This method required soldering an extra connection from the shutdown pin of the ToF sensor to the I/O outputs of the Artemis board so that the addresses could be changed during setup.
  • The placement of the ToF sensors can change the robots effective field of vision by fusing readings from both sensors. Since the robot tends to move forward, at least one ToF sensor should probably be at the front of the robot. However, the second ToF sensor can placed be on the side of the robot, which would allow a large field of vision on one side of the robot but not the other side. Another possible arrangement is placing both sensors on the front of the robot, one of the left and one on the right. This would allow a wild frontal field of vision as well as more accurate distance readings where the sensors overlap. You can even put a sensor on the back of the robot, which would improve vision of the robot after it flips 180 degrees. These various configurations are optimal depending on the task at hand.
  • In order to keep the placement of the sensors flexible, long wires were soldered to the ToF sensors so their arrangement could be swapped around when the robot is built. The wires attached to the ToF sensor can be permanently soldered. However, the connection between the ToF sensors and the Artemis board is kept detachable using a breakout board so that the sensors to be attached and reattached as desired, in case bugfixing or rearrangement is needed. The wires were soldered on the side of the board opposite of the actual sensor because the sensors will face outwards while the wires should be kept inside the robot chassis.

Connecting the Sensors

The first task was to solder a connection between the two ToF sensors and the Artemis board. The red wire was soldered to Vin and the black wire was soldered to GND by convention. The next task was to determine which of the wires, blue or yellow, represented data signals SDA and SCL respectively. This was done by opening the Artemis board data sheet and comparing the <a href = https://cdn.sparkfun.com/assets/5/5/1/6/3/RedBoard-Artemis-Nano.pdfschematic>schematic</a> to the header connection. The blue wire was soldered to SDA and the yellow wire was soldered to SCL on both of the ToF sensor boards. Soldered ToF Sensor Current Connections

I2C Addressing

Next, the SparkFun VL53L1X 4m laser distance sensor library was installed via the Arduino IDE. The Apollo 3 -> Example05_Wire_I2C.ino was used as an example to learn the I2C library. The address of one ToF sensor was found to be 0x29. When both ToF sensors are connected, addresses 0x1, 0x2, 0x3 ... 0x7E were all detected. Later in the lab, the address of the first sensor was set as 0x52 and the second sensor address was changed to 0x20.

Searching for I2C Device

Sensor Data

The ToF sensor has three functions avaialable:

.setDistanceModeShort(); //1.3m 
.setDistanceModeMedium(); //3m 
.setDistanceModeLong(); //4m, Default

These functions optimize the ranging performance given the expected distance of operation. Depending on the task, different distance modes can be set on the final robot in order to maximize accuracy. For example, a task that involves avoiding many nearby obstacles would rely on the short distance mode, while a task that involves looking for a distant object could utilize the long distance mode. For the purposes of this lab, the .setDistanceModeShort() method was used.

In order to test the measurements of the ToF sensor, the below experiment was set up.

Experimental Setup

Repeated measurements from the ToF sensor were gathered from various distances. A white wall and good lighting were used to ensure the sensor could accurately detect the distance from the wall. For the experiment, 100 measurements were gathered at 100 mm intervals.

Distance Error Graph

The sensor is overall very precise in its measurements. Another important characteristic of the sensor to determine is its reliability, or how often it will output the same measurement at the same distance. The results are shown below:

Repeatability Graph

The measurements of the sensor do tend to vary, but only on the magnitude of a few millimeters. The inaccuracy of the meassurements increase past the 1.3 m mark, which matches the specification of the distance mode function used, .setDistanceModeShort(). The effective range of the sensor was found max out at a distance of 2.3 m.

Parallel Sensors

Both ToF sensors were connected to the Artemis board simultaneously. The address of the sensor is hardwired on the board, so having multiple sensors is not easily supported. To solve this, an additional wire were soldered from the shutdown pin of one ToF sensor to the output pin GPIO_08 of the Artemis board. A signal is sent from the I/O of the Artemis board to the shutdown pin when the Artemis board is first initialized. While the ToF sensor is shutdown, the second ToF sensor's address is changed in Arduino code. The shutdown signal is set to low, re-enabling the ToF sensor and allowing both sensors to work in parallel with seperate memory addresses.

// Shut down sensor 2
distanceSensor2.sensorOff();
// Change address of sensor 1 from default to NEW_ADDRESS
int sensor1_address = distanceSensor1.getI2CAddress();
if (sensor1_address == DEF_ADDRESS)
{
  distanceSensor1.setI2CAddress(NEW_ADDRESS);
  Serial.print("Sensor 1 address changed to 0x");
  Serial.println(distanceSensor1.getI2CAddress(), HEX);
}
Parallel Sensors

Sensor Speed

The speed of the ToF is significantly slower than the clock cycle of the Artemis board. This was determined through the below code, which prints the clock timing and sensor data as often as they are individually available. The frequency of time prints is much greater than the frequency of sensor measurement prints, so the limiting time factor is the time it takes for the ToF sensor to gather data rather than the microcontroller's internal clock cycle. The code below showcases the code used to test the timing of the internal clock and the below video shows the frequency the time can be retrieved compared to the much slower distance measurements.

#Code used to test sensor speed
while (!distanceSensor1.checkForDataReady() && !distanceSensor2.checkForDataReady())
{
    int time = millis();
    Serial.println("Time: ");
    Serial.print(time);
    Serial.println();
    delay(1);
}

Bluetooth

Using methods created in Lab 2, the distance from both sensors was sent to my computer via bluetooth. This data can be compiled into a graphical form for easier data analysis. The below graph shows distance data gathered over approximately 5 seconds from both sensors. The first ToF sensor was kept steady, while the second ToF sensor was slowly moved to face a more distant wall. A Jupyter notebook python method was also created to convert the bluetooth-sent data into a more readable graph, which involved editing the callback function of the bluetooth notify function to process the data being updating in the Artemis board string characteristic.

#Callback function
def callback(uuid, string_value):
    global string_characteristic
    string_characteristic = ble.bytearray_to_string(string_value)
    str_list = list(map(int, re.findall('\d+', string_characteristic)))
    time = str_list[0]
    distance1 = str_list[2]
    distance2 = str_list[4]
    time_list.append(time)
    distance1_list.append(distance1)
    distance2_list.append(distance2) 
Distance vs Time Graph