AP_InertialSensor: SITL the raw sample rate is not the same as the sensor rate
use regulated time for frequency noise to avoid spurious harmonics SITL sensors must be true separate instances don't compile in FFT structures if DSP disabled
This commit is contained in:
parent
83b1c3a0bd
commit
0e9b2a26c5
@ -656,6 +656,7 @@ AP_InertialSensor_Backend *AP_InertialSensor::_find_backend(int16_t backend_id,
|
||||
}
|
||||
|
||||
bool AP_InertialSensor::set_gyro_window_size(uint16_t size) {
|
||||
#if HAL_WITH_DSP
|
||||
_gyro_window_size = size;
|
||||
|
||||
// allocate FFT gyro window
|
||||
@ -676,7 +677,7 @@ bool AP_InertialSensor::set_gyro_window_size(uint16_t size) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -797,7 +798,8 @@ AP_InertialSensor::detect_backends(void)
|
||||
// IMUs defined by IMU lines in hwdef.dat
|
||||
HAL_INS_PROBE_LIST;
|
||||
#elif CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
||||
ADD_BACKEND(AP_InertialSensor_SITL::detect(*this));
|
||||
ADD_BACKEND(AP_InertialSensor_SITL::detect(*this, INS_SITL_SENSOR_A));
|
||||
ADD_BACKEND(AP_InertialSensor_SITL::detect(*this, INS_SITL_SENSOR_B));
|
||||
#elif HAL_INS_DEFAULT == HAL_INS_HIL
|
||||
ADD_BACKEND(AP_InertialSensor_HIL::detect(*this));
|
||||
#elif AP_FEATURE_BOARD_DETECT
|
||||
|
@ -153,6 +153,7 @@ public:
|
||||
uint16_t get_accel_rate_hz(uint8_t instance) const { return uint16_t(_accel_raw_sample_rates[instance] * _accel_over_sampling[instance]); }
|
||||
|
||||
// FFT support access
|
||||
#if HAL_WITH_DSP
|
||||
const Vector3f &get_raw_gyro(void) const { return _gyro_raw[_primary_gyro]; }
|
||||
GyroWindow get_raw_gyro_window(uint8_t instance, uint8_t axis) const { return _gyro_window[instance][axis]; }
|
||||
GyroWindow get_raw_gyro_window(uint8_t axis) const { return get_raw_gyro_window(_primary_gyro, axis); }
|
||||
@ -161,8 +162,8 @@ public:
|
||||
uint16_t get_raw_gyro_window_index(uint8_t instance) const { return _circular_buffer_idx[instance]; }
|
||||
uint16_t get_raw_gyro_rate_hz() const { return get_raw_gyro_rate_hz(_primary_gyro); }
|
||||
uint16_t get_raw_gyro_rate_hz(uint8_t instance) const { return _gyro_raw_sample_rates[_primary_gyro]; }
|
||||
#endif
|
||||
bool set_gyro_window_size(uint16_t size);
|
||||
|
||||
// get accel offsets in m/s/s
|
||||
const Vector3f &get_accel_offsets(uint8_t i) const { return _accel_offset[i]; }
|
||||
const Vector3f &get_accel_offsets(void) const { return get_accel_offsets(_primary_accel); }
|
||||
@ -441,13 +442,14 @@ private:
|
||||
LowPassFilter2pVector3f _gyro_filter[INS_MAX_INSTANCES];
|
||||
Vector3f _accel_filtered[INS_MAX_INSTANCES];
|
||||
Vector3f _gyro_filtered[INS_MAX_INSTANCES];
|
||||
#if HAL_WITH_DSP
|
||||
// Thread-safe public version of _last_raw_gyro
|
||||
Vector3f _gyro_raw[INS_MAX_INSTANCES];
|
||||
// circular buffer of gyro data for frequency analysis
|
||||
uint16_t _circular_buffer_idx[INS_MAX_INSTANCES];
|
||||
GyroWindow _gyro_window[INS_MAX_INSTANCES][XYZ_AXIS_COUNT];
|
||||
uint16_t _gyro_window_size;
|
||||
|
||||
#endif
|
||||
bool _new_accel_data[INS_MAX_INSTANCES];
|
||||
bool _new_gyro_data[INS_MAX_INSTANCES];
|
||||
|
||||
|
@ -225,11 +225,11 @@ void AP_InertialSensor_Backend::_notify_new_gyro_raw_sample(uint8_t instance,
|
||||
// save previous delta angle for coning correction
|
||||
_imu._last_delta_angle[instance] = delta_angle;
|
||||
_imu._last_raw_gyro[instance] = gyro;
|
||||
|
||||
#if HAL_WITH_DSP
|
||||
// capture gyro window for FFT analysis
|
||||
_last_gyro_window[_num_gyro_samples++] = gyro * _imu._gyro_raw_sampling_multiplier[instance];
|
||||
_num_gyro_samples = _num_gyro_samples % INS_MAX_GYRO_WINDOW_SAMPLES; // protect against overrun
|
||||
|
||||
#endif
|
||||
// apply the low pass filter
|
||||
Vector3f gyro_filtered = _imu._gyro_filter[instance].apply(gyro);
|
||||
|
||||
@ -514,6 +514,7 @@ void AP_InertialSensor_Backend::update_gyro(uint8_t instance)
|
||||
if (_imu._new_gyro_data[instance]) {
|
||||
_publish_gyro(instance, _imu._gyro_filtered[instance]);
|
||||
// copy the gyro samples from the backend to the frontend window
|
||||
#if HAL_WITH_DSP
|
||||
if (_imu._gyro_window_size > 0) {
|
||||
uint8_t idx = _imu._circular_buffer_idx[instance];
|
||||
for (uint8_t i = 0; i < _num_gyro_samples; i++) {
|
||||
@ -526,6 +527,7 @@ void AP_InertialSensor_Backend::update_gyro(uint8_t instance)
|
||||
_imu._circular_buffer_idx[instance] = idx;
|
||||
}
|
||||
_imu._gyro_raw[instance] = _imu._last_raw_gyro[instance] * _imu._gyro_raw_sampling_multiplier[instance];
|
||||
#endif
|
||||
_imu._new_gyro_data[instance] = false;
|
||||
}
|
||||
|
||||
|
@ -7,17 +7,19 @@
|
||||
|
||||
const extern AP_HAL::HAL& hal;
|
||||
|
||||
AP_InertialSensor_SITL::AP_InertialSensor_SITL(AP_InertialSensor &imu) :
|
||||
AP_InertialSensor_Backend(imu)
|
||||
AP_InertialSensor_SITL::AP_InertialSensor_SITL(AP_InertialSensor &imu, const uint16_t sample_rates[]) :
|
||||
AP_InertialSensor_Backend(imu),
|
||||
gyro_sample_hz(sample_rates[0]),
|
||||
accel_sample_hz(sample_rates[1])
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
detect the sensor
|
||||
*/
|
||||
AP_InertialSensor_Backend *AP_InertialSensor_SITL::detect(AP_InertialSensor &_imu)
|
||||
AP_InertialSensor_Backend *AP_InertialSensor_SITL::detect(AP_InertialSensor &_imu, const uint16_t sample_rates[])
|
||||
{
|
||||
AP_InertialSensor_SITL *sensor = new AP_InertialSensor_SITL(_imu);
|
||||
AP_InertialSensor_SITL *sensor = new AP_InertialSensor_SITL(_imu, sample_rates);
|
||||
if (sensor == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -34,24 +36,6 @@ bool AP_InertialSensor_SITL::init_sensor(void)
|
||||
if (sitl == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// grab the used instances
|
||||
for (uint8_t i=0; i<INS_SITL_INSTANCES; i++) {
|
||||
|
||||
gyro_instance[i] = _imu.register_gyro(gyro_sample_hz[i],
|
||||
AP_HAL::Device::make_bus_id(AP_HAL::Device::BUS_TYPE_SITL, i, 1, DEVTYPE_SITL));
|
||||
accel_instance[i] = _imu.register_accel(accel_sample_hz[i],
|
||||
AP_HAL::Device::make_bus_id(AP_HAL::Device::BUS_TYPE_SITL, i, 2, DEVTYPE_SITL));
|
||||
if (enable_fast_sampling(accel_instance[i])) {
|
||||
_set_accel_raw_sample_rate(accel_instance[i], accel_sample_hz[i]*4);
|
||||
}
|
||||
if (enable_fast_sampling(gyro_instance[i])) {
|
||||
_set_gyro_raw_sample_rate(gyro_instance[i], gyro_sample_hz[i]*8);
|
||||
}
|
||||
}
|
||||
|
||||
hal.scheduler->register_timer_process(FUNCTOR_BIND_MEMBER(&AP_InertialSensor_SITL::timer_update, void));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -63,14 +47,14 @@ static float calculate_noise(float noise, float noise_variation) {
|
||||
/*
|
||||
generate an accelerometer sample
|
||||
*/
|
||||
void AP_InertialSensor_SITL::generate_accel(uint8_t instance)
|
||||
void AP_InertialSensor_SITL::generate_accel()
|
||||
{
|
||||
Vector3f accel_accum;
|
||||
uint8_t nsamples = enable_fast_sampling(accel_instance[instance]) ? 4 : 1;
|
||||
uint8_t nsamples = enable_fast_sampling(accel_instance) ? 4 : 1;
|
||||
for (uint8_t j = 0; j < nsamples; j++) {
|
||||
|
||||
// add accel bias and noise
|
||||
Vector3f accel_bias = instance == 0 ? sitl->accel_bias.get() : sitl->accel2_bias.get();
|
||||
Vector3f accel_bias = accel_instance == 0 ? sitl->accel_bias.get() : sitl->accel2_bias.get();
|
||||
float xAccel = sitl->state.xAccel + accel_bias.x;
|
||||
float yAccel = sitl->state.yAccel + accel_bias.y;
|
||||
float zAccel = sitl->state.zAccel + accel_bias.z;
|
||||
@ -78,9 +62,9 @@ void AP_InertialSensor_SITL::generate_accel(uint8_t instance)
|
||||
// minimum noise levels are 2 bits, but averaged over many
|
||||
// samples, giving around 0.01 m/s/s
|
||||
float accel_noise = 0.01f;
|
||||
float noise_variation = 0.05;
|
||||
float noise_variation = 0.05f;
|
||||
// this smears the individual motor peaks somewhat emulating physical motors
|
||||
float freq_variation = 0.12;
|
||||
float freq_variation = 0.12f;
|
||||
|
||||
xAccel += accel_noise * rand_float();
|
||||
yAccel += accel_noise * rand_float();
|
||||
@ -91,24 +75,24 @@ void AP_InertialSensor_SITL::generate_accel(uint8_t instance)
|
||||
// giving a accel noise variation of 5.33 m/s/s over the full throttle range
|
||||
if (motors_on) {
|
||||
// add extra noise when the motors are on
|
||||
accel_noise = (instance == 0 ? sitl->accel_noise : sitl->accel2_noise) * sitl->throttle;
|
||||
accel_noise = (accel_instance == 0 ? sitl->accel_noise : sitl->accel2_noise) * sitl->throttle;
|
||||
}
|
||||
|
||||
// VIB_FREQ is a static vibration applied to each axis
|
||||
const Vector3f &vibe_freq = sitl->vibe_freq;
|
||||
if (!vibe_freq.is_zero() && motors_on) {
|
||||
float t = AP_HAL::micros() * 1.0e-6f;
|
||||
xAccel += sinf(t * 2 * M_PI * vibe_freq.x) * calculate_noise(accel_noise, noise_variation);
|
||||
yAccel += sinf(t * 2 * M_PI * vibe_freq.y) * calculate_noise(accel_noise, noise_variation);
|
||||
zAccel += sinf(t * 2 * M_PI * vibe_freq.z) * calculate_noise(accel_noise, noise_variation);
|
||||
xAccel += sinf(accel_time * 2 * M_PI * vibe_freq.x) * calculate_noise(accel_noise, noise_variation);
|
||||
yAccel += sinf(accel_time * 2 * M_PI * vibe_freq.y) * calculate_noise(accel_noise, noise_variation);
|
||||
zAccel += sinf(accel_time * 2 * M_PI * vibe_freq.z) * calculate_noise(accel_noise, noise_variation);
|
||||
accel_time += 1.0f / (accel_sample_hz * nsamples);
|
||||
}
|
||||
|
||||
// VIB_MOT_MAX is a rpm-scaled vibration applied to each axis
|
||||
if (!is_zero(sitl->vibe_motor) && motors_on) {
|
||||
for (uint8_t i = 0; i < sitl->state.num_motors; i++) {
|
||||
float &phase = accel_motor_phase[instance][i];
|
||||
float &phase = accel_motor_phase[i];
|
||||
float motor_freq = calculate_noise(sitl->state.rpm[i] / 60.0f, freq_variation);
|
||||
float phase_incr = motor_freq * 2 * M_PI / (accel_sample_hz[instance] * nsamples);
|
||||
float phase_incr = motor_freq * 2 * M_PI / (accel_sample_hz * nsamples);
|
||||
phase += phase_incr;
|
||||
if (phase_incr > M_PI) {
|
||||
phase -= 2 * M_PI;
|
||||
@ -150,25 +134,26 @@ void AP_InertialSensor_SITL::generate_accel(uint8_t instance)
|
||||
|
||||
Vector3f accel = Vector3f(xAccel, yAccel, zAccel);
|
||||
|
||||
_rotate_and_correct_accel(accel_instance[instance], accel);
|
||||
_notify_new_accel_sensor_rate_sample(instance, accel);
|
||||
_notify_new_accel_sensor_rate_sample(accel_instance, accel);
|
||||
|
||||
accel_accum += accel;
|
||||
}
|
||||
|
||||
accel_accum /= nsamples;
|
||||
_notify_new_accel_raw_sample(accel_instance[instance], accel_accum);
|
||||
_rotate_and_correct_accel(accel_instance, accel_accum);
|
||||
_notify_new_accel_raw_sample(accel_instance, accel_accum);
|
||||
|
||||
_publish_temperature(instance, 23);
|
||||
_publish_temperature(accel_instance, 23);
|
||||
}
|
||||
|
||||
/*
|
||||
generate a gyro sample
|
||||
*/
|
||||
void AP_InertialSensor_SITL::generate_gyro(uint8_t instance)
|
||||
void AP_InertialSensor_SITL::generate_gyro()
|
||||
{
|
||||
Vector3f gyro_accum;
|
||||
uint8_t nsamples = enable_fast_sampling(gyro_instance[instance]) ? 8 : 1;
|
||||
uint8_t nsamples = enable_fast_sampling(gyro_instance) ? 8 : 1;
|
||||
|
||||
for (uint8_t j = 0; j < nsamples; j++) {
|
||||
float p = radians(sitl->state.rollRate) + gyro_drift();
|
||||
float q = radians(sitl->state.pitchRate) + gyro_drift();
|
||||
@ -195,18 +180,18 @@ void AP_InertialSensor_SITL::generate_gyro(uint8_t instance)
|
||||
// VIB_FREQ is a static vibration applied to each axis
|
||||
const Vector3f &vibe_freq = sitl->vibe_freq;
|
||||
if (!vibe_freq.is_zero() && motors_on) {
|
||||
float t = AP_HAL::micros() * 1.0e-6f;
|
||||
p += sinf(t * 2 * M_PI * vibe_freq.x) * calculate_noise(gyro_noise, noise_variation);
|
||||
q += sinf(t * 2 * M_PI * vibe_freq.y) * calculate_noise(gyro_noise, noise_variation);
|
||||
r += sinf(t * 2 * M_PI * vibe_freq.z) * calculate_noise(gyro_noise, noise_variation);
|
||||
p += sinf(gyro_time * 2 * M_PI * vibe_freq.x) * calculate_noise(gyro_noise, noise_variation);
|
||||
q += sinf(gyro_time * 2 * M_PI * vibe_freq.y) * calculate_noise(gyro_noise, noise_variation);
|
||||
r += sinf(gyro_time * 2 * M_PI * vibe_freq.z) * calculate_noise(gyro_noise, noise_variation);
|
||||
gyro_time += 1.0f / (gyro_sample_hz * nsamples);
|
||||
}
|
||||
|
||||
// VIB_MOT_MAX is a rpm-scaled vibration applied to each axis
|
||||
if (!is_zero(sitl->vibe_motor) && motors_on) {
|
||||
for (uint8_t i = 0; i < sitl->state.num_motors; i++) {
|
||||
float motor_freq = calculate_noise(sitl->state.rpm[i] / 60.0f, freq_variation);
|
||||
float phase_incr = motor_freq * 2 * M_PI / (gyro_sample_hz[instance] * nsamples);
|
||||
float &phase = gyro_motor_phase[instance][i];
|
||||
float phase_incr = motor_freq * 2 * M_PI / (gyro_sample_hz * nsamples);
|
||||
float &phase = gyro_motor_phase[i];
|
||||
phase += phase_incr;
|
||||
if (phase_incr > M_PI) {
|
||||
phase -= 2 * M_PI;
|
||||
@ -228,12 +213,12 @@ void AP_InertialSensor_SITL::generate_gyro(uint8_t instance)
|
||||
gyro.y *= (1 + scale.y * 0.01f);
|
||||
gyro.z *= (1 + scale.z * 0.01f);
|
||||
|
||||
_rotate_and_correct_gyro(gyro_instance[instance], gyro);
|
||||
gyro_accum += gyro;
|
||||
_notify_new_gyro_sensor_rate_sample(instance, gyro);
|
||||
_notify_new_gyro_sensor_rate_sample(gyro_instance, gyro);
|
||||
}
|
||||
gyro_accum /= nsamples;
|
||||
_notify_new_gyro_raw_sample(gyro_instance[instance], gyro_accum);
|
||||
_rotate_and_correct_gyro(gyro_instance, gyro_accum);
|
||||
_notify_new_gyro_raw_sample(gyro_instance, gyro_accum);
|
||||
}
|
||||
|
||||
void AP_InertialSensor_SITL::timer_update(void)
|
||||
@ -246,30 +231,26 @@ void AP_InertialSensor_SITL::timer_update(void)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
for (uint8_t i=0; i<INS_SITL_INSTANCES; i++) {
|
||||
if (now >= next_accel_sample[i]) {
|
||||
if (((1U<<i) & sitl->accel_fail_mask) == 0) {
|
||||
generate_accel(i);
|
||||
if (next_accel_sample[i] == 0) {
|
||||
next_accel_sample[i] = now + 1000000UL / accel_sample_hz[i];
|
||||
}
|
||||
else {
|
||||
while (now >= next_accel_sample[i]) {
|
||||
next_accel_sample[i] += 1000000UL / accel_sample_hz[i];
|
||||
}
|
||||
if (now >= next_accel_sample) {
|
||||
if (((1U << accel_instance) & sitl->accel_fail_mask) == 0) {
|
||||
generate_accel();
|
||||
if (next_accel_sample == 0) {
|
||||
next_accel_sample = now + 1000000UL / accel_sample_hz;
|
||||
} else {
|
||||
while (now >= next_accel_sample) {
|
||||
next_accel_sample += 1000000UL / accel_sample_hz;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (now >= next_gyro_sample[i]) {
|
||||
if (((1U<<i) & sitl->gyro_fail_mask) == 0) {
|
||||
generate_gyro(i);
|
||||
if (next_gyro_sample[i] == 0) {
|
||||
next_gyro_sample[i] = now + 1000000UL / gyro_sample_hz[i];
|
||||
}
|
||||
else {
|
||||
while (now >= next_gyro_sample[i]) {
|
||||
next_gyro_sample[i] += 1000000UL / gyro_sample_hz[i];
|
||||
}
|
||||
}
|
||||
if (now >= next_gyro_sample) {
|
||||
if (((1U << gyro_instance) & sitl->gyro_fail_mask) == 0) {
|
||||
generate_gyro();
|
||||
if (next_gyro_sample == 0) {
|
||||
next_gyro_sample = now + 1000000UL / gyro_sample_hz;
|
||||
} else {
|
||||
while (now >= next_gyro_sample) {
|
||||
next_gyro_sample += 1000000UL / gyro_sample_hz;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,11 +274,21 @@ float AP_InertialSensor_SITL::gyro_drift(void)
|
||||
|
||||
bool AP_InertialSensor_SITL::update(void)
|
||||
{
|
||||
for (uint8_t i=0; i<INS_SITL_INSTANCES; i++) {
|
||||
update_accel(accel_instance[i]);
|
||||
update_gyro(gyro_instance[i]);
|
||||
}
|
||||
update_accel(accel_instance);
|
||||
update_gyro(gyro_instance);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t AP_InertialSensor_SITL::bus_id = 0;
|
||||
|
||||
void AP_InertialSensor_SITL::start()
|
||||
{
|
||||
gyro_instance = _imu.register_gyro(gyro_sample_hz,
|
||||
AP_HAL::Device::make_bus_id(AP_HAL::Device::BUS_TYPE_SITL, bus_id, 1, DEVTYPE_SITL));
|
||||
accel_instance = _imu.register_accel(accel_sample_hz,
|
||||
AP_HAL::Device::make_bus_id(AP_HAL::Device::BUS_TYPE_SITL, bus_id, 2, DEVTYPE_SITL));
|
||||
bus_id++;
|
||||
hal.scheduler->register_timer_process(FUNCTOR_BIND_MEMBER(&AP_InertialSensor_SITL::timer_update, void));
|
||||
}
|
||||
|
||||
#endif // HAL_BOARD_SITL
|
||||
|
@ -6,37 +6,43 @@
|
||||
#include "AP_InertialSensor.h"
|
||||
#include "AP_InertialSensor_Backend.h"
|
||||
|
||||
#define INS_SITL_INSTANCES 2
|
||||
// simulated sensor rates in Hz. This matches a pixhawk1
|
||||
const uint16_t INS_SITL_SENSOR_A[] = { 1000, 1000 };
|
||||
const uint16_t INS_SITL_SENSOR_B[] = { 760, 800 };
|
||||
|
||||
class AP_InertialSensor_SITL : public AP_InertialSensor_Backend
|
||||
{
|
||||
public:
|
||||
AP_InertialSensor_SITL(AP_InertialSensor &imu);
|
||||
AP_InertialSensor_SITL(AP_InertialSensor &imu, const uint16_t sample_rates[]);
|
||||
|
||||
/* update accel and gyro state */
|
||||
bool update() override;
|
||||
void start() override;
|
||||
|
||||
// detect the sensor
|
||||
static AP_InertialSensor_Backend *detect(AP_InertialSensor &imu);
|
||||
static AP_InertialSensor_Backend *detect(AP_InertialSensor &imu, const uint16_t sample_rates[]);
|
||||
|
||||
private:
|
||||
bool init_sensor(void);
|
||||
void timer_update();
|
||||
float gyro_drift(void);
|
||||
void generate_accel(uint8_t instance);
|
||||
void generate_gyro(uint8_t instance);
|
||||
void generate_accel();
|
||||
void generate_gyro();
|
||||
|
||||
SITL::SITL *sitl;
|
||||
|
||||
// simulated sensor rates in Hz. This matches a pixhawk1
|
||||
const uint16_t gyro_sample_hz[INS_SITL_INSTANCES] { 1000, 760 };
|
||||
const uint16_t accel_sample_hz[INS_SITL_INSTANCES] { 1000, 800 };
|
||||
const uint16_t gyro_sample_hz;
|
||||
const uint16_t accel_sample_hz;
|
||||
|
||||
uint8_t gyro_instance[INS_SITL_INSTANCES];
|
||||
uint8_t accel_instance[INS_SITL_INSTANCES];
|
||||
uint64_t next_gyro_sample[INS_SITL_INSTANCES];
|
||||
uint64_t next_accel_sample[INS_SITL_INSTANCES];
|
||||
float gyro_motor_phase[INS_SITL_INSTANCES][12];
|
||||
float accel_motor_phase[INS_SITL_INSTANCES][12];
|
||||
uint8_t gyro_instance;
|
||||
uint8_t accel_instance;
|
||||
uint64_t next_gyro_sample;
|
||||
uint64_t next_accel_sample;
|
||||
float gyro_time;
|
||||
float accel_time;
|
||||
float gyro_motor_phase[12];
|
||||
float accel_motor_phase[12];
|
||||
|
||||
static uint8_t bus_id;
|
||||
};
|
||||
#endif // CONFIG_HAL_BOARD
|
||||
|
Loading…
Reference in New Issue
Block a user