-
PX4
源码分析,以及思路随笔。
目录:
1.0
环境安装
1.1 roll
pitch yaw
2.1
loop()
3.1
fastloop()
3.1 .1
read_AHRS()
3.1.1.1
()
3.1.2
rate_controller_run()
3.1.2.1
_motors
.set_roll()
(
嵌套了
rate_bf_to_motor_roll
)
3.1.3 motors_output()
3.1.3.1
update_t
hrottle_filter
()
3.1.3.2
update_b
attery_resistance
()
3.1.3.3
update_lift_max_from_batt_voltage()
3.1.3.4
output_logic()
3.1.3.5
output_armed_stabilizing()
1.0
环境安装
1.
首先安装
px4_toolchain_instal
ler_v14_
,并配置好
java
环境
(安装
jdk
,
< br>32
位)。
2.
安装
GitHub
网站:
/dev/docs/
若提示失败,在
IE
浏览器中打开网页,
p>
http
变为
https
< br>,不断尝试。
3.
克隆程序(
需要翻墙),可能多次失败。
4.
从
C:px4toolchainmsys1.0
内的
eclipse
批处理文件打开
eclipse<
/p>
。
5.
按照<
/p>
/dev/docs/
从第二张图开始。
注:第二张图位置为
ardupilot
的位置。
返回目录
1.1 ROLL YAW PITCH
/yuzhongc
hun/article/details/22749521
在航空中,
pitch, yaw,
roll
如图
2
所示。
pitch
是围绕
X
轴旋转,也叫做俯仰角,如图
3
所示。
yaw
是围绕
Y<
/p>
轴旋转,也叫偏航角,如图
4
所示。
p>
roll
是围绕
Z
轴旋转,也叫翻滚角,如图
5
所示。
返回目录
2.1
loop
函数:
各种初始化,先忽略。
2.
初始定义
第一个是函数名,
第二个单位为赫兹为过多少时间调用一次,
第三个
单位为微秒,即为最大花费时间。
const
AP_Scheduler
::
Task
Copter::scheduler_tasks
< br>[] = {
SCHED_TASK(rc_loop,
100, 130),
/*
控制角
*/
SCHED_TASK(throttle_loop,
50, 75),
/*
油门控制
*/
SCHED_TASK(update_GPS, 50, 200),
/*
GPS
更新
*/
3.
从
Loop()
开始。
(1)
等待数据
_for_sample();
我认为
是
,也就是指惯性传感器。
void<
/p>
AP_InertialSensor::wait_for_sample
(
void
)
uint32_t timer = micros();
(
2
)计算最大循环时间
。
perf_info_check_loop_time(timer -
fast_loopTimer
);
检查循环时间
被
PI
Loops
使用??
G_Dt
=
(
float
)(timer -
fast_loopTimer
) /
1000000.0f;
fast_loopTimer
= timer;
记录当前循环时间
mainLoop_count
++;
主要循环的故障检测
(3)
快速循环,
< br>主要的循环,
重要的一步!
!
!
!
!
!
!
p>
!
!
!
!
!
因此首选需主要研究此函数!
fast_loop();
(
4
)任务
调度
scheduler
.tick();
告诉调度程序,一个流程已经走完??
uint32_t
time_available =
(timer + MAIN_LOOP_MICROS) - micros();
任务周期
scheduler
.run(time_available);
任务调度
返回
目录
3.1 fastloop()
函数
Fastloop
,最关键的循环<
/p>
(400hz)
,下面对每个函数进行工作的分
< br>析。
1.
更新传感器并更新姿态的函数
read_AHRS();
2.<
/p>
进行角速度
PID
运算的函数
attitude_control
.rate
_controller_run();
3.
直升机框架判断
(
HELI_FRAME
)
#if
FRAME_CONFIG ==
HELI_FRAME
update_heli_control_dynamics();
#endif<
/p>
//HELI_FRAME
4.
输出电机
PWM
值
的函数
motors_output();
5.
惯性导航
// InertialNav
read_inertia();
6.
扩展卡尔曼滤波器
// check if ekf has reset target
heading
check_ekf_yaw_reset();
7.
p>
更新控制模式
,
并计算本级控制输出下级控
制输入
...
// run the attitude
controllers
update_flight_mode();
8.
扩展卡尔曼滤波器
//
update home from EKF if necessary
update_home_from_EKF();
9.
检查是否落地
< br>or
追回
// check
if we've landed or crashed
update_land_and_crash_detectors();
10.
摄像机
#if
MOUNT == ENABLED
// camera mount's fast
update
camera_mount
.update_fast();
#endif
11.
记录传感器健康状态??
// log sensor health
if
(should_log(MASK_LOG_ANY)) {
Log_Sensor_Health();
返回目录
3.1.1
Read_AHRS()
函数
1.
read_AHRS
void
Copter::read_AHRS
(
void
)
{
// Perform IMU calculations and get
attitude info
//------------
-----------------------------------
#if
HIL_MODE !=
HIL_MODE_DISABLED
//Mavlink
协议支持
,全传感器仿真??模拟?(
full sensor
simulation.
)
//
update hil before ahrs update
gcs_check_input();
#endif
ahrs
.update();
//
重要!
}
2.
ahrs
.update()
其中主要函数为
ahrs
.update()
,函数为:
//DCM
:
DirectionCosine
Matrix
,方向余弦矩阵
AP_
AHRS_DCM::update
(
void
)
{
float
delta_t;
if
(
_last_startup_ms
== 0) {
_last_startup_ms
=
AP_HAL::millis();
}
(1)
更新加速度计和陀螺仪
// tell the IMU to grab some
data
_ins
.update();
// ask the IMU how much time this
sensor reading represents
delta_t =
_ins
.get_delta_time();
// if the update call took more than
0.2 seconds then discard it,
// otherwise we may move too far. This
happens when arming motors
// in ArduCopter
if
(delta_t > 0.2f) {
memset(&
_ra_sum
[0], 0,
sizeof
(
_ra_sum
< br>));
_ra_deltat
= 0;
return
;
}
(2)
使用陀螺仪更新四元素矩阵(做余弦矩阵的归一化)
// Integrate the DCM matrix
using gyro inputs
matrix_update(delta_t);
(3)
标准化
// Normalize the DCM matrix
normalize();
(4)
执行漂移修正
使用加速度计和罗盘与该次计算的四元素矩阵做差,
修正出下一
次陀螺仪的输出
// Perform drift
correction
drift_correction(delta_t);
(5)
检查错误值
//
paranoid check for bad values in the DCM
matrix
check_matrix();
(6)
计算俯仰角,偏航角,翻转角
// Calculate pitch, roll, yaw for
stabilization and navigation
euler_angles();
(7)
更新三角函数的值,包括俯仰角的余弦和翻滚角的余弦
// update trig values including
_cos_roll, cos_pitch
update_trig();
}
返回目录
3.1.1.1
_ins
.update()
更新加速度计和陀螺仪
//
tell the IMU to grab some data
_ins
.update();
函数
定义:
void
AP_InertialSensor::up
date
(
void
)
:
在函数中:
_backends
[i]->update();
为主要操作步骤。
_backend
s
[i]
的定义为:
(
是一个指针数组
)
AP_InertialSensor_Backend
*<
/p>
_backends
[INS_MAX_BACKENDS];
查找
_backends
所指向的数据
,有两个函数值得注意:
void
A
P_InertialSensor::_add_backend
(AP_Inert
ialSensor_Backend
*backend)
Void
AP_InertialSensor::detect_backends<
/p>
(
void
)
考虑在
detect_backends()
中进行了调用:<
/p>
#elif
HAL_INS_DEFAULT == HAL_INS_PX4 || HAL_INS_DEFAULT
==
HAL_INS_VRBRAIN
_add_
backend(AP_InertialSensor_PX4::detect(*
this
));
因此得出
_backends
指向的是类
AP_Ine
rtialSensor_PX4
。找到函数如下:
bool
AP_InertialSensor_PX4::
update
(
void
)
{
// get the latest
sample from the sensor drivers
_get_sample();
//
uint8_t _num_accel_instances;
//
uint8_t _num_gyro_instances;
for
(uint8_t k=0;
k<_num_accel_instances; k++) {
update_accel(_accel_instance[k]);
//
加速度计
}
for
(uint8_t
k=0; k<_num_gyro_instances; k++) {
update_gyro(_gyro_instance[k]);
//
陀螺仪
}
returntrue
;
}
其中两个重要的函数分别为:
<
/p>
update_accel(_accel_instance[k])
< br>和
update_gyro(_gyro_instance[k]).
首先看
update_accel(
_accel_instance[k])
:
输入参数为
_accel_instance[k]
和
_gyro_instance[k]
,定义为:
#define
INS_MAX_INSTANCES 3
uint8_t
_accel_instance[INS_MAX_INSTANCES];
uint8_t
_gyro_instance[INS_MAX_INSTANCES];
随后看
update_accel()
和
update_gyro()
的定义:
void
AP_InertialS
ensor_Backend::update_accel
(
uint8_t
instance)
{
hal.
scheduler
->suspend_timer_procs();
//
任务
调度,推迟进程
//_imu._new_acce
l_data[instance]
为布尔型变量,推测为观察是否可以更新
//
其中
_p
ublish_accel()
应该就是
if
(
_imu
.
_new_accel_data
[instance]
) {
//
两个参数,其中一个是
< br>instance
,另一个参考为过滤后的加速度计数据??
_publish_accel(instance,
_imu
.
_accel_filtered
[instance]);
_imu
.
_new_accel_data
[instance] =
false
;
}
// possibly update filter
frequency
设定频率?
if
(
_last_accel_f
ilter_hz
[instance] !=
_accel_filter_cutoff()) {
_imu
.
_accel_filter
[instance].s
et_cutoff_frequency(_accel_raw_sample_r
ate(instance), _accel_filter_cutoff());
_last_accel_filter_hz
[instance] =
_accel_filter_cutoff();
}
//
任务调度,推测为经过一个进程后重新设置
hal.
scheduler
->resume_timer_procs();
}
下面对于陀螺仪的控制基本没有区别:
void
AP_InertialSensor_Backend::update_
gyro
(
uint8_t
instance)
{
hal.
scheduler
->suspend_timer_procs()
;
if
(
_imu
.
_new_gyro_data
< br>[instance]) {
_publish_gyro(instance,
_imu
.
_gyro_filtered
[instance]);
_imu
.
_new_gyro_da
ta
[instance] =
false
;
}
// possibly update filter
frequency
if
(
_last_gyro_filter_hz
[instance]
!= _gyro_filter_cutoff()) {
_imu
.
_gyro_filter
[instance].
set_cutoff_frequency(_gyro_raw_sample_rat
e(instance), _gyro_filter_cutoff());
_last_gyro_filter_hz
[instance] =
_gyro_filter_cutoff();
}
hal.
schedule
r
->resume_timer_procs();
}
然后需要看一下
_publish_
accel()
这个函数
:
void
AP_InertialSensor_Backend::
_publish_accel
(
uint8_t
instance,
const
Vector3f&accel)
{
_imu
.
_accel
[instance] = accel;
_
imu
.
_accel_healthy
[instance] =
true
;
if
(
_
imu
.
_accel_raw_sample_rates<
/p>
[instance] <= 0) {
return
;
}
// publish delta
velocity
_imu
.
_delta_velocity
[instance] =
_imu
.
_delta_velocity
_acc
[instance];
_imu
< br>.
_delta_velocity_dt
[insta
nce] =
_imu
.
_delt
a_velocity_acc_dt
[instance];
_imu
.
_delta_velocity_valid<
/p>
[instance] =
true
;
if
(
_imu
.
_accel_calib
rator
!=
NULL&&
_i
mu
.
_accel_calibrator
< br>[instance].get_status() ==
ACCEL_CAL_COLLECTING_SAMPLE
)
{
Vector3f cal_sample =
_imu
.
_delta_velocity
[
instance];
//remove
rotation
cal__invers
e(
_imu
.
_board_ori
entation
);
//
remove scale factors
const
Vector3f&accel_scale =
_imu
.
_accel_scale
[instance].get();
cal_sample.x /= accel_scale.x;
cal_sample.y /= accel_scale.y;
cal_sample.z /= accel_scale.z;
//remove offsets
cal_sample +=
_imu
.
_accel_offset
[instance].get() *
_imu
.
_delta_velocity_d
t
[instance]
_i
mu
.
_accel_calibrator
< br>[instance].new_sample(cal_sample,
_i
mu
.
_delta_velocity_dt
[instance]);
}
}
返回目录
3.1.2
attitude_control
.rate_controller_run()
姿态控制函数(
PID
函数)
attitude_control
.rate_controller_run();
定义为:
void
< br>AC_AttitudeControl::rate_controller_run
< br>()
{
_motors
.s
et_roll(rate_bf_to_motor_roll(
_ang_vel_
target_rads
.
x
));
_motors
.set_pitch(rate_bf_to
_motor_pitch(
_ang_vel_target_rads
.
y
));
_motor
s
.set_yaw(rate_bf_to_motor_yaw(
< br>_ang_vel_target_rads
.
z
));
}
注:其中,
_ang_vel_target_rads.x
等三个输入参数的取得主要在
void
Copter::stabilize_run()
内取得。
推测
Angularvelocity target rad
s
的含义为:要求
(
期望
)
的角度速度
注:
rate_bf_roll_pitch_yaw():
< br>此函数采用“车身骨架坐标系”标示翻滚、俯仰和偏航速率
(
度
/
秒
)
。
例:此函数的滚动
=
-1000,
间距
=
-1500,
偏航
= 500
会导致飞
机向左滚动
10
度
/
< br>秒
,
向前倾斜
15
度
/
秒
,
< br>对于车辆的
z
轴旋转
5
度
/
秒。
返回目录
3.1.2.1
_motors
.set_roll()
1.
首先分析
_motor
s
.set_roll()
定义:
void
set_roll
(
float
roll_in)
{
_roll_in
= roll_in; };
主要就是将输入的参数定义为
roll_in
,并
传值给
_roll_in
。
注
:
_roll_in
在
fastloop()
内
的
下
个
函
数
motors_
output()
函数进行操作,这里我认为是个切入点!
set
_roll()
中嵌套的函数为:
rate_bf_to_mo
tor_roll()
定义为:
f
loat
AC_AttitudeControl::rate_bf_to_moto
r_roll
(
float
rate_target_rads)
{
//
从陀螺仪获取
get_g
yro().x
,也就是当前的飞行器的翻滚角。
float
current_rate_rads =
p>
_ahrs
.get_gyro().
x<
/p>
;
//
翻滚角的期望与当前数值的差值
float
rate_error_rads =
rate_target_rads - current_rate_rads;
// pass error to PID controller
将误差传递给
PID
控制器
,
其中有微分过滤
//
和将目标数据传入结构体
PID
。
get_rate_roll_pid().set_input_fi
lter_d(rate_error_rads);
get_rate_r
oll_pid().set_desired_rate(rate_target_rads);
//
进行积分
float
integrator =
get_rate_roll_pid().get_integrator();
//
Ensure
that
integrator
can
only
be
reduced
if
the
output
is
saturated
//
确保积分只在饱和时下降
if
(!
_motors
.
limit
.
roll
_pitch
|| ((integrator > 0 &&
rate_error_rads <
0) || (integrator < 0
&& rate_error_rads > 0))) {
integrator = get_rate_roll_pid().get_i();
}
// Compute output in
range -1 ~ +1
进行
PID
计算,得到控制量
output
。
//
其中
get_d()
和
getp
中有参数
_kp
和
_kd
,没有找到是如何进行计算的
!
//
这里是个大问题。
float
output =
get_rate_roll_pid().get_p() + integrator +
get_rate_roll_pid().get_d();
//
Constrain
output
,
限制
output
的值,如果是非法的则变为
0
,如果比
0
小则变
//
为
0,
大于
1
则为
1
return
constrain_float(output, -1.0f, 1.0f);
}
剩余的
rate_bf_to_mo
tor_pitch(
_ang_vel_target_rads
.
y
)
和
rate_bf_to_motor_yaw(
_ang_ve
l_target_rads
.
z
)<
/p>
与第一个没有差别
在这三个函数中,我们分别获得了三个参数,
_roll_in
,
_pitch_in
和
_yaw_in
,
取值范
围在
-1
到
1
,
应该会应用在
fastloop()
中的下个函数
motors_output()
。
返回目录
-
-
-
-
-
-
-
-
-
上一篇:船舶专业英语词汇(排版后)
下一篇:不同类型文件的压缩方案(转载).