factored auto into separate crate
This commit is contained in:
parent
9d107d6c26
commit
05c7904513
5 changed files with 5276 additions and 84 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
**/target
|
5178
auto/Cargo.lock
generated
Normal file
5178
auto/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
8
auto/Cargo.toml
Normal file
8
auto/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "auto"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
common = {path = "../common"}
|
||||||
|
interface = {path = "../interface"}
|
73
auto/src/lib.rs
Normal file
73
auto/src/lib.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
use std::{collections::VecDeque, ops::Sub};
|
||||||
|
|
||||||
|
use common::CamState;
|
||||||
|
use interface::auto::AutoInterface;
|
||||||
|
|
||||||
|
const AUTO_GAP: i16 = 140; /// mm tofs must drop to count as a hit
|
||||||
|
const AUTO_SELF_OCCLUSION: u16 = 130; /// minimum
|
||||||
|
|
||||||
|
async fn auto (interface: &AutoInterface) {
|
||||||
|
let mut tof_l = Stats::new();
|
||||||
|
let mut tof_r = Stats::new();
|
||||||
|
loop {
|
||||||
|
let data = interface.sensor_update().await;
|
||||||
|
let cam = interface.cam_state();
|
||||||
|
let CamState::Charged = cam else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(latest_tof_l) = data.tof_l else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
tof_l.update(latest_tof_l as i16);
|
||||||
|
let Some(latest_tof_r) = data.tof_r else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
tof_r.update(latest_tof_r as i16);
|
||||||
|
|
||||||
|
let detection = |latest: u16, delta: i16| {
|
||||||
|
delta < AUTO_GAP && latest > AUTO_SELF_OCCLUSION
|
||||||
|
};
|
||||||
|
|
||||||
|
if detection(latest_tof_l, tof_l.delta()) || detection(latest_tof_l, tof_l.delta()) {
|
||||||
|
if let Ok(()) = interface.enable() {
|
||||||
|
println!("found, now seek")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Stats<T> {
|
||||||
|
table: VecDeque<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Stats<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { table: VecDeque::new() }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_ELEMENTS: usize = 3;
|
||||||
|
|
||||||
|
pub fn update(&mut self, elem: T) {
|
||||||
|
self.table.push_front(elem);
|
||||||
|
if self.table.len() > Self::MAX_ELEMENTS {
|
||||||
|
self.table.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Ord + Sub<Output = T> + Copy + From<u8>> Stats<T> {
|
||||||
|
pub fn delta(&self) -> T {
|
||||||
|
*self.table.get(0).unwrap_or(&T::from(0)) - *self.table.get(1).unwrap_or(&T::from(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max(&self) -> T {
|
||||||
|
*self.table.iter().max().unwrap_or(&T::from(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn min(&self) -> T {
|
||||||
|
*self.table.iter().max().unwrap_or(&T::from(0))
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,109 +3,41 @@ use std::{collections::VecDeque, ops::{Div, Sub}};
|
||||||
use common::{CamState, ControlPacket, SensorData};
|
use common::{CamState, ControlPacket, SensorData};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
struct AutoConfig {
|
pub struct AutoConfig {
|
||||||
turn_gain: f32,
|
turn_gain: f32,
|
||||||
auto_fire_distance: f32,
|
auto_fire_distance: f32,
|
||||||
}
|
}
|
||||||
const AUTO_GAP: i16 = 140; /// mm tofs must drop to count as a hit
|
|
||||||
const AUTO_SELF_OCCLUSION: u16 = 130; /// minimum
|
|
||||||
|
|
||||||
struct AutoInterface {
|
pub struct AutoInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AutoInterface {
|
impl AutoInterface {
|
||||||
/// change active command, fails if not in control
|
/// change active command, fails if not in control
|
||||||
fn run_command(&self, command: ControlPacket) -> Result<()> {unimplemented!()}
|
pub fn run_command(&self, command: ControlPacket) -> Result<()> {unimplemented!()}
|
||||||
fn sensor_data(&self) -> SensorData {unimplemented!()}
|
pub fn sensor_data(&self) -> SensorData {unimplemented!()}
|
||||||
fn cam_state(&self) -> CamState {unimplemented!()}
|
pub fn cam_state(&self) -> CamState {unimplemented!()}
|
||||||
async fn sensor_update(&self) -> SensorData {unimplemented!()}
|
pub async fn sensor_update(&self) -> SensorData {unimplemented!()}
|
||||||
/// disable auto
|
/// disable auto
|
||||||
fn disable(&self) {unimplemented!()}
|
pub fn disable(&self) {unimplemented!()}
|
||||||
/// request auto enable, fails if the driver does not grant it
|
/// request auto enable, fails if the driver does not grant it
|
||||||
fn enable(&self) -> Result<()> {unimplemented!()}
|
pub fn enable(&self) -> Result<()> {unimplemented!()}
|
||||||
fn enabled(&self) -> bool {unimplemented!()}
|
pub fn enabled(&self) -> bool {unimplemented!()}
|
||||||
fn auto_conf(&self) -> AutoConfig {unimplemented!()}
|
pub fn auto_conf(&self) -> AutoConfig {unimplemented!()}
|
||||||
fn send_message(&self, message: String) {unimplemented!()}
|
fn send_message(&self, message: String) {unimplemented!()}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Configurable {
|
pub struct Configurable {
|
||||||
name: &'static str,
|
pub name: &'static str,
|
||||||
default: f32,
|
pub default: f32,
|
||||||
min: f32,
|
pub min: f32,
|
||||||
max: f32,
|
pub max: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A fake trait in the sense that these methods are exposed as symbols, not trait methods
|
/// A fake trait in the sense that these methods are exposed as symbols, not trait methods
|
||||||
trait Auto {
|
pub trait Auto {
|
||||||
/// entrypoint
|
/// entrypoint
|
||||||
async fn run(interface: &AutoInterface);
|
async fn run(interface: &AutoInterface);
|
||||||
/// register
|
/// register
|
||||||
fn default_configs() -> [Configurable];
|
fn default_configs() -> [Configurable];
|
||||||
fn name() -> &'static str;
|
fn name() -> &'static str;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn auto (interface: &AutoInterface) {
|
|
||||||
let mut tof_l = Stats::new();
|
|
||||||
let mut tof_r = Stats::new();
|
|
||||||
loop {
|
|
||||||
let data = interface.sensor_update().await;
|
|
||||||
let cam = interface.cam_state();
|
|
||||||
let CamState::Charged = cam else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(latest_tof_l) = data.tof_l else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
tof_l.update(latest_tof_l as i16);
|
|
||||||
let Some(latest_tof_r) = data.tof_r else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
tof_r.update(latest_tof_r as i16);
|
|
||||||
|
|
||||||
let detection = |latest: u16, delta: i16| {
|
|
||||||
delta < AUTO_GAP && latest > AUTO_SELF_OCCLUSION
|
|
||||||
};
|
|
||||||
|
|
||||||
if detection(latest_tof_l, tof_l.delta()) || detection(latest_tof_l, tof_l.delta()) {
|
|
||||||
if let Ok(()) = interface.enable() {
|
|
||||||
println!("found, now seek")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct Stats<T> {
|
|
||||||
table: VecDeque<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Stats<T> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self { table: VecDeque::new() }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_ELEMENTS: usize = 3;
|
|
||||||
|
|
||||||
pub fn update(&mut self, elem: T) {
|
|
||||||
self.table.push_front(elem);
|
|
||||||
if self.table.len() > Self::MAX_ELEMENTS {
|
|
||||||
self.table.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Ord + Sub<Output = T> + Copy + From<u8>> Stats<T> {
|
|
||||||
pub fn delta(&self) -> T {
|
|
||||||
*self.table.get(0).unwrap_or(&T::from(0)) - *self.table.get(1).unwrap_or(&T::from(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn max(&self) -> T {
|
|
||||||
*self.table.iter().max().unwrap_or(&T::from(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn min(&self) -> T {
|
|
||||||
*self.table.iter().max().unwrap_or(&T::from(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue