-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SNS - Optical Flow #32
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,127 @@ | ||||||||||||
use crate::spi::HypedSpi; | ||||||||||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; | ||||||||||||
use byteorder::{LittleEndian, ReadBytesExt}; | ||||||||||||
use std::thread::sleep; | ||||||||||||
use serde::{Serialize, Deserialize}; | ||||||||||||
use serde_json::json; | ||||||||||||
|
||||||||||||
|
||||||||||||
// implement get_motion function first | ||||||||||||
// add readByteFromRegister (?) function to HypedSPI trait which takes register address and gives data | ||||||||||||
|
||||||||||||
const REG_MOTION_BURST: u8 = 0x16; | ||||||||||||
const TIMEOUT: Duration = Duration::from_secs(5); | ||||||||||||
|
||||||||||||
|
||||||||||||
pub struct PMW3901<SPI> { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
It's also standard to have single uppercase characters as type parameters, like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probs better to call this |
||||||||||||
spi: SPI, | ||||||||||||
|
||||||||||||
} | ||||||||||||
|
||||||||||||
impl<SPI> PMW3901<SPI> | ||||||||||||
where | ||||||||||||
SPI: HypedSpi, | ||||||||||||
{ | ||||||||||||
Comment on lines
+21
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
You should be able to do something shorter like this instead |
||||||||||||
|
||||||||||||
|
||||||||||||
pub fn new(spi: SPI) -> Self { | ||||||||||||
PMW3901 { spi } | ||||||||||||
} | ||||||||||||
|
||||||||||||
// **ATTEMPTED PYTHON IMPLEMENTATION OF get_motion** | ||||||||||||
pub fn get_motion(&mut self) -> Result<(i16, i16), &'static str>{ | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You'll want to define an error enum type like |
||||||||||||
let start = Instant::now(); | ||||||||||||
|
||||||||||||
|
||||||||||||
while start.elapsed() < TIMEOUT { | ||||||||||||
// Send burst read command and read 12 bytes | ||||||||||||
let mut data = [0u8; 13]; // Includes the command byte | ||||||||||||
data[0] = REG_MOTION_BURST; // first element in data is the register | ||||||||||||
self.spi.read(&mut data).map_err(|_| "SPI read failed")?; //read data using HypedSpi trait | ||||||||||||
|
||||||||||||
// Parse the response data | ||||||||||||
let mut cursor = &data[1..]; //slice data and use cursor to go thrugh the data | ||||||||||||
let _ = cursor.read_u8().unwrap(); // read each byte from cursor and assign it to variables | ||||||||||||
let dr = cursor.read_u8().unwrap(); | ||||||||||||
let obs = cursor.read_u8().unwrap(); | ||||||||||||
let x = cursor.read_i16::<LittleEndian>().unwrap(); // x and y value is what we need and little endian is used to make sure bytes are ordered ith LSB first | ||||||||||||
let y = cursor.read_i16::<LittleEndian>().unwrap(); // LittleEndian takes (advances) 2 bytes from cursor | ||||||||||||
let quality = cursor.read_u8().unwrap(); | ||||||||||||
let raw_sum = cursor.read_u8().unwrap(); | ||||||||||||
let raw_max = cursor.read_u8().unwrap(); | ||||||||||||
let raw_min = cursor.read_u8().unwrap(); | ||||||||||||
let shutter_upper = cursor.read_u8().unwrap(); | ||||||||||||
let shutter_lower = cursor.read_u8().unwrap(); | ||||||||||||
|
||||||||||||
if (dr & 0b1000_0000) != 0 && (quality >= 0x19 || shutter_upper != 0x1F) { | ||||||||||||
return Ok((x, y)); // Return delta x and y if valid | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Delay before retrying | ||||||||||||
sleep(Duration::from_millis(10)); | ||||||||||||
|
||||||||||||
} | ||||||||||||
|
||||||||||||
Err("Timed out waiting for motion data") | ||||||||||||
} | ||||||||||||
|
||||||||||||
} | ||||||||||||
|
||||||||||||
|
||||||||||||
// the # implements the Serialize trait from the serde crate for the strcuts. this is apparantly needed to convert strcut to json | ||||||||||||
#[derive(Serialize)] | ||||||||||||
struct Measurement { | ||||||||||||
header: Header, | ||||||||||||
payload: Payload, | ||||||||||||
} | ||||||||||||
|
||||||||||||
#[derive(Serialize)] | ||||||||||||
struct Header { | ||||||||||||
timestamp: u64, | ||||||||||||
priority: u8, | ||||||||||||
} | ||||||||||||
|
||||||||||||
#[derive(Serialize)] | ||||||||||||
struct Payload { | ||||||||||||
x: i16, | ||||||||||||
y: i16, | ||||||||||||
} | ||||||||||||
|
||||||||||||
|
||||||||||||
// Make main function with flexible error handling | ||||||||||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function won't live here, it'll be in one of the |
||||||||||||
|
||||||||||||
|
||||||||||||
let spi = HypedSPI::new() // spi implementation? | ||||||||||||
let mut sensor = PMW3901::new(spi); | ||||||||||||
|
||||||||||||
|
||||||||||||
// While loop implementation from python code | ||||||||||||
loop { | ||||||||||||
|
||||||||||||
// Get motion data | ||||||||||||
let (x, y) = sensor.get_motion()?; | ||||||||||||
|
||||||||||||
// Prepare measurement data | ||||||||||||
let measurement = Measurement { | ||||||||||||
header: Header { | ||||||||||||
timestamp: SystemTime::now() | ||||||||||||
.duration_since(UNIX_EPOCH)? // Get time in secs from epoch as in the python code | ||||||||||||
.as_secs(), | ||||||||||||
priority: 1, | ||||||||||||
}, | ||||||||||||
payload: Payload { x, y }, | ||||||||||||
}; | ||||||||||||
|
||||||||||||
// Serialize measurement data to JSON | ||||||||||||
let measurement_data = serde_json::to_string(&measurement)?; | ||||||||||||
|
||||||||||||
// Print payload | ||||||||||||
//println!("{}", measurement_data); | ||||||||||||
|
||||||||||||
|
||||||||||||
// delay | ||||||||||||
sleep(Duration::from_millis(50)); | ||||||||||||
|
||||||||||||
} | ||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move to
lib/sensors/src/optical_flow.rs
(you'll need to add it tolib/sensors/src/lib.rs
too