1
Fork 0

factored auto into separate crate

This commit is contained in:
Andy Killorin 2025-03-08 17:21:55 -05:00
parent 9d107d6c26
commit 05c7904513
Signed by: ank
GPG key ID: 23F9463ECB67FE8C
5 changed files with 5276 additions and 84 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
**/target

5178
auto/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

8
auto/Cargo.toml Normal file
View 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
View 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))
}
}

View file

@ -3,109 +3,41 @@ use std::{collections::VecDeque, ops::{Div, Sub}};
use common::{CamState, ControlPacket, SensorData};
use anyhow::Result;
struct AutoConfig {
pub struct AutoConfig {
turn_gain: 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 {
/// change active command, fails if not in control
fn run_command(&self, command: ControlPacket) -> Result<()> {unimplemented!()}
fn sensor_data(&self) -> SensorData {unimplemented!()}
fn cam_state(&self) -> CamState {unimplemented!()}
async fn sensor_update(&self) -> SensorData {unimplemented!()}
pub fn run_command(&self, command: ControlPacket) -> Result<()> {unimplemented!()}
pub fn sensor_data(&self) -> SensorData {unimplemented!()}
pub fn cam_state(&self) -> CamState {unimplemented!()}
pub async fn sensor_update(&self) -> SensorData {unimplemented!()}
/// disable auto
fn disable(&self) {unimplemented!()}
pub fn disable(&self) {unimplemented!()}
/// request auto enable, fails if the driver does not grant it
fn enable(&self) -> Result<()> {unimplemented!()}
fn enabled(&self) -> bool {unimplemented!()}
fn auto_conf(&self) -> AutoConfig {unimplemented!()}
pub fn enable(&self) -> Result<()> {unimplemented!()}
pub fn enabled(&self) -> bool {unimplemented!()}
pub fn auto_conf(&self) -> AutoConfig {unimplemented!()}
fn send_message(&self, message: String) {unimplemented!()}
}
struct Configurable {
name: &'static str,
default: f32,
min: f32,
max: f32,
pub struct Configurable {
pub name: &'static str,
pub default: f32,
pub min: f32,
pub max: f32,
}
/// A fake trait in the sense that these methods are exposed as symbols, not trait methods
trait Auto {
pub trait Auto {
/// entrypoint
async fn run(interface: &AutoInterface);
/// register
fn default_configs() -> [Configurable];
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))
}
}