Skip to content

Commit 708fb42

Browse files
committed
2 parents cfc0712 + d554ddb commit 708fb42

File tree

13 files changed

+149
-95
lines changed

13 files changed

+149
-95
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ perf.data**
3838
perf.data
3939

4040
.allow-ws
41+
.idea
4142

4243
embedded/target/

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ workspace = false
3838
command = "cargo"
3939
args = ["run", "--features=production", "-p", "lunabot", "--profile", "optdebug", "--", "main"]
4040

41+
[tasks.checkmain]
42+
workspace=false
43+
command = "cargo"
44+
args = ["check", "--features=production", "-p", "lunabot", "--profile", "optdebug"]
45+
4146
[tasks.dataviz]
4247
workspace = false
4348
command = "cargo"
@@ -111,4 +116,4 @@ args = ["run", "-p", "lunaserver-web-client", "--", "10601"]
111116
[tasks.lunaserver-web-client-audio]
112117
workspace = false
113118
command = "cargo"
114-
args = ["run", "-p", "lunaserver-web-client", "--", "10602"]
119+
args = ["run", "-p", "lunaserver-web-client", "--", "10602"]

embedded/imu_chip/build.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,20 @@
88
//! updating `memory.x` ensures a rebuild of the application with the
99
//! new memory settings.
1010
11-
use std::env;
11+
use std::env::{self, VarError};
1212
use std::fs::File;
1313
use std::io::Write;
1414
use std::path::PathBuf;
1515

1616
fn main() {
17+
if let Err(e) = std::env::var("IMU_SERIAL") {
18+
if e == VarError::NotPresent {
19+
println!("cargo:warning=IMU_SERIAL environment variable not set");
20+
} else {
21+
println!("cargo:warning=IMU_SERIAL environment variable not set to a valid value");
22+
}
23+
}
24+
1725
// Put `memory.x` in our output directory and ensure it's
1826
// on the linker search path.
1927
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());

lunabotics/.idea/.gitignore

Lines changed: 0 additions & 8 deletions
This file was deleted.

lunabotics/.idea/lunabotics.iml

Lines changed: 0 additions & 15 deletions
This file was deleted.

lunabotics/.idea/modules.xml

Lines changed: 0 additions & 8 deletions
This file was deleted.

lunabotics/.idea/vcs.xml

Lines changed: 0 additions & 6 deletions
This file was deleted.

lunabotics/lunabot/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ rodio = { version = "0.20.1", optional = true }
3939
tokio-serial = { version = "5.4.5", optional = true }
4040
mio = { version = "1", optional = true }
4141
file-lock = { version = "2.1.11", optional = true }
42+
imu-fusion = { version = "0.2.5", optional = true }
4243

4344
[features]
4445
production = [
@@ -55,5 +56,6 @@ production = [
5556
"mio",
5657
"embedded_common",
5758
"file-lock",
59+
"imu-fusion",
5860
]
5961
experimental = ["opus", "production", "rodio"]

lunabotics/lunabot/src/apps/production/rp2040.rs

Lines changed: 101 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,34 @@
1-
21
use std::sync::mpsc::{Receiver, SyncSender};
32

43
use embedded_common::*;
54
use fxhash::FxHashMap;
65
use nalgebra::Vector3;
76
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+
};
916
use tokio_serial::SerialPortBuilderExt;
1017
use tracing::{debug, error, info, warn};
1118
use udev::{EventType, MonitorBuilder, Udev};
12-
19+
use imu_fusion::{FusionAhrsSettings, Fusion};
20+
use crossbeam::queue::ArrayQueue;
21+
use std::time::Instant;
1322
use crate::localization::LocalizerRef;
1423

1524
use super::udev_poll;
1625

26+
type TIMESTAMP = f32;
27+
pub enum IMUReading {
28+
Acceleration((Vector3<f32>, TIMESTAMP)),
29+
AngularRate((Vector3<f32>, TIMESTAMP))
30+
}
31+
1732
pub struct IMUInfo {
1833
pub node: StaticImmutableNode,
1934
}
@@ -23,31 +38,63 @@ pub fn enumerate_imus(
2338
serial_to_chain: impl IntoIterator<Item = (String, IMUInfo)>,
2439
) {
2540
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+
2681
let mut threads: FxHashMap<String, SyncSender<String>> = serial_to_chain
2782
.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+
})
5198
.collect();
5299

53100
std::thread::spawn(move || {
@@ -104,9 +151,7 @@ pub fn enumerate_imus(
104151
.chain(
105152
udev_poll(listener)
106153
.filter(|event| event.event_type() == EventType::Add)
107-
.map(|event| {
108-
event.device()
109-
}),
154+
.map(|event| event.device()),
110155
)
111156
.for_each(|device| {
112157
let Some(path) = device.devnode() else {
@@ -123,10 +168,14 @@ pub fn enumerate_imus(
123168
return;
124169
};
125170
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+
}
126175
return;
127176
};
128177
serial = tmp;
129-
178+
130179
if let Some(path_sender) = threads.get(serial) {
131180
if path_sender.send(path_str.into()).is_err() {
132181
threads.remove(serial);
@@ -138,13 +187,13 @@ pub fn enumerate_imus(
138187
});
139188
}
140189

141-
struct IMUTask<'a> {
190+
struct IMUTask{
142191
path: Receiver<String>,
143-
localizer: &'a LocalizerRef,
144192
node: StaticImmutableNode,
193+
queue: &'static ArrayQueue<IMUReading>,
145194
}
146195

147-
impl<'a> IMUTask<'a> {
196+
impl IMUTask {
148197
async fn imu_task(&mut self) {
149198
let path_str = match self.path.recv() {
150199
Ok(x) => x,
@@ -169,14 +218,16 @@ impl<'a> IMUTask<'a> {
169218
let mut imu_port = BufStream::new(imu_port);
170219
let mut data: [u8; 13] = [0; 13];
171220

221+
let start = Instant::now();
172222
loop {
173223
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
174224
const ACK: [u8; 1] = [1];
175225
let result = async {
176226
imu_port.write(&ACK).await?;
177227
imu_port.flush().await?;
178228
imu_port.read_exact(&mut data).await
179-
}.await;
229+
}
230+
.await;
180231
if let Err(e) = result {
181232
error!("Failed to read/write to IMU: {e}");
182233
break;
@@ -190,18 +241,19 @@ impl<'a> IMUTask<'a> {
190241
};
191242
match msg {
192243
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+
}
200249
}
201250
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+
}
205257
}
206258
FromIMU::NoDataReady => {
207259
continue;
@@ -242,8 +294,10 @@ async fn imu_wifi_listener() {
242294
let Ok(line_str) = std::str::from_utf8(&line) else {
243295
continue;
244296
};
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);
247301
line.drain(0..=i);
248302
}
249303
Err(e) => {
@@ -254,4 +308,4 @@ async fn imu_wifi_listener() {
254308
}
255309
});
256310
}
257-
}
311+
}

0 commit comments

Comments
 (0)