owb_core/utils/controllers/
i2c.rs1use crate::utils;
7use core::cell::RefCell;
8
9use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
10use embedded_hal::i2c::I2c;
11use embedded_hal_bus::i2c::RefCellDevice;
12use icm42670::{
13 accelerometer::{Accelerometer, Error as AccelerometerError},
14 Address as ImuAddress, Error as ImuError, Icm42670, PowerMode,
15};
16use pwm_pca9685::{Address as PwmAddress, Channel, Error as PwmError, Pca9685};
17use serde::{Deserialize, Serialize};
18
19pub static I2C_CHANNEL: embassy_sync::channel::Channel<CriticalSectionRawMutex, I2CCommand, 16> =
21 embassy_sync::channel::Channel::new();
22
23#[derive(Debug)]
25pub enum DeviceError<E: core::fmt::Debug> {
26 PwmError(PwmError<E>),
27 ImuError(ImuError<E>),
28 AccelError(AccelerometerError<ImuError<E>>),
29 ImuNotInitialized,
30 PwmNotInitialized,
31}
32
33#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
37#[serde(tag = "ic", rename_all = "snake_case")]
38pub enum I2CCommand {
39 T { d: f32, s: f32 },
42 Y { s: f32, o: Option<f32> },
44 O {
46 d: f32,
47 s: f32,
48 rs: f32,
49 o: Option<f32>,
50 },
51
52 ReadIMU,
55 Enable,
57 Disable,
59}
60
61pub struct I2CDevices<'a, I2C: 'static> {
63 #[allow(dead_code)]
64 i2c: &'a RefCell<I2C>,
65 pub pwm: Option<Pca9685<RefCellDevice<'a, I2C>>>,
66 imu: Option<Icm42670<RefCellDevice<'a, I2C>>>,
67 motor_channels: [(Channel, Channel); 3],
68 embodied: utils::ek,
69}
70
71impl<'a, I2C, E> I2CDevices<'a, I2C>
72where
73 I2C: I2c<Error = E> + 'static,
74 E: core::fmt::Debug,
75{
76 pub fn new(
78 i2c_bus: &'a RefCell<I2C>,
79 wheel_radius: f32,
80 robot_radius: f32,
81 ) -> Self {
82 I2CDevices {
83 i2c: i2c_bus,
84 pwm: None,
85 imu: None,
86 motor_channels: [
87 (Channel::C6, Channel::C7),
88 (Channel::C2, Channel::C3),
89 (Channel::C4, Channel::C5),
90 ],
91 embodied: utils::ek::new(wheel_radius, robot_radius),
92 }
93 }
94 pub fn init_devices(&mut self) -> Result<(), DeviceError<E>> {
98 let imu = Icm42670::new(RefCellDevice::new(&self.i2c), ImuAddress::Primary)
99 .map_err(DeviceError::ImuError)?;
100 let pwm = Pca9685::new(RefCellDevice::new(&self.i2c), PwmAddress::from(0x55))
101 .map_err(DeviceError::PwmError)?;
102
103 self.imu = Some(imu);
104 self.pwm = Some(pwm);
105 Ok(())
106 }
107 pub fn scan_bus(&self) {
109 let mut bus = self.i2c.borrow_mut();
110 for addr in 0x03..0x78 {
111 if bus.write(addr, &[]).is_ok() {
112 tracing::warn!("I2C device found at 0x{:02X}", addr);
113 }
114 }
115 }
116 pub fn configure_pwm(&mut self) -> Result<(), DeviceError<E>> {
118 if let Some(pca) = &mut self.pwm {
119 pca.enable().map_err(DeviceError::PwmError)?;
120 tracing::info!("PWM enabled");
121 pca.set_prescale(100).map_err(DeviceError::PwmError)?;
122 tracing::info!("PWM prescale set to 60Hz");
123 } else {
124 tracing::error!("PWM not initialized");
125 }
126
127 Ok(())
128 }
129 pub fn init_imu_data(&mut self) {
131 match self.read_imu() {
132 Ok((accel, gyro, temp)) => {
133 tracing::info!("Initial IMU read successful:");
134 tracing::info!("Accelerometer: {:?}", accel);
135 tracing::info!("Gyroscope: {:?}", gyro);
136 tracing::info!("Temperature: {:?}", temp);
137 }
138 Err(e) => {
139 tracing::error!("Failed to read IMU data: {:?}", e);
140 }
141 }
142 }
143
144 pub fn execute_command(
148 &mut self,
149 command: I2CCommand,
150 ) -> Result<Option<((f32, f32, f32), (f32, f32, f32), f32)>, DeviceError<E>> {
151 match command {
152 I2CCommand::T { d, s } => {
153 self.set_motor_velocities_strafe(d, s)?;
154 Ok(None)
155 }
156 I2CCommand::Y { s, o } => {
157 self.set_motor_velocities_rotate(s, o)?;
158 Ok(None)
159 }
160 I2CCommand::O { d, s, rs, o } => {
161 let orientation = o.unwrap_or(0.0);
162 let new_orientation = (orientation + rs) % 360.0;
163 let wheel_speeds =
164 self.embodied
165 .compute_wheel_velocities(s, d, new_orientation, rs);
166 self.apply_wheel_speeds(&wheel_speeds)?;
167 Ok(None)
168 }
169 I2CCommand::ReadIMU => Ok(Some(self.read_imu()?)),
170 I2CCommand::Enable => {
171 self.enable()?;
172 Ok(None)
173 }
174 I2CCommand::Disable => {
175 self.disable()?;
176 Ok(None)
177 }
178 }
179 }
180
181 fn set_motor_velocities_strafe(
183 &mut self,
184 direction: f32,
185 speed: f32,
186 ) -> Result<(), DeviceError<E>> {
187 let wheel_speeds = self
188 .embodied
189 .compute_wheel_velocities(speed, direction, 0.0, 0.0);
190 self.apply_wheel_speeds(&wheel_speeds)
191 }
192
193 fn set_motor_velocities_rotate(
195 &mut self,
196 speed: f32,
197 orientation: Option<f32>,
198 ) -> Result<(), DeviceError<E>> {
199 let new_orientation = (orientation.unwrap_or(0.0) + speed) % 360.0;
200 let wheel_speeds = self
201 .embodied
202 .compute_wheel_velocities(0.0, 0.0, new_orientation, speed);
203 self.apply_wheel_speeds(&wheel_speeds)
204 }
205
206 pub fn apply_wheel_speeds(
208 &mut self,
209 wheel_speeds: &[f32],
210 ) -> Result<(), DeviceError<E>> {
211 const MAX_DUTY: u16 = 4095;
212
213 for (i, &(phase_channel, enable_channel)) in self.motor_channels.iter().enumerate() {
214 let speed = wheel_speeds[i].abs().min(1.0);
215 let direction = wheel_speeds[i] >= 0.0;
216
217 if let Some(pca) = &mut self.pwm {
218 pca.set_channel_on_off(phase_channel, 0, if direction { 0 } else { MAX_DUTY })
219 .map_err(DeviceError::PwmError)?;
220 pca.set_channel_on_off(enable_channel, 0, (speed * MAX_DUTY as f32) as u16)
221 .map_err(DeviceError::PwmError)?;
222 } else {
223 tracing::error!("PWM not initialized");
224 }
225 }
226 Ok(())
227 }
228 #[allow(dead_code)]
229 fn apply_wheels_bulk(
230 &mut self,
231 _wheels: &[f32],
232 ) -> Result<(), DeviceError<E>> {
233 todo!("Need to implement function for bulk all on and off for simulations changes")
234 }
235
236 pub fn read_imu(&mut self) -> Result<((f32, f32, f32), (f32, f32, f32), f32), DeviceError<E>> {
242 let imu = self.imu.as_mut().ok_or(DeviceError::ImuNotInitialized)?;
243 let accel = imu.accel_norm().map_err(DeviceError::AccelError)?;
244 let gyro = imu.gyro_norm().map_err(DeviceError::ImuError)?;
245 let temp = imu.temperature().map_err(DeviceError::ImuError)?;
246
247 Ok(((accel.x, accel.y, accel.z), (gyro.x, gyro.y, gyro.z), temp))
248 }
249
250 pub fn enable(&mut self) -> Result<(), DeviceError<E>> {
252 if let Some(pca) = self.pwm.as_mut() {
253 pca.enable().map_err(DeviceError::PwmError)?;
254 }
255
256 if let Some(imu) = self.imu.as_mut() {
257 imu.set_power_mode(PowerMode::SixAxisLowNoise)
258 .map_err(DeviceError::ImuError)?;
259 }
260
261 Ok(())
262 }
263
264 pub fn disable(&mut self) -> Result<(), DeviceError<E>> {
266 if let Some(pca) = self.pwm.as_mut() {
267 pca.disable().map_err(DeviceError::PwmError)?;
268 }
269
270 if let Some(imu) = self.imu.as_mut() {
271 imu.set_power_mode(PowerMode::Sleep)
272 .map_err(DeviceError::ImuError)?;
273 }
274
275 Ok(())
276 }
277}