PX4飞控之PWM输出控制
2019-04-13 20:28发布
生成海报
PX4飞控之PWM输出控制
多旋翼电调如好盈XRotor,DJI通用电调等都支持PWM信号来传输控制信号。常用的400Hz电调信号对应周期2500us,一般使用高电平时间1000us~2000us为有效信号区间,即1000us为最低输出,2000us为最高输出,锁定(停转)信号一般取900us(或950us,太低电调会判断成无信号,太高容易误判成有输出而意外启动)。一般电调也都支持有效信区间设置,可以在典型值附近自定义。
为了保证安全,电调上电后需要先检测到锁定信号,即900us左右的高电平时间,上电后检测到锁定信号电调会长叫一声(这个声音通过电机发出来的,电动机跟扬声器原理上很像,接上声音信号放放音乐也是毫无压力的==),从锁定信号到最低输出信号(1000us)需要有加速过程(即分多次慢慢增加到1000us),加速完成后,进入开启模式,这时就可以在有效信号区间内直接输出给定值。如果电调上电后飞控直接输出有效信号或从锁定信号直接跳变到有效信号都会导致电调进入报警模式(急促“嘀嘀嘀”报警声),而且控制器的输出信号区间(如-1~1)也需要量化到电调的有效区间,因此需要有一个电调控制程序来启动电调和量化有效信号。分享下PX4的电调控制程序。
- pwm_limit中使用状态机来标志电调控制的不同阶段
enum {
PWM_LIMIT_STATE_INIT = 0,
PWM_LIMIT_STATE_OFF,
PWM_LIMIT_STATE_RAMP,
PWM_LIMIT_STATE_ON
};
void pwm_limit_init(pwm_limit_t *limit)
{
limit->state = PWM_LIMIT_STATE_INIT;
limit->time_armed = 0;
return;
}
switch (limit->state) {
case PWM_LIMIT_STATE_INIT:
if (armed) {
if (limit->time_armed == 0) {
limit->time_armed = hrt_absolute_time();
}
if (hrt_elapsed_time(&limit->time_armed) >= INIT_TIME_US) {
limit->state = PWM_LIMIT_STATE_OFF;
}
}
break;
case PWM_LIMIT_STATE_OFF:
if (armed) {
limit->state = PWM_LIMIT_STATE_RAMP;
limit->time_armed = hrt_absolute_time();
}
break;
case PWM_LIMIT_STATE_RAMP:
if (!armed) {
limit->state = PWM_LIMIT_STATE_OFF;
} else if (hrt_elapsed_time(&limit->time_armed) >= RAMP_TIME_US) {
limit->state = PWM_LIMIT_STATE_ON;
}
break;
case PWM_LIMIT_STATE_ON:
if (!armed) {
limit->state = PWM_LIMIT_STATE_OFF;
}
break;
default:
break;
}
- 不同状态下的输出值
switch (local_limit_state) {
case PWM_LIMIT_STATE_OFF:
case PWM_LIMIT_STATE_INIT:
for (unsigned i = 0; i < num_channels; i++) {
effective_pwm[i] = disarmed_pwm[i];
}
break;
case PWM_LIMIT_STATE_RAMP: {
hrt_abstime diff = hrt_elapsed_time(&limit->time_armed);
progress = diff * PROGRESS_INT_SCALING / RAMP_TIME_US;
if (progress > PROGRESS_INT_SCALING) {
progress = PROGRESS_INT_SCALING;
}
for (unsigned i = 0; i < num_channels; i++) {
float control_value = output[i];
if (!isfinite(control_value)) {
effective_pwm[i] = disarmed_pwm[i];
continue;
}
uint16_t ramp_min_pwm;
if (disarmed_pwm[i] > 0) {
unsigned disarmed = disarmed_pwm[i];
if (disarmed > min_pwm[i]) {
disarmed = min_pwm[i];
}
unsigned disarmed_min_diff = min_pwm[i] - disarmed;
ramp_min_pwm = disarmed + (disarmed_min_diff * progress) / PROGRESS_INT_SCALING;
} else {
ramp_min_pwm = min_pwm[i];
}
if (reverse_mask & (1 << i)) {
control_value = -1.0f * control_value;
}
effective_pwm[i] = control_value * (max_pwm[i] - ramp_min_pwm) / 2 + (max_pwm[i] + ramp_min_pwm) / 2;
if (effective_pwm[i] < ramp_min_pwm) {
effective_pwm[i] = ramp_min_pwm;
} else if (effective_pwm[i] > max_pwm[i]) {
effective_pwm[i] = max_pwm[i];
}
}
}
break;
case PWM_LIMIT_STATE_ON:
for (unsigned i = 0; i < num_channels; i++) {
float control_value = output[i];
if (!isfinite(control_value)) {
effective_pwm[i] = disarmed_pwm[i];
continue;
}
if (reverse_mask & (1 << i)) {
control_value = -1.0f * control_value;
}
effective_pwm[i] = control_value * (max_pwm[i] - min_pwm[i]) / 2 + (max_pwm[i] + min_pwm[i]) / 2;
if (effective_pwm[i] < min_pwm[i]) {
effective_pwm[i] = min_pwm[i];
} else if (effective_pwm[i] > max_pwm[i]) {
effective_pwm[i] = max_pwm[i];
}
}
break;
default:
break;
}
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮