linguini1 opened a new pull request, #15789:
URL: https://github.com/apache/nuttx/pull/15789
## Summary
Adds support for the LSM6DSO32 IMU by STM using the uORB framework. This
only contains limited support for the I2C interface, interrupt and polling
driven measurement and standard modes of operation (high performance ODRs).
Features like interrupts besides DRDY, filtering, gesture recognition and
acting as a bus master are not implemented.
Accompanying documentation included.
## Impact
This PR adds another available uORB driver to the NuttX sensor drivers.
It impacts the build system by adding more Kconfig options and impacts the
kernel with more driver source files.
## Testing
All builds were performed on a Linux host. All testing was performed on an
RP2040 MCU on a custom flight computer board.
Below is the script that was used for testing.
```c
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <nuttx/sensors/lsm6dso32.h>
#include <uORB/uORB.h>
#define SAMPLE_FREQ 50
#define ACCEL_NAME "sensor_accel0"
#define GYRO_NAME "sensor_gyro0"
int main(int argc, char **argv)
{
int err;
unsigned frequency;
int accel;
struct sensor_accel accel_data;
int gyro;
struct sensor_gyro gyro_data;
struct sensor_device_info_s info;
bool update = false;
printf("TESTING ACCELEROMETER IMPLEMENTATION\n");
/* Get accelerometer metadata */
const struct orb_metadata *accel_meta = orb_get_meta(ACCEL_NAME);
if (accel_meta == NULL)
{
fprintf(stderr, "Failed to get metadata for %s\n", ACCEL_NAME);
return EXIT_FAILURE;
}
/* Subscribe to accelerometer */
accel = orb_subscribe(accel_meta);
if (accel < 0)
{
fprintf(stderr, "Could not subsribe to %s: %d\n", ACCEL_NAME, errno);
return EXIT_FAILURE;
}
/* Set sampling rate to 50Hz */
err = orb_set_frequency(accel, SAMPLE_FREQ);
if (err)
{
fprintf(stderr, "Wasn't able to set frequency to %uHz: %d\n",
SAMPLE_FREQ, err);
return EXIT_FAILURE;
}
/* Show sampling rate */
err = orb_get_frequency(accel, &frequency);
if (err)
{
fprintf(stderr, "Could not verify frequency: %d\n", err);
return EXIT_FAILURE;
}
printf("Sampling frequency is %uHz\n", frequency);
/* Print sensor information */
err = orb_ioctl(accel, SNIOC_GET_INFO, (unsigned long)&info);
if (err < 0)
{
fprintf(stderr, "Could not get sensor information: %d", errno);
return EXIT_FAILURE;
}
printf("Sensor: %s\n", info.name);
printf("Manufacturer: %s\n", info.vendor);
printf("Power consumption: %.2fmA\n", info.power);
printf("Resolution: %.6f m/s^2\n", info.resolution);
printf("Max range: %.2f m/s^2\n", info.max_range);
printf("Min delay: %ld us\n", info.min_delay);
/* Perform self-test */
err = orb_ioctl(accel, SNIOC_SELFTEST, 0);
if (err < 0)
{
fprintf(stderr, "Self test failed: %d\n", errno);
return EXIT_FAILURE;
}
printf("Self test passed!\n");
/* Loop forever while printing out tab separated data as X, Y, Z */
for (int i = 0; i < 10;)
{
err = orb_check(accel, &update);
if (err)
{
fprintf(stderr, "Failed to check for new accel_data: %d\n", err);
continue;
}
/* Grab latest accel_data */
if (update)
{
err = orb_copy(accel_meta, accel, &accel_data);
if (err)
{
fprintf(stderr, "Failed to get new accel_data: %d\n", err);
continue;
}
printf("%f\t%f\t%f\n", accel_data.x, accel_data.y, accel_data.z);
i++;
}
}
/* Subtract offset */
float offsets[3] = {0.0f, -0.4f, 9.98f};
err = orb_ioctl(accel, SNIOC_SET_CALIBVALUE, (unsigned long)offsets);
if (err < 0)
{
fprintf(stderr, "Failed to set calibration values: %d", err);
return EXIT_FAILURE;
}
printf("Offsets set: %.2f X, %.2f Y, %.2f Z\n", offsets[0], offsets[1],
offsets[2]);
/* Loop forever while printing out tab separated accel_data as X, Y, Z */
for (int i = 0; i < 10;)
{
err = orb_check(accel, &update);
if (err)
{
fprintf(stderr, "Failed to check for new accel_data: %d\n", err);
continue;
}
/* Grab latest accel_data */
if (update)
{
err = orb_copy(accel_meta, accel, &accel_data);
if (err)
{
fprintf(stderr, "Failed to get new accel_data: %d\n", err);
continue;
}
printf("%f\t%f\t%f\n", accel_data.x, accel_data.y, accel_data.z);
i++;
}
}
printf("TESTING GYROSCOPE IMPLEMENTATION\n");
/* Get gyro metadata */
const struct orb_metadata *gyro_meta = orb_get_meta(GYRO_NAME);
if (gyro_meta == NULL)
{
fprintf(stderr, "Failed to get metadata for %s\n", GYRO_NAME);
return EXIT_FAILURE;
}
/* Subscribe to gyroerometer */
gyro = orb_subscribe(gyro_meta);
if (gyro < 0)
{
fprintf(stderr, "Could not subsribe to %s: %d\n", GYRO_NAME, errno);
return EXIT_FAILURE;
}
/* Set sampling rate to 50Hz */
err = orb_set_frequency(gyro, SAMPLE_FREQ);
if (err)
{
fprintf(stderr, "Wasn't able to set frequency to %uHz: %d\n",
SAMPLE_FREQ, err);
return EXIT_FAILURE;
}
/* Show sampling rate */
err = orb_get_frequency(gyro, &frequency);
if (err)
{
fprintf(stderr, "Could not verify frequency: %d\n", err);
return EXIT_FAILURE;
}
printf("Sampling frequency is %uHz\n", frequency);
/* Print sensor information */
err = orb_ioctl(gyro, SNIOC_GET_INFO, (unsigned long)&info);
if (err < 0)
{
fprintf(stderr, "Could not get sensor information: %d", errno);
return EXIT_FAILURE;
}
printf("Sensor: %s\n", info.name);
printf("Manufacturer: %s\n", info.vendor);
printf("Power consumption: %.2fmA\n", info.power);
printf("Resolution: %.6f rad/s\n", info.resolution);
printf("Max range: %.2f rad/s\n", info.max_range);
printf("Min delay: %ld us\n", info.min_delay);
/* Perform self-test */
err = orb_ioctl(gyro, SNIOC_SELFTEST, 0);
if (err < 0)
{
fprintf(stderr, "Self test failed: %d\n", errno);
return EXIT_FAILURE;
}
printf("Self test passed!\n");
/* Loop forever while printing out tab separated gyro_data as X, Y, Z */
for (int i = 0; i < 10;)
{
err = orb_check(gyro, &update);
if (err)
{
fprintf(stderr, "Failed to check for new gyro_data: %d\n", err);
continue;
}
/* Grab latest gyro_data */
if (update)
{
err = orb_copy(gyro_meta, gyro, &gyro_data);
if (err)
{
fprintf(stderr, "Failed to get new gyro_data: %d\n", err);
continue;
}
printf("%f\t%f\t%f\n", gyro_data.x, gyro_data.y, gyro_data.z);
i++;
}
}
/* Subtract offset */
float offsets2[3] = {0.0f, -1.0f, 0.0f};
err = orb_ioctl(gyro, SNIOC_SET_CALIBVALUE, (unsigned long)offsets2);
if (err < 0)
{
fprintf(stderr, "Failed to set calibration values: %d", err);
return EXIT_FAILURE;
}
printf("Offsets set: %.2f X, %.2f Y, %.2f Z\n", offsets2[0], offsets2[1],
offsets2[2]);
/* Loop forever while printing out tab separated gyro_data as X, Y, Z */
for (int i = 0; i < 10;)
{
err = orb_check(gyro, &update);
if (err)
{
fprintf(stderr, "Failed to check for new gyro_data: %d\n", err);
continue;
}
/* Grab latest gyro_data */
if (update)
{
err = orb_copy(gyro_meta, gyro, &gyro_data);
if (err)
{
fprintf(stderr, "Failed to get new gyro_data: %d\n", err);
continue;
}
printf("%f\t%f\t%f\n", gyro_data.x, gyro_data.y, gyro_data.z);
i++;
}
}
uint8_t id = 0;
err = orb_ioctl(gyro, SNIOC_WHO_AM_I, (unsigned long)&id);
if (err < 0)
{
fprintf(stderr, "Could not get WHOAMI value: %d\n", errno);
return EXIT_FAILURE;
}
printf("WHOAMI: %02X\n", id);
printf("Changing FSR of accelerometer to +/-32g\n");
err = orb_ioctl(accel, SNIOC_SETFULLSCALE, LSM6DSO32_FSR_XL_32G);
if (err < 0)
{
fprintf(stderr, "Could not get WHOAMI value: %d\n", errno);
return EXIT_FAILURE;
}
printf("New measurement values:\n");
for (int i = 0; i < 10;)
{
err = orb_check(accel, &update);
if (err)
{
fprintf(stderr, "Failed to check for new accel_data: %d\n", err);
continue;
}
/* Grab latest accel_data */
if (update)
{
err = orb_copy(accel_meta, accel, &accel_data);
if (err)
{
fprintf(stderr, "Failed to get new accel_data: %d\n", err);
continue;
}
printf("%f\t%f\t%f\n", accel_data.x, accel_data.y, accel_data.z);
i++;
}
}
orb_unsubscribe(accel);
orb_unsubscribe(gyro);
return EXIT_SUCCESS;
}
```
This script tests the following:
- Measurements are within the correct range for stationary board (i.e.
9.81~m/s^2 in one axis, 0 in others and 0 angular velocity in any direction)
- Self-tests for the sensors pass
- Self-tests for the sensors do not affect subsequent measurements due to
hysteresis
- `WHOAMI` register is read and the value is correct
- `SETFULLSCALE` changes the range of the sensor correctly and measurements
are correct following this change
- Measurement values are correctly modified by using `SET_CALIBVALUE`
- Measurement frequency can be set
- Changing FSR and ODR correctly changes the data in `get_info`
- `get_info` returns the correct information depending on accel/gyro
Here is the output of the script in interrupt-driven mode:
```console
TESTING ACCELEROMETER IMPLEMENTATION
Sampling frequency is 50Hz
Sensor: LSM6DSO32
Manufacturer: STMicro
Power consumption: 0.55mA
Resolution: 0.002392 m/s^2
Max range: 78.41 m/s^2
Min delay: 80000 us
Self test passed!
0.126820 -0.806385 19.946671
0.126820 -0.806385 19.946671
0.078963 -0.555138 13.189305
0.021535 -0.023928 0.165106
0.028714 -0.011964 0.052642
0.033499 -0.007178 0.052642
0.033499 -0.014357 0.057428
0.035892 -0.016749 0.057428
0.033499 -0.023928 0.055035
0.031106 -0.019142 0.057428
Offsets set: 0.00 X, -0.40 Y, 9.98 Z
0.031106 -0.016749 0.059820
0.031106 -0.009571 0.059820
0.038285 -0.009571 0.052642
0.031106 -0.014357 0.057428
0.033499 -0.016749 0.057428
0.026321 -0.021535 0.055035
0.026321 -0.028714 0.052642
0.028714 -0.023928 0.055035
0.035892 -0.011964 0.059820
0.035892 -0.016749 0.057428
TESTING GYROSCOPE IMPLEMENTATION
Sampling frequency is 50Hz
Sensor: LSM6DSO32
Manufacturer: STMicro
Power consumption: 0.55mA
Resolution: 0.000076 rad/s
Max range: 2.50 rad/s
Min delay: 80000 us
Self test passed!
0.001374 1.004123 0.001527
0.001374 1.004123 0.001527
0.001450 1.003894 0.001374
0.001450 1.003818 0.001450
0.001298 1.003894 0.001450
0.000839 1.003742 0.001374
0.000534 1.003894 0.001679
0.000763 1.003742 0.001374
0.000534 1.004047 0.001450
0.000916 1.003971 0.001298
Offsets set: 0.00 X, -1.00 Y, 0.00 Z
0.001069 1.003818 0.001679
0.001450 1.003818 0.001298
0.001298 1.003818 0.001679
0.001374 1.003665 0.001679
0.001221 1.003894 0.001679
0.001298 1.003665 0.001527
0.001145 1.003589 0.001374
0.000839 1.003589 0.001450
0.000687 1.003742 0.001374
0.000916 1.003894 0.001527
WHOAMI: 6C
Changing FSR of accelerometer to +/-32g
New measurement values:
0.035892 -0.016749 0.062213
0.028714 -0.014357 0.064606
0.028714 -0.019142 0.059820
0.031106 -0.016749 0.069392
0.031106 -0.014357 0.066999
0.035892 -0.011964 0.059820
0.035892 -0.011964 0.062213
0.035892 -0.011964 0.059820
0.033499 -0.014357 0.062213
0.028714 -0.016749 0.066999
```
Here is the output of the script in polling mode:
```console
TESTING ACCELEROMETER IMPLEMENTATION
Sampling frequency is 50Hz
Sensor: LSM6DSO32
Manufacturer: STMicro
Power consumption: 0.55mA
Resolution: 0.001196 m/s^2
Max range: 39.20 m/s^2
Min delay: 80000 us
Self test passed!
0.000000 0.000000 0.000000
0.078963 -0.436692 9.978121
0.076570 -0.429514 9.979318
0.065803 -0.425925 9.979318
0.076570 -0.445067 9.970942
0.064606 -0.440282 9.970942
0.053838 -0.443871 9.955389
0.069392 -0.423532 9.978121
0.074177 -0.423532 9.973335
0.070588 -0.434299 9.986496
Offsets set: 0.00 X, -0.40 Y, 9.98 Z
0.059820 -0.130409 0.177070
0.078963 -0.120838 0.180659
0.075374 -0.117249 0.175873
0.055035 -0.132802 0.165106
0.072981 -0.120838 0.183052
0.057428 -0.117249 0.163909
0.080160 -0.108874 0.173481
0.069392 -0.124427 0.177070
0.069392 -0.116052 0.185445
0.056231 -0.125624 0.180659
TESTING GYROSCOPE IMPLEMENTATION
Sampling frequency is 50Hz
Sensor: LSM6DSO32
Manufacturer: STMicro
Power consumption: 0.55mA
Resolution: 0.000076 rad/s
Max range: 2.50 rad/s
Min delay: 80000 us
Self test passed!
0.000000 0.000000 0.000000
0.001221 0.003436 0.001527
0.001069 0.003894 0.001450
0.000992 0.003665 0.001450
0.001221 0.003665 0.001450
0.000839 0.003741 0.001527
0.001298 0.003665 0.001603
0.001450 0.003359 0.000839
0.000916 0.003665 0.001374
0.001603 0.003436 0.001069
Offsets set: 0.00 X, -1.00 Y, 0.00 Z
0.000534 1.003589 0.001298
0.001450 1.003665 0.001450
0.001603 1.003360 0.001527
0.001679 1.003207 0.001374
0.001374 1.003665 0.001603
0.001756 1.003436 0.001298
0.001298 1.003589 0.001603
0.001527 1.003589 0.001527
0.001603 1.003207 0.001221
0.001069 1.003665 0.001450
WHOAMI: 6C
Changing FSR of accelerometer to +/-32g
New measurement values:
0.071785 -0.124427 0.212962
0.033499 -0.033499 0.066999
0.035892 -0.028714 0.066999
0.035892 -0.033499 0.069392
0.031106 -0.038285 0.066999
0.040678 -0.023928 0.064606
0.035892 -0.033499 0.071785
0.033499 -0.031106 0.066999
0.031106 -0.033499 0.066999
0.031106 -0.038285 0.069392
```
Here is the output of `uorb_listener` in polling mode (there is also a
magnetometer on this board, only the accel and gyro readings are from this
driver).
```console
object_name:sensor_mag, object_instance:0
object_name:sensor_gyro, object_instance:0
object_name:sensor_accel, object_instance:0
sensor_mag(now:80440000):timestamp:80440000,x:-72.900002,y:0.150000,z:-242.700012,temperature:23.101563,s0
sensor_gyro(now:80450000):timestamp:80440000,x:-0.000076,y:0.000000,z:-0.000076,temperature:23.000000
sensor_accel(now:80450000):timestamp:80450000,x:0.041874,y:-0.029910,z:-0.010767,temperature:23.000000
sensor_mag(now:80470000):timestamp:80470000,x:-74.099998,y:0.450000,z:-241.800003,temperature:23.070313,s0
sensor_gyro(now:80470000):timestamp:80470000,x:-0.050701,y:-0.017944,z:0.028863,temperature:24.000000
sensor_accel(now:80480000):timestamp:80480000,x:0.011964,y:-0.002392,z:-0.297908,temperature:24.000000
sensor_mag(now:80500000):timestamp:80500000,x:-74.250000,y:-0.750000,z:-242.700012,temperature:23.066406,0
sensor_gyro(now:80500000):timestamp:80500000,x:-0.031994,y:-0.001985,z:-0.008704,temperature:24.000000
sensor_accel(now:80510000):timestamp:80510000,x:0.014357,y:-0.017946,z:0.025124,temperature:24.000000
sensor_mag(now:80530000):timestamp:80530000,x:-73.800003,y:0.450000,z:-243.449997,temperature:23.078125,s0
Object name:sensor_mag0, recieved:4
Object name:sensor_gyro0, recieved:3
Object name:sensor_accel0, recieved:3
Total number of received Message:10/10
```
Here is the output of `uorb_listener` in interrupt-driven mode (there is
also a magnetometer and barometer on this board, only the accel and gyro
readings are from this driver).
```console
nsh> uorb_listener -r 50 -n 10
Mointor objects num:4
object_name:sensor_mag, object_instance:0
object_name:sensor_gyro, object_instance:0
object_name:sensor_baro, object_instance:0
object_name:sensor_accel, object_instance:0
sensor_mag(now:54820000):timestamp:54810000,x:-77.100006,y:0.150000,z:-243.600006,temperature:22.992188,s0
sensor_mag(now:54830000):timestamp:54830000,x:-75.599998,y:-0.150000,z:-243.300003,temperature:23.031250,0
sensor_gyro(now:54830000):timestamp:54820000,x:-0.039400,y:-0.034513,z:0.038331,temperature:23.000000
sensor_accel(now:54830000):timestamp:54820000,x:-0.007178,y:-0.093320,z:2.392835,temperature:23.000000
sensor_gyro(now:54840000):timestamp:54840000,x:-0.027107,y:-0.011377,z:-0.004886,temperature:24.000000
sensor_accel(now:54840000):timestamp:54840000,x:0.009571,y:-0.458228,z:9.941032,temperature:24.000000
sensor_baro(now:54850000):timestamp:54850000,pressure:505.600006,temperature:18.510000
sensor_mag(now:54850000):timestamp:54850000,x:-75.300003,y:0.600000,z:-243.300003,temperature:23.039063,s0
sensor_gyro(now:54860000):timestamp:54860000,x:0.126449,y:-0.159665,z:-0.030008,temperature:24.000000
sensor_accel(now:54860000):timestamp:54860000,x:0.039481,y:-0.513263,z:9.961371,temperature:24.000000
Object name:sensor_mag0, recieved:3
Object name:sensor_gyro0, recieved:3
Object name:sensor_baro0, recieved:1
Object name:sensor_accel0, recieved:3
Total number of received Message:10/10
```
Here are the system logs in debug mode when the driver is registered in
polling mode:
```console
lsm6dso32_register: LSM6DSO32 gyro using polling thread.
lsm6dso32_register: LSM6DSO32 accel using polling thread.
lsm6dso32_register: LSM6DSO32 driver registered!
```
Here are the system logs in debug mode when the driver is registered in
interrupt-driven mode:
```console
lis2mdl_register: Registered LIS2MDL driver in interrupt driven mode.
lis2mdl_register: Registered LIS2MDL driver.
sensor_custom_register: Registering /dev/uorb/sensor_gyro0
sensor_custom_register: Registering /dev/uorb/sensor_accel0
lsm6dso32_register: LSM6DSO32 gyro interrupt handler attached to INT1.
lsm6dso32_register: LSM6DSO32 accel interrupt handler attached to INT2.
lsm6dso32_register: LSM6DSO32 driver registered!
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]