cam manager, hopefully somewhat realtime
This commit is contained in:
parent
f7ab1c119a
commit
2af0807abd
1 changed files with 114 additions and 12 deletions
|
@ -19,7 +19,8 @@ use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER};
|
||||||
use embassy_rp::i2c::{Async, I2c};
|
use embassy_rp::i2c::{Async, I2c};
|
||||||
use embassy_rp::multicore::{spawn_core1, Stack};
|
use embassy_rp::multicore::{spawn_core1, Stack};
|
||||||
use embassy_rp::pwm::{self, Pwm};
|
use embassy_rp::pwm::{self, Pwm};
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex};
|
||||||
|
use embassy_sync::blocking_mutex::{Mutex, ThreadModeMutex};
|
||||||
use embassy_sync::channel::Channel;
|
use embassy_sync::channel::Channel;
|
||||||
use embedded_hal_bus::i2c::RefCellDevice;
|
use embedded_hal_bus::i2c::RefCellDevice;
|
||||||
use fixed::FixedU16;
|
use fixed::FixedU16;
|
||||||
|
@ -30,7 +31,7 @@ use embassy_net::tcp::TcpSocket;
|
||||||
use embassy_net::{Config, StackResources};
|
use embassy_net::{Config, StackResources};
|
||||||
use embassy_rp::bind_interrupts;
|
use embassy_rp::bind_interrupts;
|
||||||
use embassy_rp::clocks::RoscRng;
|
use embassy_rp::clocks::RoscRng;
|
||||||
use embassy_rp::gpio::{Level, Output};
|
use embassy_rp::gpio::{Input, Level, Output, Pull};
|
||||||
use embassy_rp::peripherals::{DMA_CH0, PIO0, USB};
|
use embassy_rp::peripherals::{DMA_CH0, PIO0, USB};
|
||||||
use embassy_rp::pio::{InterruptHandler, Pio};
|
use embassy_rp::pio::{InterruptHandler, Pio};
|
||||||
use embassy_rp::usb::Driver;
|
use embassy_rp::usb::Driver;
|
||||||
|
@ -86,16 +87,21 @@ async fn main(spawner: Spawner) {
|
||||||
let driver = Driver::new(p.USB, Irqs);
|
let driver = Driver::new(p.USB, Irqs);
|
||||||
spawner.spawn(logger_task(driver)).unwrap();
|
spawner.spawn(logger_task(driver)).unwrap();
|
||||||
|
|
||||||
let mut flipper = Output::new(p.PIN_22, Level::Low);
|
let mut limit_switch = Input::new(p.PIN_22, Pull::Up);
|
||||||
|
|
||||||
|
let mut d: pwm::Config = Default::default();
|
||||||
|
d.divider = 40.into();
|
||||||
|
d.top = 62500; // 20ms
|
||||||
|
d.compare_b = 4687; // 1.5ms
|
||||||
|
d.compare_a = 4687; // 1.5ms
|
||||||
|
let mut drive_pwm = Pwm::new_output_ab(p.PWM_SLICE1, p.PIN_18, p.PIN_19, d.clone());
|
||||||
|
|
||||||
|
let mut f: pwm::Config = Default::default();
|
||||||
|
f.divider = 40.into();
|
||||||
|
f.top = 62500; // 20ms
|
||||||
|
f.compare_b = 4687; // 1.5ms
|
||||||
|
let flip_pwm = Pwm::new_output_b(p.PWM_SLICE0, p.PIN_17, f.clone());
|
||||||
|
|
||||||
let mut c: pwm::Config = Default::default();
|
|
||||||
c.divider = 40.into();
|
|
||||||
c.top = 62500; // 20ms
|
|
||||||
c.compare_b = 4687; // 1.5ms
|
|
||||||
c.compare_a = 4687; // 1.5ms
|
|
||||||
let mut drive_pwm = Pwm::new_output_ab(p.PWM_SLICE1, p.PIN_18, p.PIN_19, c.clone());
|
|
||||||
flipper.set_high();
|
|
||||||
|
|
||||||
let sda = p.PIN_20;
|
let sda = p.PIN_20;
|
||||||
let scl = p.PIN_21;
|
let scl = p.PIN_21;
|
||||||
let config = embassy_rp::i2c::Config::default();
|
let config = embassy_rp::i2c::Config::default();
|
||||||
|
@ -179,6 +185,12 @@ async fn main(spawner: Spawner) {
|
||||||
let mut buf = [0; 4096];
|
let mut buf = [0; 4096];
|
||||||
let mut telem_buf = [0; 4096];
|
let mut telem_buf = [0; 4096];
|
||||||
|
|
||||||
|
let cam_state: RefCell<CamState> = RefCell::new(CamState::Idle);
|
||||||
|
|
||||||
|
let cam_state_forever = unsafe { transmute(&cam_state) }; // SAFETY: if main exits we shall
|
||||||
|
// shortly die.
|
||||||
|
spawner.spawn(cam_manager(flip_pwm, limit_switch, cam_state_forever)).unwrap();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
||||||
socket.set_timeout(Some(Duration::from_secs(3)));
|
socket.set_timeout(Some(Duration::from_secs(3)));
|
||||||
|
@ -190,7 +202,7 @@ async fn main(spawner: Spawner) {
|
||||||
c.compare_a = 4687; // 1.5ms
|
c.compare_a = 4687; // 1.5ms
|
||||||
drive_pwm.set_config(&c);
|
drive_pwm.set_config(&c);
|
||||||
|
|
||||||
flipper.set_low();
|
cam_state.replace(CamState::Idle);
|
||||||
|
|
||||||
control.gpio_set(0, false).await;
|
control.gpio_set(0, false).await;
|
||||||
info!("Listening on TCP:1234...");
|
info!("Listening on TCP:1234...");
|
||||||
|
@ -220,7 +232,31 @@ async fn main(spawner: Spawner) {
|
||||||
ControlPacket::Twist(forward, right) => {
|
ControlPacket::Twist(forward, right) => {
|
||||||
info!("left to {}", clamp(forward+right, -1., 1.));
|
info!("left to {}", clamp(forward+right, -1., 1.));
|
||||||
info!("right to {}", clamp(forward-right, -1., 1.));
|
info!("right to {}", clamp(forward-right, -1., 1.));
|
||||||
|
|
||||||
|
c.compare_a = calc_speed(right + forward);
|
||||||
|
c.compare_b = calc_speed(right - forward);
|
||||||
|
drive_pwm.set_config(&c);
|
||||||
},
|
},
|
||||||
|
ControlPacket::Fire => {
|
||||||
|
cam_state.replace(CamState::Fire);
|
||||||
|
},
|
||||||
|
ControlPacket::Stop => {
|
||||||
|
c.compare_a = calc_speed(0.);
|
||||||
|
c.compare_b = calc_speed(0.);
|
||||||
|
drive_pwm.set_config(&c);
|
||||||
|
|
||||||
|
cam_state.replace(CamState::Idle);
|
||||||
|
},
|
||||||
|
ControlPacket::FireOverride(speed) => {
|
||||||
|
cam_state.replace(CamState::Override(speed));
|
||||||
|
},
|
||||||
|
ControlPacket::Arm(enable) => {
|
||||||
|
if enable {
|
||||||
|
cam_state.replace(CamState::Charging(None));
|
||||||
|
} else {
|
||||||
|
cam_state.replace(CamState::Idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
d => {error!("unimplemented: {d:?}")} // TODO
|
d => {error!("unimplemented: {d:?}")} // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,3 +277,69 @@ async fn main(spawner: Spawner) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// -1 to 1
|
||||||
|
fn calc_speed(speed: f32) -> u16 {
|
||||||
|
const COUNTS_PER_MS: f32 = 3125.;
|
||||||
|
let speed = speed.clamp(-1., 1.);
|
||||||
|
|
||||||
|
let ms = (speed/2.0)+1.5;
|
||||||
|
|
||||||
|
(COUNTS_PER_MS * ms) as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CamState {
|
||||||
|
Override(f32),
|
||||||
|
Charging(Option<Instant>),
|
||||||
|
Charged,
|
||||||
|
Fire,
|
||||||
|
Idle,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn cam_manager(mut cam: Pwm<'static>, limit: Input<'static>, cam_state: &'static RefCell<CamState>) {
|
||||||
|
loop {
|
||||||
|
let mut cam_state = cam_state.borrow_mut();
|
||||||
|
handle_cam(&mut cam, &mut (*cam_state), &limit);
|
||||||
|
drop(cam_state);
|
||||||
|
|
||||||
|
Timer::after_micros(500).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_cam(cam: &mut Pwm, state: &mut CamState, limit: &Input) {
|
||||||
|
let speed = match state {
|
||||||
|
CamState::Override(speed) => {
|
||||||
|
*speed
|
||||||
|
},
|
||||||
|
CamState::Charging(mut charged) => {
|
||||||
|
if limit.is_low() {
|
||||||
|
let became_low = charged.get_or_insert_with(Instant::now);
|
||||||
|
if became_low.elapsed().as_micros() > 1800 {
|
||||||
|
*state = CamState::Charged;
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
charged = None;
|
||||||
|
1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CamState::Fire => {
|
||||||
|
if limit.is_high() {
|
||||||
|
*state = CamState::Charging(None);
|
||||||
|
}
|
||||||
|
1.0
|
||||||
|
},
|
||||||
|
CamState::Charged | CamState::Idle => 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let mut f: pwm::Config = Default::default();
|
||||||
|
f.divider = 40.into();
|
||||||
|
f.top = 62500; // 20ms
|
||||||
|
f.compare_b = calc_speed(speed); // 1.5ms
|
||||||
|
cam.set_config(&f);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue