Fripuck devlog n°2: April update

This month I've been quite busy with University work and had less time to focus on Fripuck. Still, I've managed to add new sensors and solve some pesky errors !

New sensors

The e-puck2 robot is equipped with a ring of 8 proximity sensors (IR reflectors). I followed the architecture of the previous implementation. It cleverly turns the IR ligths of the sensors on and off at specific time intervals to limit interference and measure the ambient light levels.

This is a significant step-up of my previous implementation, which kept the IR lights always on and scanned the sensors continuously. Not only did this produce interference in the results, but also increased power consumption.

This month also brought three sensors living on the I²C connection: the Time-of-Flight (ToF), the Inertial Measurement Unit (IMU) and the ground sensors.

I²C stability issues

I²C is a communication protocol where a master can communicate to multiple slave on the same wire. On the e-puck2, three sensors are configured and transfer their data over I²C: the ToF, IMU and ground sensors.

At first, the I²C connection seemed to work for the ToF, but wouldn't for the other sensors, always returning HAL_BUSY error. Looking online, I found that I²C can be quite unstable on some STM chips, especially when using the standard HAL_I2C_Mem_Read/Write functions. I decided to copy the implementation of the vl53l0x ToF api code, which used the HAL_I2C_Master_Receive/Transmit functions directly.

Here is how my custom 2c_read/write_reg was implemented, if it can be of use for anyone:

HAL_StatusTypeDef i2c_read_reg(uint8_t dev_addr, uint8_t reg, uint8_t *buffer, uint16_t len)
{
    HAL_StatusTypeDef res;
    osMutexAcquire(i2c_mutex, osWaitForever);

    // Announce which device/register will be sent to
    res = HAL_I2C_Master_Transmit(i2c_handle, (dev_addr << 1), &reg, 1, 100);

    if (res == HAL_OK)
    {
        // Recieve data from the slave
        res = HAL_I2C_Master_Receive(i2c_handle, (dev_addr << 1), buffer, len, 100);
    }

    osMutexRelease(i2c_mutex);
    return res;
}

HAL_StatusTypeDef i2c_write_reg(uint8_t dev_addr, uint8_t reg, uint8_t *buffer, uint16_t len)
{
    // Local buffer to combine reg + data
    uint8_t tmp[len + 1];
    tmp[0] = reg;
    memcpy(&tmp[1], buffer, len);

    osMutexAcquire(i2c_mutex, osWaitForever);
    HAL_StatusTypeDef res = HAL_I2C_Master_Transmit(i2c_handle, (dev_addr << 1), tmp, len + 1, 100);
    osMutexRelease(i2c_mutex);

    return res;
}

Python API

The python API now internally exposes an Abstract Base Class that makes it very easy to implement the reception of new sensor data. This framework has been used to implement all the sensor management in the python API, significantly reducing code duplication.

What's next ?

Next month, I'll be working more on my upcoming exams, so it will probably be a quite uneventful month.

In the available time I have, I will try to come op with a good priority system to manage which sensor data gets packaged when and sent. Currently, if I let too many sensors run at once, the Flatbuffers packet will consume so much ram that the program crashes. My objective is to smartly cut up the incoming data streams to control the final size of my Flatbuffers packet and make sure no streams are getting starved.

Wrapping up

While this month didn't bring as many features as I would have hoped, I am still happy with what I achieved considering the limited amount of free time at my disposal. I am also pleased to see the I²C issue fixed, which has been bothering me for some time now.