How to Export Sensor Data From the Rover

In this tutorial, we will show you how to use the rover as a data collection device to assist with analysis and experiments.

Why Collect Data?:

While the ‘print’ function can display values on the terminal, sometimes we need to see many lines of information from different stages of the code. With this technique, we can record the data from each sensor at any point in the code and record and edit it in a Microsoft Excel file. This would let us analyse tables and graphs of data for an array of purposes. Maybe the rover could be used in science experiments? Or we might need to read the data to see how the colour sensors perform on different materials? Continue reading to find out how to record data for your project.

How to Use the Code:

Shown below is the code used to collect data from the rover. Note that this code must be used in an external code editor. Not sure how to do this? Click the button below for our tutorial on getting stared with external code editors:

Shown below is the whole code used to record sensor data from the rover. Once the code has completed running, there will be a ‘data.csv’ file in the same folder as the code which contains the recorded data. Make sure to copy the data to an excel file as this file is overwritten each time the code is run.

Copy the code below into your code editor, and scroll down on this page to find out how to use it.

from micromelon import *
import csv
import time

rc = RoverController()
rc.connectBLE(1) # Enter the number for your rover
rc.startRover()

START_TIME = time.time()

def current_time():
    """
    Returns the time elapsed since the start of the code
    
    Returns:
        int: Seconds since the start of the code
    """
    return time.time() - START_TIME

# Below, uncomment the sensor data you wish to record
sensors = {
    'Time': current_time,
    'Ultrasonic': lambda: Ultrasonic.read(),
    'Brightness_Left': lambda: Colour.readSensor(CS.BRIGHT, sensor = 0),
    'Brightness_Middle': lambda: Colour.readSensor(CS.BRIGHT, sensor = 1),
    'Brightness_Right': lambda: Colour.readSensor(CS.BRIGHT, sensor = 2),
    'IR_Left': lambda: IR.readLeft(),
    'IR_Right': lambda: IR.readRight(),
    'Accelerometer_x': lambda: IMU.readAccel(0),
    'Accelerometer_y': lambda: IMU.readAccel(1),
    'Accelerometer_z': lambda: IMU.readAccel(2),
    'Gyro_x': lambda: IMU.readGyro(0),
    'Gyro_y': lambda: IMU.readGyro(1),
    'Gyro_z': lambda: IMU.readGyro(2),
    'Gyro_Accumulated_x': lambda: IMU.readGyroAccum(0),
    'Gyro_Accumulated_y': lambda: IMU.readGyroAccum(1),
    'Gyro_Accumulated_z': lambda: IMU.readGyroAccum(2),
}

def record_data(output_file):
    """
    Read all of the given sensors and record each of the values to memory once

    Parameters:
        output_file (list[list[int,...]]): A list containing lists of integers.
        Each list of integers is a single row of data

    Returns:
        list[list[int,...]]: The output file with the new row of data in it
    """
    row = []
    for key in sensors.keys():
        row.append((sensors[key])())
    output_file.append(row)
    return output_file

def write_data(output_file):
    """
    write the output file into a CSV file with each of the sensor names as
    headers

    Parameters:
        output_file (list[list[int,...]]): A list containing lists of integers.
        Each list of integers is a single row of data
    """
    fieldnames = sensors.keys()
    with open('data.csv', mode = 'w', newline="") as file:
        writer = csv.writer(file)
        writer.writerow(fieldnames)
        for row in output_file:
            writer.writerow(row)
        
delay(2)
output_file = []

# ENTER YOUR CODE BELOW THIS LINE


# DON'T ENTER CODE PAST THIS LINE
write_data(output_file)
rc.stopRover()
rc.end()

1) Enter the rover number

In the section shown below, enter the number of your rover to connect. Make sure bluetooth is turned on on the computer.

rc = RoverController()
rc.connectBLE(1) # Enter the number for your rover
rc.startRover()

2) Choose your sensors

The ‘sensors’ dictionary is used to select which sensors we gather data from. An additional sensor ‘Time’ gives the real time since the code has started running. The function ‘current_time’ may be used to get the timestamp for use in your code. When a sensor is commented out (grey), the rover will not record data from it.

# Below, uncomment the sensor data you wish to record
sensors = {
    'Time': current_time,
    'Ultrasonic': lambda: Ultrasonic.read(),
    'Brightness_Left': lambda: Colour.readSensor(CS.BRIGHT, sensor = 0),
    'Brightness_Middle': lambda: Colour.readSensor(CS.BRIGHT, sensor = 1),
    'Brightness_Right': lambda: Colour.readSensor(CS.BRIGHT, sensor = 2),
    'IR_Left': lambda: IR.readLeft(),
    'IR_Right': lambda: IR.readRight(),
    # 'Accelerometer_x': lambda: IMU.readAccel(0),
    # 'Accelerometer_y': lambda: IMU.readAccel(1),
    # 'Accelerometer_z': lambda: IMU.readAccel(2),
    'Gyro_x': lambda: IMU.readGyro(0),
    'Gyro_y': lambda: IMU.readGyro(1),
    'Gyro_z': lambda: IMU.readGyro(2),
    # 'Gyro_Accumulated_x': lambda: IMU.readGyroAccum(0),
    # 'Gyro_Accumulated_y': lambda: IMU.readGyroAccum(1),
    # 'Gyro_Accumulated_z': lambda: IMU.readGyroAccum(2),
}

3) Record your data

Now we move to the section where we record data. It’s very important to remember that the section below must not loop forever! If it does, the data will not be written to the CSV file. To record a line of data from all of your selected sensors, use the line below:

output_file = record_data(output_file)

Next, we’ll show you some tips and tricks to record data:

Collect data on prompt: This code below will take a reading of data when the middle colour sensor sees black

# ENTER YOUR CODE BELOW THIS LINE
while True:
    if Colour.readSensor(CS.BRIGHT, sensor = 1) < 100:
        output_file = record_data(output_file)
        break

# DON'T ENTER CODE PAST THIS LINE

Record data for 3 seconds: This is to record all sensor data for a set amount of time

# ENTER YOUR CODE BELOW THIS LINE
start_recording = current_time()
while (current_time() - start_recording) < 3:
    output_file = record_data(output_file)

# DON'T ENTER CODE PAST THIS LINE

Control the amount of data points: If the code is recording too many data points, you can limit how often it records. In the example below, the rover only records data once every 500 iterations of the loop. Increase this number to record fewer data points.

# ENTER YOUR CODE BELOW THIS LINE
start_recording = current_time()
counter = 0
while (current_time() - start_recording) < 3:
    if not counter % 500:
        output_file = record_data(output_file)
    counter += 1

# DON'T ENTER CODE PAST THIS LINE

Demonstration:

In our demonstration, we will setup the rover on the platform as shown. The idea is for the rover to drive forward, and record the brightness from each colour sensor. Data point collection has been limited to once every 500 loops and recording will stop when the ultrasonic sensor sees the block at the end of the platform. Shown below is the configuration of the code that was used:

from micromelon import *
import csv
import time

rc = RoverController()
rc.connectBLE(371) # Enter the number for your rover
rc.startRover()

START_TIME = time.time()

def current_time():
    """
    Returns the time elapsed since the start of the code
    
    Returns:
        int: Seconds since the start of the code
    """
    return time.time() - START_TIME

# Below, uncomment the sensor data you wish to record
sensors = {
    'Time': current_time,
    # 'Ultrasonic': lambda: Ultrasonic.read(),
    'Brightness_Left': lambda: Colour.readSensor(CS.BRIGHT, sensor = 0),
    'Brightness_Middle': lambda: Colour.readSensor(CS.BRIGHT, sensor = 1),
    'Brightness_Right': lambda: Colour.readSensor(CS.BRIGHT, sensor = 2),
    # 'IR_Left': lambda: IR.readLeft(),
    # 'IR_Right': lambda: IR.readRight(),
    # 'Accelerometer_x': lambda: IMU.readAccel(0),
    # 'Accelerometer_y': lambda: IMU.readAccel(1),
    # 'Accelerometer_z': lambda: IMU.readAccel(2),
    # 'Gyro_x': lambda: IMU.readGyro(0),
    # 'Gyro_y': lambda: IMU.readGyro(1),
    # 'Gyro_z': lambda: IMU.readGyro(2),
    # 'Gyro_Accumulated_x': lambda: IMU.readGyroAccum(0),
    # 'Gyro_Accumulated_y': lambda: IMU.readGyroAccum(1),
    # 'Gyro_Accumulated_z': lambda: IMU.readGyroAccum(2),
}

def record_data(output_file):
    """
    Read all of the given sensors and record each of the values to memory once

    Parameters:
        output_file (list[list[int,...]]): A list containing lists of integers.
        Each list of integers is a single row of data

    Returns:
        list[list[int,...]]: The output file with the new row of data in it
    """
    row = []
    for key in sensors.keys():
        row.append((sensors[key])())
    output_file.append(row)
    return output_file

def write_data(output_file):
    """
    write the output file into a CSV file with each of the sensor names as
    headers

    Parameters:
        output_file (list[list[int,...]]): A list containing lists of integers.
        Each list of integers is a single row of data
    """
    fieldnames = sensors.keys()
    with open('data.csv', mode = 'w', newline="") as file:
        writer = csv.writer(file)
        writer.writerow(fieldnames)
        for row in output_file:
            writer.writerow(row)
        
delay(2)
output_file = []

# ENTER YOUR CODE BELOW THIS LINE
counter = 0
Motors.write(8)
while Ultrasonic.read() > 10:
    if not counter % 500:
        output_file = record_data(output_file)
    counter += 1
Motors.write(0)

# DON'T ENTER CODE PAST THIS LINE
write_data(output_file)
rc.stopRover()
rc.end()

Once the code was run, the ‘data.csv’ file was opened up in Microsoft Excel, and graphed.

Looking at the graph, we are now able to analyse how the sensors interpret the platform and the shade of the tape. There are three distinct drops in the data where the rover passed over the tape. This information can be used to easily analyse the brightness readings of each colour sensor on different surfaces.

Previous
Previous

Activity: Claw Attachment

Next
Next

Activity: Digger and Tipper