2022-03-28 22:46:58 +01:00
|
|
|
#include "motor_cluster.hpp"
|
|
|
|
#include "pwm.hpp"
|
|
|
|
#include <cstdio>
|
2022-04-09 01:41:42 +01:00
|
|
|
#include "math.h"
|
2022-03-28 22:46:58 +01:00
|
|
|
|
|
|
|
namespace motor {
|
2022-04-09 01:41:42 +01:00
|
|
|
MotorCluster::MotorCluster(PIO pio, uint sm, uint pin_base, uint pin_pair_count, Direction direction,
|
|
|
|
float speed_scale, float deadzone, float freq, DecayMode mode,
|
2022-04-05 16:53:36 +01:00
|
|
|
bool auto_phase, PWMCluster::Sequence *seq_buffer, PWMCluster::TransitionData *dat_buffer)
|
|
|
|
: pwms(pio, sm, pin_base, (pin_pair_count * 2), seq_buffer, dat_buffer), pwm_frequency(freq) {
|
2022-04-09 01:41:42 +01:00
|
|
|
create_motor_states(direction, speed_scale, deadzone, mode, auto_phase);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
MotorCluster::MotorCluster(PIO pio, uint sm, const pin_pair *pin_pairs, uint32_t length, Direction direction,
|
|
|
|
float speed_scale, float deadzone, float freq, DecayMode mode,
|
2022-04-05 16:53:36 +01:00
|
|
|
bool auto_phase, PWMCluster::Sequence *seq_buffer, PWMCluster::TransitionData *dat_buffer)
|
|
|
|
: pwms(pio, sm, pin_pairs, length, seq_buffer, dat_buffer), pwm_frequency(freq) {
|
2022-04-09 01:41:42 +01:00
|
|
|
create_motor_states(direction, speed_scale, deadzone, mode, auto_phase);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
MotorCluster::MotorCluster(PIO pio, uint sm, std::initializer_list<pin_pair> pin_pairs, Direction direction,
|
|
|
|
float speed_scale, float deadzone, float freq, DecayMode mode,
|
2022-04-05 16:53:36 +01:00
|
|
|
bool auto_phase, PWMCluster::Sequence *seq_buffer, PWMCluster::TransitionData *dat_buffer)
|
|
|
|
: pwms(pio, sm, pin_pairs, seq_buffer, dat_buffer), pwm_frequency(freq) {
|
2022-04-09 01:41:42 +01:00
|
|
|
create_motor_states(direction, speed_scale, deadzone, mode, auto_phase);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
MotorCluster::~MotorCluster() {
|
|
|
|
delete[] states;
|
|
|
|
delete[] motor_phases;
|
2022-04-09 01:41:42 +01:00
|
|
|
delete[] motor_modes;
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MotorCluster::init() {
|
|
|
|
bool success = false;
|
|
|
|
|
|
|
|
if(pwms.init()) {
|
|
|
|
// Calculate a suitable pwm wrap period for this frequency
|
|
|
|
uint32_t period; uint32_t div256;
|
|
|
|
if(pimoroni::PWMCluster::calculate_pwm_factors(pwm_frequency, period, div256)) {
|
|
|
|
pwm_period = period;
|
|
|
|
|
|
|
|
// Update the pwm before setting the new wrap
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
2022-04-05 16:53:36 +01:00
|
|
|
pwms.set_chan_level(motor_positive(motor), 0, false);
|
|
|
|
pwms.set_chan_level(motor_negative(motor), 0, false);
|
|
|
|
pwms.set_chan_offset(motor_positive(motor), (uint32_t)(motor_phases[motor] * (float)pwm_period), false);
|
|
|
|
pwms.set_chan_offset(motor_negative(motor), (uint32_t)(motor_phases[motor] * (float)pwm_period), false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set the new wrap (should be 1 less than the period to get full 0 to 100%)
|
|
|
|
pwms.set_wrap(pwm_period, true); // NOTE Minus 1 not needed here. Maybe should change Wrap behaviour so it is needed, for consistency with hardware pwm?
|
|
|
|
|
|
|
|
// Apply the new divider
|
|
|
|
// This is done after loading new PWM speeds to avoid a lockup condition
|
|
|
|
uint8_t div = div256 >> 8;
|
|
|
|
uint8_t mod = div256 % 256;
|
|
|
|
pwms.set_clkdiv_int_frac(div, mod);
|
|
|
|
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t MotorCluster::count() const {
|
2022-04-05 16:53:36 +01:00
|
|
|
return pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-05 16:53:36 +01:00
|
|
|
pin_pair MotorCluster::pins(uint8_t motor) const {
|
|
|
|
return pwms.get_chan_pin_pair(motor);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::enable(uint8_t motor, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-04 20:00:03 +01:00
|
|
|
float new_duty = states[motor].enable_with_return();
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::enable(const uint8_t *motors, uint8_t length, bool load) {
|
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
enable(motors[i], false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::enable(std::initializer_list<uint8_t> motors, bool load) {
|
|
|
|
for(auto motor : motors) {
|
|
|
|
enable(motor, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::enable_all(bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
enable(motor, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::disable(uint8_t motor, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-04 20:00:03 +01:00
|
|
|
float new_duty = states[motor].disable_with_return();
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::disable(const uint8_t *motors, uint8_t length, bool load) {
|
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
disable(motors[i], false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::disable(std::initializer_list<uint8_t> motors, bool load) {
|
|
|
|
for(auto motor : motors) {
|
|
|
|
disable(motor, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::disable_all(bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
disable(motor, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MotorCluster::is_enabled(uint8_t motor) const {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-03-28 22:46:58 +01:00
|
|
|
return states[motor].is_enabled();
|
|
|
|
}
|
|
|
|
|
2022-04-04 20:00:03 +01:00
|
|
|
float MotorCluster::duty(uint8_t motor) const {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-04 20:00:03 +01:00
|
|
|
return states[motor].get_duty();
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-04 20:00:03 +01:00
|
|
|
void MotorCluster::duty(uint8_t motor, float duty, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-04 20:00:03 +01:00
|
|
|
float new_duty = states[motor].set_duty_with_return(duty);
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-04 20:00:03 +01:00
|
|
|
void MotorCluster::duty(const uint8_t *motors, uint8_t length, float duty, bool load) {
|
2022-03-28 22:46:58 +01:00
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
2022-04-04 20:00:03 +01:00
|
|
|
this->duty(motors[i], duty, false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
2022-04-04 20:00:03 +01:00
|
|
|
void MotorCluster::duty(std::initializer_list<uint8_t> motors, float duty, bool load) {
|
2022-03-28 22:46:58 +01:00
|
|
|
for(auto motor : motors) {
|
2022-04-04 20:00:03 +01:00
|
|
|
this->duty(motor, duty, false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
2022-04-04 20:00:03 +01:00
|
|
|
void MotorCluster::all_to_duty(float duty, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
2022-04-04 20:00:03 +01:00
|
|
|
this->duty(motor, duty, false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
float MotorCluster::speed(uint8_t motor) const {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-03-28 22:46:58 +01:00
|
|
|
return states[motor].get_speed();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::speed(uint8_t motor, float speed, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-04 20:00:03 +01:00
|
|
|
float new_duty = states[motor].set_speed_with_return(speed);
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::speed(const uint8_t *motors, uint8_t length, float speed, bool load) {
|
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
this->speed(motors[i], speed, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::speed(std::initializer_list<uint8_t> motors, float speed, bool load) {
|
|
|
|
for(auto motor : motors) {
|
|
|
|
this->speed(motor, speed, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::all_to_speed(float speed, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
this->speed(motor, speed, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
float MotorCluster::phase(uint8_t motor) const {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-03-28 22:46:58 +01:00
|
|
|
return motor_phases[motor];
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::phase(uint8_t motor, float phase, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-03-28 22:46:58 +01:00
|
|
|
motor_phases[motor] = MIN(MAX(phase, 0.0f), 1.0f);
|
|
|
|
pwms.set_chan_offset(motor, (uint32_t)(motor_phases[motor] * (float)pwms.get_wrap()), load);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::phase(const uint8_t *motors, uint8_t length, float phase, bool load) {
|
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
this->phase(motors[i], phase, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::phase(std::initializer_list<uint8_t> motors, float phase, bool load) {
|
|
|
|
for(auto motor : motors) {
|
|
|
|
this->phase(motor, phase, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::all_to_phase(float phase, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
this->phase(motor, phase, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
float MotorCluster::frequency() const {
|
|
|
|
return pwm_frequency;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MotorCluster::frequency(float freq) {
|
|
|
|
bool success = false;
|
|
|
|
|
|
|
|
if((freq >= MotorState::MIN_FREQUENCY) && (freq <= MotorState::MAX_FREQUENCY)) {
|
|
|
|
// Calculate a suitable pwm wrap period for this frequency
|
|
|
|
uint32_t period; uint32_t div256;
|
|
|
|
if(pimoroni::PWMCluster::calculate_pwm_factors(freq, period, div256)) {
|
|
|
|
|
|
|
|
pwm_period = period;
|
|
|
|
pwm_frequency = freq;
|
|
|
|
|
|
|
|
// Update the pwm before setting the new wrap
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint motor = 0; motor < motor_count; motor++) {
|
|
|
|
if(states[motor].is_enabled()) {
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, states[motor].get_deadzoned_duty(), motor_modes[motor], false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
2022-04-05 16:53:36 +01:00
|
|
|
pwms.set_chan_offset(motor_positive(motor), (uint32_t)(motor_phases[motor] * (float)pwm_period), false);
|
|
|
|
pwms.set_chan_offset(motor_negative(motor), (uint32_t)(motor_phases[motor] * (float)pwm_period), false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set the new wrap (should be 1 less than the period to get full 0 to 100%)
|
|
|
|
pwms.set_wrap(pwm_period, true);
|
|
|
|
|
|
|
|
// Apply the new divider
|
|
|
|
uint16_t div = div256 >> 8;
|
|
|
|
uint8_t mod = div256 % 256;
|
|
|
|
pwms.set_clkdiv_int_frac(div, mod);
|
|
|
|
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2022-04-05 16:53:36 +01:00
|
|
|
void MotorCluster::stop(uint8_t motor, bool load) {
|
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
|
|
|
float new_duty = states[motor].stop_with_return();
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::stop(const uint8_t *motors, uint8_t length, bool load) {
|
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
this->stop(motors[i], false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::stop(std::initializer_list<uint8_t> motors, bool load) {
|
|
|
|
for(auto motor : motors) {
|
|
|
|
this->stop(motor, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::stop_all(bool load) {
|
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
this->stop(motor, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::coast(uint8_t motor, bool load) {
|
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
|
|
|
states[motor].set_duty_with_return(0.0f);
|
|
|
|
float new_duty = states[motor].disable_with_return();
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::coast(const uint8_t *motors, uint8_t length, bool load) {
|
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
this->coast(motors[i], false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::coast(std::initializer_list<uint8_t> motors, bool load) {
|
|
|
|
for(auto motor : motors) {
|
|
|
|
this->coast(motor, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::coast_all(bool load) {
|
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
this->coast(motor, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-05 16:53:36 +01:00
|
|
|
void MotorCluster::full_negative(uint8_t motor, bool load) {
|
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
|
|
|
float new_duty = states[motor].full_negative_with_return();
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-05 16:53:36 +01:00
|
|
|
void MotorCluster::full_negative(const uint8_t *motors, uint8_t length, bool load) {
|
2022-03-28 22:46:58 +01:00
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
2022-04-05 16:53:36 +01:00
|
|
|
this->full_negative(motors[i], false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
2022-04-05 16:53:36 +01:00
|
|
|
void MotorCluster::full_negative(std::initializer_list<uint8_t> motors, bool load) {
|
2022-03-28 22:46:58 +01:00
|
|
|
for(auto motor : motors) {
|
2022-04-05 16:53:36 +01:00
|
|
|
this->full_negative(motor, false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::all_full_negative(bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
2022-04-05 16:53:36 +01:00
|
|
|
this->full_negative(motor, false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
2022-04-05 16:53:36 +01:00
|
|
|
void MotorCluster::full_positive(uint8_t motor, bool load) {
|
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
|
|
|
float new_duty = states[motor].full_positive_with_return();
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-05 16:53:36 +01:00
|
|
|
void MotorCluster::full_positive(const uint8_t *motors, uint8_t length, bool load) {
|
2022-03-28 22:46:58 +01:00
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
2022-04-05 16:53:36 +01:00
|
|
|
this->full_positive(motors[i], false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
2022-04-05 16:53:36 +01:00
|
|
|
void MotorCluster::full_positive(std::initializer_list<uint8_t> motors, bool load) {
|
2022-03-28 22:46:58 +01:00
|
|
|
for(auto motor : motors) {
|
2022-04-05 16:53:36 +01:00
|
|
|
this->full_positive(motor, false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::all_full_positive(bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
2022-04-05 16:53:36 +01:00
|
|
|
this->full_positive(motor, false);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::to_percent(uint8_t motor, float in, float in_min, float in_max, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-04 20:00:03 +01:00
|
|
|
float new_duty = states[motor].to_percent_with_return(in, in_min, in_max);
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::to_percent(const uint8_t *motors, uint8_t length, float in, float in_min, float in_max, bool load) {
|
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
to_percent(motors[i], in, in_min, in_max, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::to_percent(std::initializer_list<uint8_t> motors, float in, float in_min, float in_max, bool load) {
|
|
|
|
for(auto motor : motors) {
|
|
|
|
to_percent(motor, in, in_min, in_max, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::all_to_percent(float in, float in_min, float in_max, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
to_percent(motor, in, in_min, in_max, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::to_percent(uint8_t motor, float in, float in_min, float in_max, float speed_min, float speed_max, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-04 20:00:03 +01:00
|
|
|
float new_duty = states[motor].to_percent_with_return(in, in_min, in_max, speed_min, speed_max);
|
2022-04-09 01:41:42 +01:00
|
|
|
apply_duty(motor, new_duty, motor_modes[motor], load);
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::to_percent(const uint8_t *motors, uint8_t length, float in, float in_min, float in_max, float speed_min, float speed_max, bool load) {
|
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
to_percent(motors[i], in, in_min, in_max, speed_min, speed_max, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::to_percent(std::initializer_list<uint8_t> motors, float in, float in_min, float in_max, float speed_min, float speed_max, bool load) {
|
|
|
|
for(auto motor : motors) {
|
|
|
|
to_percent(motor, in, in_min, in_max, speed_min, speed_max, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::all_to_percent(float in, float in_min, float in_max, float speed_min, float speed_max, bool load) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
to_percent(motor, in, in_min, in_max, speed_min, speed_max, false);
|
|
|
|
}
|
|
|
|
if(load)
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::load() {
|
|
|
|
pwms.load_pwm();
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
Direction MotorCluster::direction(uint8_t motor) const {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
|
|
|
return states[motor].get_direction();
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::direction(uint8_t motor, Direction direction) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
|
|
|
states[motor].set_direction(direction);
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::direction(const uint8_t *motors, uint8_t length, Direction direction) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
this->direction(motors[i], direction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::direction(std::initializer_list<uint8_t> motors, Direction direction) {
|
2022-04-05 16:53:36 +01:00
|
|
|
for(auto motor : motors) {
|
|
|
|
this->direction(motor, direction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::all_directions(Direction direction) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
this->direction(motor, direction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float MotorCluster::speed_scale(uint8_t motor) const {
|
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
|
|
|
return states[motor].get_speed_scale();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::speed_scale(uint8_t motor, float speed_scale) {
|
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
|
|
|
states[motor].set_speed_scale(speed_scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::speed_scale(const uint8_t *motors, uint8_t length, float speed_scale) {
|
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
this->speed_scale(motors[i], speed_scale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::speed_scale(std::initializer_list<uint8_t> motors, float speed_scale) {
|
|
|
|
for(auto motor : motors) {
|
|
|
|
this->speed_scale(motor, speed_scale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MotorCluster::all_speed_scales(float speed_scale) {
|
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
this->speed_scale(motor, speed_scale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
float MotorCluster::deadzone(uint8_t motor) const {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-09 01:41:42 +01:00
|
|
|
return states[motor].get_deadzone();
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::deadzone(uint8_t motor, float deadzone) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-09 01:41:42 +01:00
|
|
|
states[motor].set_deadzone_with_return(deadzone); //TODO
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::deadzone(const uint8_t *motors, uint8_t length, float deadzone) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
2022-04-09 01:41:42 +01:00
|
|
|
this->deadzone(motors[i], deadzone);
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::deadzone(std::initializer_list<uint8_t> motors, float deadzone) {
|
2022-04-05 16:53:36 +01:00
|
|
|
for(auto motor : motors) {
|
2022-04-09 01:41:42 +01:00
|
|
|
this->deadzone(motor, deadzone);
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::all_deadzones(float deadzone) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
2022-04-09 01:41:42 +01:00
|
|
|
this->deadzone(motor, deadzone);
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
DecayMode MotorCluster::decay_mode(uint8_t motor) const {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
2022-04-09 01:41:42 +01:00
|
|
|
return SLOW_DECAY;//TODO states[motor].get_decay_mode();
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::decay_mode(uint8_t motor, DecayMode mode) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motor < pwms.get_chan_pair_count());
|
|
|
|
//TODO states[motor].set_decay_mode(mode);
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::decay_mode(const uint8_t *motors, uint8_t length, DecayMode mode) {
|
2022-04-05 16:53:36 +01:00
|
|
|
assert(motors != nullptr);
|
|
|
|
for(uint8_t i = 0; i < length; i++) {
|
|
|
|
this->decay_mode(motors[i], mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::decay_mode(std::initializer_list<uint8_t> motors, DecayMode mode) {
|
2022-04-05 16:53:36 +01:00
|
|
|
for(auto motor : motors) {
|
|
|
|
this->decay_mode(motor, mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::all_to_decay_mode(DecayMode mode) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
|
|
|
for(uint8_t motor = 0; motor < motor_count; motor++) {
|
|
|
|
this->decay_mode(motor, mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::apply_duty(uint8_t motor, float duty, DecayMode mode, bool load) {
|
|
|
|
if(isfinite(duty)) {
|
|
|
|
int32_t signed_level = MotorState::duty_to_level(duty, pwm_period);
|
2022-04-05 16:53:36 +01:00
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
switch(mode) {
|
|
|
|
case SLOW_DECAY: //aka 'Braking'
|
|
|
|
if(signed_level >= 0) {
|
|
|
|
pwms.set_chan_level(motor_positive(motor), pwm_period, false);
|
|
|
|
pwms.set_chan_level(motor_negative(motor), pwm_period - signed_level, load);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pwms.set_chan_level(motor_positive(motor), pwm_period + signed_level, false);
|
|
|
|
pwms.set_chan_level(motor_negative(motor), pwm_period, load);
|
|
|
|
}
|
|
|
|
break;
|
2022-04-05 16:53:36 +01:00
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
case FAST_DECAY: //aka 'Coasting'
|
|
|
|
default:
|
|
|
|
if(signed_level >= 0) {
|
|
|
|
pwms.set_chan_level(motor_positive(motor), signed_level, false);
|
|
|
|
pwms.set_chan_level(motor_negative(motor), 0, load);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pwms.set_chan_level(motor_positive(motor), 0, false);
|
|
|
|
pwms.set_chan_level(motor_negative(motor), 0 - signed_level, load);
|
|
|
|
}
|
|
|
|
break;
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
2022-04-09 01:41:42 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
pwms.set_chan_level(motor_positive(motor), 0, false);
|
|
|
|
pwms.set_chan_level(motor_negative(motor), 0, load);
|
2022-04-05 16:53:36 +01:00
|
|
|
}
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
|
2022-04-09 01:41:42 +01:00
|
|
|
void MotorCluster::create_motor_states(Direction direction, float speed_scale,
|
|
|
|
float deadzone, DecayMode mode, bool auto_phase) {
|
2022-04-05 16:53:36 +01:00
|
|
|
uint8_t motor_count = pwms.get_chan_pair_count();
|
2022-03-28 22:46:58 +01:00
|
|
|
if(motor_count > 0) {
|
|
|
|
states = new MotorState[motor_count];
|
|
|
|
motor_phases = new float[motor_count];
|
2022-04-09 01:41:42 +01:00
|
|
|
motor_modes = new DecayMode[motor_count];
|
2022-03-28 22:46:58 +01:00
|
|
|
|
|
|
|
for(uint motor = 0; motor < motor_count; motor++) {
|
2022-04-09 01:41:42 +01:00
|
|
|
states[motor] = MotorState(direction, speed_scale, deadzone);
|
2022-03-28 22:46:58 +01:00
|
|
|
motor_phases[motor] = (auto_phase) ? (float)motor / (float)motor_count : 0.0f;
|
2022-04-09 01:41:42 +01:00
|
|
|
motor_modes[motor] = mode;
|
2022-03-28 22:46:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|