概述
目录
- 一. 控制分配的理论推导
- 二. 控制分配的代码实现
一. 控制分配的理论推导
众所周知四旋翼有四个电机,控制的最后一环就是控制四个电机的速度。上一节我们讲到姿态角串级PID控制,三个角度环输出了三个控制量,加上油门量,一共四个控制量,那么这四个量如何分别决定四个电机的速度呢?就需要设计一个控制分配器,如图所示:
这个图后面还会用到~
下图是我画的一般性四旋翼的布局图,可以看到是非对称的,因为我希望从一般情况下进行推导。其中四个电机标号从右上角顺时针旋转记为M1,M2,M3,M4。螺旋桨的旋向如图箭头所示。姿态传感器的安装如图中 O x b y b z b O{{x}_{b}}{{y}_{b}}{{z}_{b}} Oxbybzb所示。 x x x轴正方向指向后方, y y y轴正方向指向右侧, z z z轴正方向垂直向上(注意都是机体坐标系)。各轴的正方向按右手定则确定(拇指指向轴的正方向,四指方向为正),机体长度为 2 L 2L 2L,对角线夹角为 2 α 2alpha 2α。
单个螺旋桨的拉力可以表示为:
T
i
=
c
T
w
i
2
T_{i}=c_{T} w_{i}^{2}
Ti=cTwi2
其中
c
T
c_{T}
cT为拉力系数,容易通过实验测量确定。反扭力大小表示为
M
i
=
c
M
w
i
2
M_{i}=c_{M} w_{i}^{2}
Mi=cMwi2
M
i
M_{i}
Mi表示螺旋桨叶
i
i
i 在机身上产生的反扭力矩,
c
M
c_{M}
cM为反扭力矩系数,也可通过实验确定。
设螺旋桨对角线连线确定的安装夹角为 2 α 2alpha 2α ,对角线螺旋桨间安装距离为 2 L 2L 2L ,则滚转力矩和俯仰力矩的作用距离为 L sin α L sin alpha Lsinα、 L cos α L cos alpha Lcosα 。
推进器作用在水下四旋翼上的总拉力为
f
=
∑
i
=
1
4
T
i
=
c
T
(
w
1
2
+
w
2
2
+
w
3
2
+
w
4
2
)
f=sum_{i=1}^{4} T_{i}=c_{T}left(w_{1}^{2}+w_{2}^{2}+w_{3}^{2}+w_{4}^{2}right)
f=i=1∑4Ti=cT(w12+w22+w32+w42)
记
τ
x
,
τ
y
,
τ
z
tau_{x}, tau_{y} , tau_{z}
τx,τy,τz 为螺旋桨产生的三轴力矩,可计算为
{
τ
x
=
L
sin
α
⋅
c
T
(
w
1
2
+
w
2
2
−
w
3
2
−
w
4
2
)
τ
y
=
L
cos
α
⋅
c
T
(
w
1
2
−
w
2
2
−
w
3
2
+
w
4
2
)
τ
z
=
c
M
(
w
1
2
−
w
2
2
+
w
3
2
−
w
4
2
)
left{begin{array}{l} tau_{x}=L sin alpha cdot c_{T}left(w_{1}^{2}+w_{2}^{2}-w_{3}^{2}-w_{4}^{2}right) \ tau_{y}=L cos alpha cdot c_{T}left(w_{1}^{2}-w_{2}^{2}-w_{3}^{2}+w_{4}^{2}right) \ tau_{z}=c_{M}left(w_{1}^{2}-w_{2}^{2}+w_{3}^{2}-w_{4}^{2}right) end{array}right.
⎩⎨⎧τx=Lsinα⋅cT(w12+w22−w32−w42)τy=Lcosα⋅cT(w12−w22−w32+w42)τz=cM(w12−w22+w32−w42)
当
α
=
45
o
alpha ={{45}^{o}}
α=45o时就是典型的X型布局,上式变为:
{
τ
x
=
2
2
L
⋅
c
T
(
w
1
2
+
w
2
2
−
w
3
2
−
w
4
2
)
τ
y
=
2
2
L
⋅
c
T
(
w
1
2
−
w
2
2
−
w
3
2
+
w
4
2
)
τ
z
=
c
M
(
w
1
2
−
w
2
2
+
w
3
2
−
w
4
2
)
left{begin{array}{l} tau_{x}=frac{sqrt{2}}{2} L cdot c_{T}left(w_{1}^{2}+w_{2}^{2}-w_{3}^{2}-w_{4}^{2}right) \ tau_{y}=frac{sqrt{2}}{2} L cdot c_{T}left(w_{1}^{2}-w_{2}^{2}-w_{3}^{2}+w_{4}^{2}right) \ tau_{z}=c_{M}left(w_{1}^{2}-w_{2}^{2}+w_{3}^{2}-w_{4}^{2}right) end{array}right.
⎩⎪⎨⎪⎧τx=22L⋅cT(w12+w22−w32−w42)τy=22L⋅cT(w12−w22−w32+w42)τz=cM(w12−w22+w32−w42)
这个式子其实就说明了三轴的力矩在各个电机上的投影值。在确定电机的速度时按照这个值分配即可。
记四个推进器的速度分别为
V
M
1
V_{M1}
VM1,
V
M
2
V_{M2}
VM2,
V
M
3
V_{M3}
VM3,
V
M
4
V_{M4}
VM4,
t
V
t_{V}
tV为遥控器摇杆输入的垂直方向推进的油门值。俯仰角PID输出为
O
pitch
O_{text {pitch }}
Opitch ,滚转角PID输出为
O
roll
O_{text {roll}}
Oroll,偏航角PID输出为
O
yaw
O_{text {yaw}}
Oyaw 。 三轴PID的输出就可以等效为输出力矩,那么按照上式的控制分配,将各个电机的速度写成下式:
{
V
M
1
=
t
V
+
2
2
O
r
o
l
l
+
2
2
O
p
i
t
c
h
+
O
y
a
w
V
M
2
=
t
V
+
2
2
O
r
o
l
l
−
2
2
O
p
i
t
c
h
−
O
y
a
w
V
M
3
=
t
V
−
2
2
O
r
o
l
l
−
2
2
O
p
i
t
c
h
+
O
y
a
w
V
M
4
=
t
V
−
2
2
O
r
o
l
l
+
2
2
O
p
i
t
c
h
−
O
y
a
w
left{begin{array}{l} V_{M 1}=t_{V}+frac{sqrt{2}}{2} O_{r o l l}+frac{sqrt{2}}{2} O_{p i t c h}+O_{y a w} \ V_{M 2}=t_{V}+frac{sqrt{2}}{2} O_{r o l l}-frac{sqrt{2}}{2} O_{p i t c h}-O_{y a w} \ V_{M 3}=t_{V}-frac{sqrt{2}}{2} O_{r o l l}-frac{sqrt{2}}{2} O_{p i t c h}+O_{y a w} \ V_{M 4}=t_{V}-frac{sqrt{2}}{2} O_{r o l l}+frac{sqrt{2}}{2} O_{p i t c h}-O_{y a w} end{array}right.
⎩⎪⎪⎪⎨⎪⎪⎪⎧VM1=tV+22Oroll+22Opitch+OyawVM2=tV+22Oroll−22Opitch−OyawVM3=tV−22Oroll−22Opitch+OyawVM4=tV−22Oroll+22Opitch−Oyaw
这就是我们要的控制分配率了。当然可以写成矩阵形式
V = R ∙ I mathbf{V}=mathbf{R}bullet mathbf{I} V=R∙I
R
R
R就是控制矩阵
V
=
[
V
M
1
,
V
M
2
,
V
M
3
,
V
M
4
]
T
{{mathbf{V}}}={{[{{V}_{M1}},{{V}_{M2}},{{V}_{M3}},{{V}_{M4}}]}^{T}}
V=[VM1,VM2,VM3,VM4]T
I = [ t V , O r o l l , O p i t c h , O y a w ] T {{mathbf{I}}}={{[{{t}_{V}},{{O}_{roll}},{{O}_{pitch}},{{O}_{yaw}}]}^{T}} I=[tV,Oroll,Opitch,Oyaw]T
R = [ 1 2 2 2 2 1 1 2 2 − 2 2 − 1 1 − 2 2 − 2 2 1 1 − 2 2 2 2 − 1 ] {{mathbf{R}}}=left[ begin{matrix} 1 & frac{sqrt{2}}{2} & frac{sqrt{2}}{2} & 1 \ 1 & frac{sqrt{2}}{2} & -frac{sqrt{2}}{2} & -1 \ 1 & -frac{sqrt{2}}{2} & -frac{sqrt{2}}{2} & 1 \ 1 & -frac{sqrt{2}}{2} & frac{sqrt{2}}{2} & -1 \ end{matrix} right] R=⎣⎢⎢⎢⎡11112222−22−2222−22−22221−11−1⎦⎥⎥⎥⎤
用上面的方法,我们可以推导出十字型布局的四旋翼的控制分配,还有六旋翼、八旋翼的控制分配,以及不对称安装的多旋翼的控制分配。
二. 控制分配的代码实现
经过上面的推导,我们已经有了控制分配的算法了,在上一节姿态控制的基础上,我们继续往下走。上一节姿态角的串级PID计算已经得到了三个角度的控制量,从遥控器得到了油门值,直接应用上面推导出来的算法计算出电机的速度,就可以控制电机了。
新建一个pwm_control.c和pwm_control.h的文件。
pwm_control.h的内容为:
#ifndef __POWER_CONTROL_H
#define __POWER_CONTROL_H
#include "timer.h"
#include "stabilizer.h"
#define KV 500.0f // 500 KV 电机
#define VOTAGE 25.2f
#define THRUST_MAX (KV*VOTAGE)
#define THRUST_MIN (-KV*VOTAGE)
void pwmControl(control_t *control);
void setMotorPWM(u32 m1_set, u32 m2_set, u32 m3_set, u32 m4_set);
u16 thrust2pwm(float thrust_value);
u16 thrust2pwmRange(float thrust_value, float p_min, float p_max);
float pwm2thrust(u16 pwm_value);
float pwm2Range(int pwm_value, float p_min, float p_max);
float limitThrust(float value);
u16 limitPWM(int input);
#endif
pwm_control.c的内容为:
#include "sys.h"
#include "pwm_control.h"
#include "timer.h"
#include "stabilizer.h"
float limitThrust(float value)
{
if (value > THRUST_MAX)
{
value = THRUST_MAX;
}
else if (value < THRUST_MIN)
{
value = THRUST_MIN;
}
return value;
}
u16 limitPWM(int input)
{
if (input > 2000)
return 2000;
else if (input < 1000)
return 1000;
else
return input;
}
void pwmControl(control_t *control) /*功率输出控制*/
{
float r = (float)control->roll * 0.707f;
float p = (float)control->pitch * 0.707f;
float y = (float)control->yaw;
float thrust1, thrust2, thrust3, thrust4;
thrust1 = limitThrust(control->thrust + r + p + y); // |--------> Y
thrust2 = limitThrust(control->thrust + r - p - y); // |
thrust3 = limitThrust(control->thrust - r - p + y); // V
thrust4 = limitThrust(control->thrust - r + p - y); // X
motorPWM.m1 = thrust2pwm(thrust1);
motorPWM.m2 = thrust2pwm(thrust2);
motorPWM.m3 = thrust2pwm(thrust3);
motorPWM.m4 = thrust2pwm(thrust4);
// 将电机油门值转化为 pwm 值
setMotorPWM(motorPWM.m1, motorPWM.m2, motorPWM.m3, motorPWM.m4);
}
void setMotorPWM(u32 m1_set, u32 m2_set, u32 m3_set, u32 m4_set)
{
// 直接设定pwm值
TIM_SetTIM4Compare1(m1_set);
TIM_SetTIM4Compare2(m2_set);
TIM_SetTIM4Compare3(m3_set);
TIM_SetTIM4Compare4(m4_set);
}
// 油门值转化为 PWM 值
u16 thrust2pwm(float thrust_value)
{
float pwm_value;
// 油门值转化为 PWM 1000-2000, [THRUST_MIN, THRUST_MAX] 到 [1000,2000]的映射
pwm_value = 1000.0f + (thrust_value - THRUST_MIN) * 1000.0f / (THRUST_MAX - THRUST_MIN);
return limitPWM((int)pwm_value);
}
float pwm2thrust(u16 pwm_value)
{
float thrust_value;
thrust_value = THRUST_MIN + ((float)pwm_value - 1000.0f) * (THRUST_MAX - THRUST_MIN) / 1000.0f;
return limitThrust(thrust_value);
}
u16 thrust2pwmRange(float thrust_value, float p_min, float p_max)
{
float pwm_value;
// 油门值转化为 PWM pmin-pmax, [THRUST_MIN, THRUST_MAX] 到 [p_min,p_max]的映射
pwm_value = p_min + (thrust_value - THRUST_MIN) * (p_max - p_min) / (THRUST_MAX - THRUST_MIN);
return limitPWM((int)pwm_value);
}
float pwm2Range(int pwm_value, float p_min, float p_max)
{
float p;
p = p_min + ((float)(pwm_value)-1000.0f) * (p_max - p_min) / 1000.0f;
if (p > p_max)
p = p_max;
if (p < p_min)
p = p_min;
return p;
}
定位到void pwmControl(control_t *control)
,这里面就是按照前面的分配算法来确定四个电机的油门值,然后将油门值转化为对应的pwm值,setMotorPWM(motorPWM.m1, motorPWM.m2, motorPWM.m3, motorPWM.m4)
直接就设定了四个电机的PWM值,也就是速度了,这样就实现了水下四旋翼的控制。
当然了,在上一节的基础上,我们只需要在姿态控制任务中增加一行代码就行了,就是pwmControl(&control)
,修改后的姿态控制任务函数变为
void stabilization_task(void *p_arg)
{
OS_ERR err;
CPU_SR_ALLOC();
u8 lenth = sizeof(configParam);
lenth = lenth / 4 + (lenth % 4 ? 1 : 0);
STMFLASH_Read(CONFIG_PARAM_ADDR, (u32 *)&configParam, lenth); //载入PID参数
attitudeControlInit();
while(1)
{
Water_Attitude_Control(&control);
pwmControl(&control);
delay_ms(5);
}
}
到了这一步,水下四旋翼已经可以在水里稳定的上浮下潜了(当然前提是PID参数调整对了),这时候拨动遥控器的俯仰和滚转摇杆,你会发现水下四旋翼跟着俯仰或滚转。然而的然而,它是不会像空中四旋翼那样前后左后飞行的,或者动的很慢。因为空中的阻力小,水中的阻力大,环境完全不同。所以水下四旋翼光靠机体的俯仰和滚转是很难实现前后左右机动的。推荐的方法是安装额外的水平的螺旋桨,提供水平分力。至于怎么设计那就是发挥你的聪明才智的时候啦!博主采用的方法不是水平电机,方案保密~~~增加水平电机在软件上的开销是很小的,只需要增加一路或几路PWM就行了。因为水下四旋翼已经提供了一个稳定的平台,现在只需要提供水平力就可以航行了。
最后
以上就是朴素篮球为你收集整理的STM32实现水下四旋翼(十)飞行控制任务2——控制分配一. 控制分配的理论推导二. 控制分配的代码实现的全部内容,希望文章能够帮你解决STM32实现水下四旋翼(十)飞行控制任务2——控制分配一. 控制分配的理论推导二. 控制分配的代码实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复