Hello everyone, I hope you are well !
I managed to introduce an error in my robot, by creating a custom error management.
This is the working code:
use arduino_uno::prelude::*;
use arduino_uno::hal::port::mode::{Floating};
const TRIGGER_UP_TIME: u16 = 10u16;
/// struct sensor_unit is instantiated in main, as it needs
/// pins and timer.
pub struct SensorUnit {
pub trig: arduino_uno::hal::port::portb::PB4<arduino_uno::hal::port::mode::Output>,
pub echo: arduino_uno::hal::port::portb::PB3<arduino_uno::hal::port::mode::Input<Floating>>,
pub timer: arduino_uno::atmega328p::TC1,
}
pub fn return_distance(sensor_unit: &mut SensorUnit) -> u16 {
let mut delay = arduino_uno::Delay::new();
sensor_unit.timer.tcnt1.write(|w| unsafe { w.bits(0) });
// void_unwrap() --> set high could return an error
// we are using a crate named void + unwrap
// if not, there will be a warning on the fact that result is not used
sensor_unit.trig.set_high().void_unwrap();
delay.delay_us(TRIGGER_UP_TIME);
sensor_unit.trig.set_low().void_unwrap();
while sensor_unit.echo.is_low().void_unwrap() {
// if more than 200 ms ( = 50000) we might have not detected anything and can continue.
if sensor_unit.timer.tcnt1.read().bits() >= 65000 {
// returning a huge value in case nothing in front
// a better way is needed!!
return 63500;
}
}
// restarting the timer by writing 0 bits to it
sensor_unit.timer.tcnt1.write(|w| unsafe { w.bits(0) });
// waiting for the echo to get low again
while sensor_unit.echo.is_high().void_unwrap() {}
// Taking the time the echo was high, which is as long as the time the signal was out.
// 1 timer count == 4 us so * 4 to get a value in microsecs
// we divide by 58 to get the distance in cm, since (34000 cm/s * 1e-6 us time)/2 (back and forth measurement)
// == 0.017 more or less 1/58
let value = (sensor_unit.timer.tcnt1.read().bits() * 4) / 58;
// !! AVR only natively supports 8 and 16 bit integers, so *do not* return bigger
u16::from(value)
}
So returning a huge value when nothing was detected after 200 ms is not a good way to do things.
So instead I tried to do that
The difference is the Result return type, a MeaurmentError or a u16.
use arduino_uno::prelude::*;
use arduino_uno::hal::port::mode::{Floating};
const TRIGGER_UP_TIME: u16 = 10u16;
pub struct SensorUnit {
pub trig: arduino_uno::hal::port::portb::PB4<arduino_uno::hal::port::mode::Output>,
pub echo: arduino_uno::hal::port::portb::PB3<arduino_uno::hal::port::mode::Input<Floating>>,
pub timer: arduino_uno::atmega328p::TC1,
}
pub struct MeasurementError;
pub fn return_distance(sensor_unit: &mut SensorUnit) -> Result<u16, MeasurementError> {
let mut delay = arduino_uno::Delay::new();
sensor_unit.timer.tcnt1.write(|w| unsafe { w.bits(0) });
sensor_unit.trig.set_high().void_unwrap();
delay.delay_us(TRIGGER_UP_TIME);
sensor_unit.trig.set_low().void_unwrap();
while sensor_unit.echo.is_low().void_unwrap() {
// if more than 200 ms ( = 50000) we might have not detected anything and can continue.
if sensor_unit.timer.tcnt1.read().bits() >= 65000 {
return Err(MeasurementError)
}
}
while sensor_unit.echo.is_high().void_unwrap() {}
let value = (sensor_unit.timer.tcnt1.read().bits() * 4) / 58;
}
But what is returned is really crappy values/random numbers. Rahix says it can be a miscompilation error. Anyone who ran into something similar? Any way to make a bulletproof custom error?