1
-
2
1
use std:: sync:: mpsc:: { Receiver , SyncSender } ;
3
2
4
3
use embedded_common:: * ;
5
4
use fxhash:: FxHashMap ;
6
5
use nalgebra:: Vector3 ;
7
6
use simple_motion:: StaticImmutableNode ;
8
- use tasker:: { get_tokio_handle, tokio:: { self , io:: { AsyncReadExt , AsyncWriteExt , BufStream } , net:: TcpListener } , BlockOn } ;
7
+ use tasker:: {
8
+ get_tokio_handle,
9
+ tokio:: {
10
+ self ,
11
+ io:: { AsyncReadExt , AsyncWriteExt , BufStream } ,
12
+ net:: TcpListener ,
13
+ } ,
14
+ BlockOn ,
15
+ } ;
9
16
use tokio_serial:: SerialPortBuilderExt ;
10
17
use tracing:: { debug, error, info, warn} ;
11
18
use udev:: { EventType , MonitorBuilder , Udev } ;
12
-
19
+ use imu_fusion:: { FusionAhrsSettings , Fusion } ;
20
+ use crossbeam:: queue:: ArrayQueue ;
21
+ use std:: time:: Instant ;
13
22
use crate :: localization:: LocalizerRef ;
14
23
15
24
use super :: udev_poll;
16
25
26
+ type TIMESTAMP = f32 ;
27
+ pub enum IMUReading {
28
+ Acceleration ( ( Vector3 < f32 > , TIMESTAMP ) ) ,
29
+ AngularRate ( ( Vector3 < f32 > , TIMESTAMP ) )
30
+ }
31
+
17
32
pub struct IMUInfo {
18
33
pub node : StaticImmutableNode ,
19
34
}
@@ -23,31 +38,63 @@ pub fn enumerate_imus(
23
38
serial_to_chain : impl IntoIterator < Item = ( String , IMUInfo ) > ,
24
39
) {
25
40
get_tokio_handle ( ) . spawn ( imu_wifi_listener ( ) ) ;
41
+ let data_queue: Box < ArrayQueue < IMUReading > > = Box :: new ( ArrayQueue :: new ( 64 ) ) ;
42
+ let data_queue_ref: & ' static ArrayQueue < IMUReading > = Box :: leak ( data_queue) ;
43
+
44
+ std:: thread:: spawn ( move || {
45
+ const SAMPLE_RATE_HZ : u32 = 100 ;
46
+ let settings = FusionAhrsSettings :: new ( ) ;
47
+ let mut fusion = Fusion :: new ( SAMPLE_RATE_HZ , settings) ;
48
+
49
+ let mut reading: Option < IMUReading > = None ;
50
+ let mut reading_accel: Option < ( Vector3 < f32 > , TIMESTAMP ) > = None ;
51
+ let mut reading_gyro: Option < ( Vector3 < f32 > , TIMESTAMP ) > = None ;
52
+ loop {
53
+ reading = data_queue_ref. pop ( ) ;
54
+ if let Some ( IMUReading :: Acceleration ( reading) ) = reading {
55
+ reading_accel = Some ( reading) ;
56
+ }
57
+ if let Some ( IMUReading :: AngularRate ( reading) ) = reading {
58
+ reading_gyro = Some ( reading) ;
59
+ }
60
+
61
+ // not using take up here because we dont want to consume more accel readings than gyro readings or vice versa
62
+ if reading_accel. is_some ( ) && reading_gyro. is_some ( ) {
63
+ let ( Some ( ( accel, timestamp_accel) ) , Some ( ( gyro, timestamp_gyro) ) ) = ( reading_accel. take ( ) , reading_gyro. take ( ) ) else {
64
+ continue ;
65
+ } ;
66
+
67
+ if ( timestamp_accel-timestamp_gyro) . abs ( ) > 1. {
68
+ tracing:: warn!( "acceleration and gyro timestamps were more than 1 seconds apart" ) ;
69
+ }
70
+
71
+ let avg = ( timestamp_accel+timestamp_gyro) /2.0 ;
72
+
73
+ fusion. update_no_mag ( gyro. into ( ) , accel. into ( ) , avg) ;
74
+ let acc = fusion. ahrs . linear_acc ( ) ;
75
+ tracing:: info!( "x: {}, y: {}, z: {}" , acc. x, acc. y, acc. z) ;
76
+ }
77
+ }
78
+ } ) ;
79
+
80
+
26
81
let mut threads: FxHashMap < String , SyncSender < String > > = serial_to_chain
27
82
. into_iter ( )
28
- . filter_map (
29
- |(
30
- port,
31
- IMUInfo {
32
- node
33
- } ,
34
- ) | {
35
- let port2 = port. clone ( ) ;
36
- let localizer_ref = localizer_ref. clone ( ) ;
37
- let ( tx, rx) = std:: sync:: mpsc:: sync_channel ( 1 ) ;
38
- std:: thread:: spawn ( move || {
39
- let mut imu_task = IMUTask {
40
- path : rx,
41
- localizer : & localizer_ref,
42
- node,
43
- } ;
44
- loop {
45
- imu_task. imu_task ( ) . block_on ( ) ;
46
- }
47
- } ) ;
48
- Some ( ( port2, tx) )
49
- } ,
50
- )
83
+ . filter_map ( |( port, IMUInfo { node } ) | {
84
+ let port2 = port. clone ( ) ;
85
+ let ( tx, rx) = std:: sync:: mpsc:: sync_channel ( 1 ) ;
86
+ std:: thread:: spawn ( move || {
87
+ let mut imu_task = IMUTask {
88
+ path : rx,
89
+ node,
90
+ queue : data_queue_ref
91
+ } ;
92
+ loop {
93
+ imu_task. imu_task ( ) . block_on ( ) ;
94
+ }
95
+ } ) ;
96
+ Some ( ( port2, tx) )
97
+ } )
51
98
. collect ( ) ;
52
99
53
100
std:: thread:: spawn ( move || {
@@ -104,9 +151,7 @@ pub fn enumerate_imus(
104
151
. chain (
105
152
udev_poll ( listener)
106
153
. filter ( |event| event. event_type ( ) == EventType :: Add )
107
- . map ( |event| {
108
- event. device ( )
109
- } ) ,
154
+ . map ( |event| event. device ( ) ) ,
110
155
)
111
156
. for_each ( |device| {
112
157
let Some ( path) = device. devnode ( ) else {
@@ -123,10 +168,14 @@ pub fn enumerate_imus(
123
168
return ;
124
169
} ;
125
170
let Some ( tmp) = serial. strip_prefix ( "USR_IMU_" ) else {
171
+ if serial == "USR_IMU" {
172
+ warn ! ( "IMU at path {path_str} has no serial number" ) ;
173
+ return ;
174
+ }
126
175
return ;
127
176
} ;
128
177
serial = tmp;
129
-
178
+
130
179
if let Some ( path_sender) = threads. get ( serial) {
131
180
if path_sender. send ( path_str. into ( ) ) . is_err ( ) {
132
181
threads. remove ( serial) ;
@@ -138,13 +187,13 @@ pub fn enumerate_imus(
138
187
} ) ;
139
188
}
140
189
141
- struct IMUTask < ' a > {
190
+ struct IMUTask {
142
191
path : Receiver < String > ,
143
- localizer : & ' a LocalizerRef ,
144
192
node : StaticImmutableNode ,
193
+ queue : & ' static ArrayQueue < IMUReading > ,
145
194
}
146
195
147
- impl < ' a > IMUTask < ' a > {
196
+ impl IMUTask {
148
197
async fn imu_task ( & mut self ) {
149
198
let path_str = match self . path . recv ( ) {
150
199
Ok ( x) => x,
@@ -169,14 +218,16 @@ impl<'a> IMUTask<'a> {
169
218
let mut imu_port = BufStream :: new ( imu_port) ;
170
219
let mut data: [ u8 ; 13 ] = [ 0 ; 13 ] ;
171
220
221
+ let start = Instant :: now ( ) ;
172
222
loop {
173
223
tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) . await ;
174
224
const ACK : [ u8 ; 1 ] = [ 1 ] ;
175
225
let result = async {
176
226
imu_port. write ( & ACK ) . await ?;
177
227
imu_port. flush ( ) . await ?;
178
228
imu_port. read_exact ( & mut data) . await
179
- } . await ;
229
+ }
230
+ . await ;
180
231
if let Err ( e) = result {
181
232
error ! ( "Failed to read/write to IMU: {e}" ) ;
182
233
break ;
@@ -190,18 +241,19 @@ impl<'a> IMUTask<'a> {
190
241
} ;
191
242
match msg {
192
243
FromIMU :: AngularRateReading ( AngularRate { x, y, z } ) => {
193
- // euler angle to axis angle
194
- // transform
195
- // axis angle to euler angle
196
- // let accel: Vector3<f64> = Vector3::new(x, -z, -y).cast();
197
-
198
- tracing:: info!( "{x:1},{y:1},{z:1}" ) ;
199
-
244
+ let angular_velocity = Vector3 :: new ( -x, z, y) ;
245
+ let transformed = self . node . get_local_isometry ( ) . cast ( ) * angular_velocity;
246
+ if let Err ( e) = self . queue . push ( IMUReading :: AngularRate ( ( transformed, start. elapsed ( ) . as_secs_f32 ( ) ) ) ) {
247
+ tracing:: warn!( "couldn't push gyro reading to crossbeam queue" ) ;
248
+ }
200
249
}
201
250
FromIMU :: AccelerationNormReading ( AccelerationNorm { x, y, z } ) => {
202
- let accel: Vector3 < f64 > = Vector3 :: new ( x, -z, -y) . cast ( ) ;
203
- self . localizer . set_acceleration ( self . node . get_local_isometry ( ) * accel) ;
204
- //tracing::info!("{:?}", self.node.get_local_isometry() * accel);
251
+ let accel = Vector3 :: new ( x, -z, -y) ;
252
+ let transformed = self . node . get_local_isometry ( ) . cast ( ) * accel;
253
+
254
+ if let Err ( e) = self . queue . push ( IMUReading :: Acceleration ( ( transformed, start. elapsed ( ) . as_secs_f32 ( ) ) ) ) {
255
+ tracing:: warn!( "couldn't push accel reading to crossbeam queue" ) ;
256
+ }
205
257
}
206
258
FromIMU :: NoDataReady => {
207
259
continue ;
@@ -242,8 +294,10 @@ async fn imu_wifi_listener() {
242
294
let Ok ( line_str) = std:: str:: from_utf8 ( & line) else {
243
295
continue ;
244
296
} ;
245
- let Some ( i) = line_str. find ( '\n' ) else { continue ; } ;
246
- error ! ( target=addr. to_string( ) , "{}" , line_str. split_at( i) . 0 ) ;
297
+ let Some ( i) = line_str. find ( '\n' ) else {
298
+ continue ;
299
+ } ;
300
+ error ! ( target = addr. to_string( ) , "{}" , line_str. split_at( i) . 0 ) ;
247
301
line. drain ( 0 ..=i) ;
248
302
}
249
303
Err ( e) => {
@@ -254,4 +308,4 @@ async fn imu_wifi_listener() {
254
308
}
255
309
} ) ;
256
310
}
257
- }
311
+ }
0 commit comments