sensord: use interrupts to improve LSM6DS3 timing accuracy (#24525)
* change LSM6DS3TR(-c) gyroscope and accelerometer to interrupt
* add pthread for linking
* add interrupt collector thread to fetch in parallel to non interrupt based sensors
* change get_event interface to return true on successful read
* fetch sensor interrupts via gpiochip
* avoid sending empty messages (interrupt only, non interupt magn can leave a gap in the orphan block)
* add verifier script to sensor interrupts (sensor_data_to_hist.py)
* add/update sensord testsweet (test_sensord.py)
* add poll timed out check
* unexport interrupt gpio pins
* gpiochip on both edges, but skip falling edge if rising edge is detected, this is handled in the sensor as the status flag is checked if new data is availble
* add test to sensord to verify 100Hz interrupt frequency
* add sensor shutdown/low power mode functionality on sensord exit
* relax test, will be readded in the splitup PR
Co-authored-by: Kurt Nistelberger <kurt.nistelberger@gmail.com>
old-commit-hash: 84a3c355e5
taco
parent
0c480f7b3a
commit
7451db46cf
31 changed files with 711 additions and 58 deletions
@ -0,0 +1,121 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
''' |
||||||
|
printing the gap between interrupts in a histogram to check if the |
||||||
|
frequency is what we expect, the bmx is not interrupt driven for as we |
||||||
|
get interrupts in a 2kHz rate. |
||||||
|
''' |
||||||
|
|
||||||
|
import argparse |
||||||
|
import sys |
||||||
|
from collections import defaultdict |
||||||
|
|
||||||
|
from tools.lib.logreader import LogReader |
||||||
|
from tools.lib.route import Route |
||||||
|
|
||||||
|
import matplotlib.pyplot as plt |
||||||
|
|
||||||
|
SRC_BMX = "bmx055" |
||||||
|
SRC_LSM = "lsm6ds3" |
||||||
|
|
||||||
|
|
||||||
|
def parseEvents(log_reader): |
||||||
|
bmx_data = defaultdict(list) |
||||||
|
lsm_data = defaultdict(list) |
||||||
|
|
||||||
|
for m in log_reader: |
||||||
|
# only sensorEvents |
||||||
|
if m.which() != 'sensorEvents': |
||||||
|
continue |
||||||
|
|
||||||
|
for se in m.sensorEvents: |
||||||
|
# convert data to dictionary |
||||||
|
d = se.to_dict() |
||||||
|
|
||||||
|
if d["timestamp"] == 0: |
||||||
|
continue # empty event? |
||||||
|
|
||||||
|
if d["source"] == SRC_BMX and "acceleration" in d: |
||||||
|
bmx_data["accel"].append(d["timestamp"] / 1e9) |
||||||
|
|
||||||
|
if d["source"] == SRC_BMX and "gyroUncalibrated" in d: |
||||||
|
bmx_data["gyro"].append(d["timestamp"] / 1e9) |
||||||
|
|
||||||
|
if d["source"] == SRC_LSM and "acceleration" in d: |
||||||
|
lsm_data["accel"].append(d["timestamp"] / 1e9) |
||||||
|
|
||||||
|
if d["source"] == SRC_LSM and "gyroUncalibrated" in d: |
||||||
|
lsm_data["gyro"].append(d["timestamp"] / 1e9) |
||||||
|
|
||||||
|
return bmx_data, lsm_data |
||||||
|
|
||||||
|
|
||||||
|
def cleanData(data): |
||||||
|
if len(data) == 0: |
||||||
|
return [], [] |
||||||
|
|
||||||
|
data.sort() |
||||||
|
prev = data[0] |
||||||
|
diffs = [] |
||||||
|
for v in data[1:]: |
||||||
|
diffs.append(v - prev) |
||||||
|
prev = v |
||||||
|
return data, diffs |
||||||
|
|
||||||
|
|
||||||
|
def logAvgValues(data, sensor): |
||||||
|
if len(data) == 0: |
||||||
|
print(f"{sensor}: no data to average") |
||||||
|
return |
||||||
|
|
||||||
|
avg = sum(data) / len(data) |
||||||
|
hz = 1 / avg |
||||||
|
print(f"{sensor}: data_points: {len(data)} avg [ns]: {avg} avg [Hz]: {hz}") |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
parser = argparse.ArgumentParser() |
||||||
|
parser.add_argument("route", type=str, help="route name") |
||||||
|
parser.add_argument("segment", type=int, help="segment number") |
||||||
|
args = parser.parse_args() |
||||||
|
|
||||||
|
r = Route(args.route) |
||||||
|
logs = r.log_paths() |
||||||
|
|
||||||
|
if len(logs) == 0: |
||||||
|
print("NO data routes") |
||||||
|
sys.exit(0) |
||||||
|
|
||||||
|
if args.segment >= len(logs): |
||||||
|
print(f"RouteID: {args.segment} out of range, max: {len(logs) -1}") |
||||||
|
sys.exit(0) |
||||||
|
|
||||||
|
lr = LogReader(logs[args.segment]) |
||||||
|
bmx_data, lsm_data = parseEvents(lr) |
||||||
|
|
||||||
|
# sort bmx accel data, and then cal all the diffs, and to a histogram of those |
||||||
|
bmx_accel, bmx_accel_diffs = cleanData(bmx_data["accel"]) |
||||||
|
bmx_gyro, bmx_gyro_diffs = cleanData(bmx_data["gyro"]) |
||||||
|
lsm_accel, lsm_accel_diffs = cleanData(lsm_data["accel"]) |
||||||
|
lsm_gyro, lsm_gyro_diffs = cleanData(lsm_data["gyro"]) |
||||||
|
|
||||||
|
# get out the averages |
||||||
|
logAvgValues(bmx_accel_diffs, "bmx accel") |
||||||
|
logAvgValues(bmx_gyro_diffs, "bmx gyro ") |
||||||
|
logAvgValues(lsm_accel_diffs, "lsm accel") |
||||||
|
logAvgValues(lsm_gyro_diffs, "lsm gyro ") |
||||||
|
|
||||||
|
fig, axs = plt.subplots(1, 2, tight_layout=True) |
||||||
|
axs[0].hist(bmx_accel_diffs, bins=50) |
||||||
|
axs[0].set_title("bmx_accel") |
||||||
|
axs[1].hist(bmx_gyro_diffs, bins=50) |
||||||
|
axs[1].set_title("bmx_gyro") |
||||||
|
|
||||||
|
figl, axsl = plt.subplots(1, 2, tight_layout=True) |
||||||
|
axsl[0].hist(lsm_accel_diffs, bins=50) |
||||||
|
axsl[0].set_title("lsm_accel") |
||||||
|
axsl[1].hist(lsm_gyro_diffs, bins=50) |
||||||
|
axsl[1].set_title("lsm_gyro") |
||||||
|
|
||||||
|
print("check plot...") |
||||||
|
plt.show() |
||||||
|
|
Loading…
Reference in new issue