use fixed::types::I16F16;
use rtt_target::rprintln;
use crate::{
foc::{EDir, EFocMode},
tools::foc_pid::FocPid,
EFocAngle, EFocSimpleError, Result, ShaftPosition,
};
pub struct FocSimple {
shaft_position_req: ShaftPosition,
foc_mode: EFocMode,
calibration_state: ECalibrateState,
torque: I16F16, target_pid: FocPid,
shaft_position_act: ShaftPosition,
velocity: I16F16, nr_poles: usize,
electrical_offset: I16F16, timestamp_vel: usize,
speed_req: I16F16,
speed_acc: I16F16, speed_act: I16F16,
temp: I16F16,
}
#[derive(Debug)]
#[repr(u8)]
enum ECalibrateState {
Init = 0,
FindDirection,
FindOffset,
ReturnToStart,
}
impl FocSimple {
pub fn new(nr_poles: usize) -> FocSimple {
FocSimple {
shaft_position_req: ShaftPosition::new(),
torque: I16F16::ZERO,
foc_mode: EFocMode::Idle,
electrical_offset: I16F16::ZERO,
velocity: I16F16::ZERO, shaft_position_act: ShaftPosition::new(),
nr_poles,
calibration_state: ECalibrateState::Init,
target_pid: FocPid::new(I16F16::ONE, I16F16::ONE, I16F16::ONE),
timestamp_vel: 0,
temp: I16F16::ZERO,
speed_req: I16F16::ZERO,
speed_acc: I16F16::ONE / 10, speed_act: I16F16::ZERO,
}
}
pub fn set_speed(&mut self, speed: I16F16) {
self.speed_req = speed;
}
pub fn set_torque(&mut self, torque: I16F16) {
self.torque = torque;
}
pub fn set_angle(&mut self, angle: I16F16) {
if let EFocMode::Angle(_) = self.foc_mode {
self.shaft_position_req.angle = angle;
}
}
pub fn set_position(&mut self, position: ShaftPosition) {
if let EFocMode::Angle(_) = self.foc_mode {
self.shaft_position_req = position;
}
}
pub fn set_acceleration(&mut self, acc: I16F16) {
self.speed_acc = acc / 100; }
pub fn set_electrical_offset(&mut self, offset: I16F16) {
self.electrical_offset = offset;
}
pub fn is_idle(&self) -> bool {
self.foc_mode == EFocMode::Idle
}
pub fn get_velocity(&self) -> I16F16 {
self.velocity
}
pub fn get_position_act(&self) -> ShaftPosition {
self.shaft_position_act
}
pub fn get_position_req(&self) -> ShaftPosition {
self.shaft_position_req
}
pub fn set_position_req(&mut self, req: ShaftPosition) {
self.shaft_position_req = req;
}
pub fn set_foc_mode(&mut self, mode: EFocMode) -> Result<()> {
rprintln!("Set Foc mode");
self.foc_mode = mode;
match self.foc_mode {
EFocMode::Calibration(param) => match param {
Some(p) => {
self.electrical_offset = p.zero;
self.shaft_position_act.set_inversed(p.dir == EDir::Ccw);
self.foc_mode = EFocMode::Idle;
}
None => {
self.electrical_offset = I16F16::ZERO;
self.shaft_position_act.set_inversed(false);
self.calibration_state = ECalibrateState::Init;
if self.torque < I16F16::ONE/10 {
self.torque = I16F16::ONE/4;
}
}
},
EFocMode::Angle(param) => {
self.target_pid = FocPid::new(param.p, param.i, param.d);
self.target_pid.set_integral_max(I16F16::ONE * 3);
self.shaft_position_req = self.shaft_position_act.clone();
}
EFocMode::Velocity(param) => {
self.speed_req = I16F16::ZERO;
self.speed_act = I16F16::ZERO;
self.shaft_position_req = self.shaft_position_act.clone();
self.target_pid = FocPid::new(param.p, param.i, param.d);
self.target_pid.set_integral_max(I16F16::ONE * 20);
}
EFocMode::Torque(param) => {
self.torque = I16F16::ZERO;
self.target_pid = FocPid::new(param.p, param.i, param.d);
self.target_pid.set_integral_max(I16F16::ONE);
}
EFocMode::Idle => (),
EFocMode::Error(e) => return Err(e),
}
Ok(())
}
pub fn update(&mut self, angle: EFocAngle) -> Result<(I16F16, I16F16)> {
let electrical_angle = match angle {
EFocAngle::SensorLess => I16F16::ZERO,
EFocAngle::SensorValue(angle) => {
self.shaft_position_act.update_shaft_angle(angle);
I16F16::from_num(self.nr_poles) * self.shaft_position_act.angle - self.electrical_offset
}
EFocAngle::Interpolate => {
I16F16::from_num(self.nr_poles) * self.shaft_position_act.angle - self.electrical_offset
}
};
match self.foc_mode {
EFocMode::Idle => Ok((electrical_angle, I16F16::ZERO)),
EFocMode::Error(e) => Err(e),
EFocMode::Calibration(_) => match angle {
EFocAngle::SensorLess => Err(EFocSimpleError::NoAngleSensor),
_ => self.do_calibration(),
},
EFocMode::Angle(_) => {
match angle {
EFocAngle::SensorLess => Err(EFocSimpleError::NoAngleSensor),
_ => {
let torque = self
.target_pid
.update_position(&self.shaft_position_req, &self.shaft_position_act);
Ok((electrical_angle, torque))
}
}
}
EFocMode::Velocity(_) => {
match angle {
EFocAngle::SensorLess => {
let delta_electrical_angle = I16F16::from_num(self.nr_poles) * self.speed_act / 1000;
self.shaft_position_req.inc(delta_electrical_angle); let request_angle = self.shaft_position_req.get_angle();
Ok((request_angle, I16F16::ONE / 4))
}
_ => {
let diff = self.shaft_position_req.compare(&self.shaft_position_act);
if diff.abs() < I16F16::PI {
let delta_angle = self.speed_act / 1000;
self.shaft_position_req.inc(delta_angle);
}
let requested_torque = self
.target_pid
.update_position(&self.shaft_position_req, &self.shaft_position_act);
Ok((electrical_angle, requested_torque))
}
}
}
EFocMode::Torque(_) => match angle {
EFocAngle::SensorLess => Err(EFocSimpleError::NoAngleSensor),
_ => Ok((electrical_angle, self.torque)),
},
}
}
pub fn update_velocity(&mut self, ts: usize) {
self.update_speed();
let delta_ts = ts - self.timestamp_vel;
if delta_ts > 0 {
self.timestamp_vel = ts;
let delta_sec = I16F16::from_num(delta_ts) / 1_000;
let position_delta = self.shaft_position_act.delta();
let velocity_current = position_delta / delta_sec;
self.velocity = (velocity_current + 19 * self.velocity) / 20;
}
}
#[inline]
fn update_speed(&mut self) {
let req = self.speed_req;
if self.speed_acc == 0 {
self.speed_act = req;
} else {
let mut act = self.speed_act;
if act > req {
act -= self.speed_acc;
if act < req {
act = req;
}
} else if act < req {
act += self.speed_acc;
if act > req {
act = req;
}
} self.speed_act = act;
}
}
fn do_calibration(&mut self) -> Result<(I16F16, I16F16)> {
let req = self.shaft_position_req;
let act = self.shaft_position_act;
match self.calibration_state {
ECalibrateState::Init => {
self.shaft_position_req.reset();
self.shaft_position_act.reset();
self.electrical_offset = I16F16::ZERO;
self.calibration_state = ECalibrateState::FindDirection
}
ECalibrateState::FindDirection => {
if req.rotations > 1 {
if act.rotations == 0 && act.angle == I16F16::ZERO {
self.calibration_state = ECalibrateState::Init;
self.foc_mode = EFocMode::Error(EFocSimpleError::NoMotorMovement);
rprintln!("End condition No motor movement detected");
} else {
if act.get_position() < 0 {
rprintln!("Direction inversed");
self.shaft_position_act.set_inversed(true);
} else {
rprintln!("Direction not inversed");
self.shaft_position_act.set_inversed(false);
}
self.calibration_state = ECalibrateState::FindOffset;
}
} else {
self.shaft_position_req.inc(I16F16::from_num(0.01));
}
}
ECalibrateState::FindOffset => {
if req.rotations > 2 && req.angle > 3 * I16F16::FRAC_TAU_4 {
let offset = self.shaft_position_act.get_angle() * self.nr_poles as i32;
self.electrical_offset = ShaftPosition::clamp(offset);
self.calibration_state = ECalibrateState::ReturnToStart;
rprintln!("Electrical offset:{}", self.electrical_offset);
} else {
self.shaft_position_req.inc(I16F16::from_num(0.01));
}
}
ECalibrateState::ReturnToStart => {
if req.rotations == 0 && req.angle < I16F16::FRAC_TAU_2 {
self.foc_mode = EFocMode::Idle;
rprintln!("Calibraton finished");
} else {
self.shaft_position_req.inc(I16F16::from_num(-0.01));
}
}
}
Ok((self.shaft_position_req.get_angle(), self.torque.abs()))
}
}