通过本节课,讲解如何添加自定义的飞行模式,帮助大家深入了解APM固件二次开发的流程。
1 功能目标
添加一种“五角星航线模式”飞行模式:切入此模式后,飞控自动按照“五角星航线”进行自动飞行。
2 添加代码
说明:飞行模式定义于mode.h文件中,Mode为基类型,类型ModeGuided即对应引导模式,以此为参照,创建我们自己的飞行模式,名称为DRAWSTAR,
类型名为ModeDrawStar。
使用Vscode打开ardupilot文件夹。(4.0.x版本源码)
进入ArduCopter文件夹
1、更改config.h文件 (大概第273行,不同版本源码位置不同),添加MODE_DRAWSTAR_ENABLED定义,代码如下
//////////////////////////////////////////////////////////////////////////////
// Drawstar mode - draw five-pointed star ----waypoint
#ifndef MODE_DRAWSTAR_ENABLED
# define MODE_DRAWSTAR_ENABLED ENABLED
#endif
2、更改mode.h文件 在enumclassNumber : uint8_t { }中,参照其它类型,添加DRAWSTAR,代码如下,
此处设定DRAWSTAR模式为29,不同版本代码的值不同,在源代码最下方依次序添加
TURTLE = 28, // Flip over after crash
DRAWSTAR = 29, // five-points star waypoints
3、更改mode.h文件 参照ModeGuided类型,在其后添加ModeDrawStar类型定义,代码如下
class ModeDrawStar : public Mode {
public:
// inherit constructor
using Mode::Mode;
Number mode_number() const override { return Number::DRAWSTAR; }
bool init(bool ignore_checks) override;
void run() override;
bool requires_GPS() const override { return true; } // 此模式需要有GPS定位
bool has_manual_throttle() const override { return false; } // 此模式不允许手动控制油门
bool allows_arming(AP_Arming::Method method) const override { return false; } // 不允许在此模式下解锁
bool is_autopilot() const override { return true; } // 此模式为自动飞行控制
bool has_user_takeoff(bool must_navigate) const override { return false; } // 不允许在此模式下直接起飞(必须是在空中切到此模式)
bool in_guided_mode() const override { return true; } // 此模式是一种引导的模式
protected:
const char *name() const override { return "DRAW_STAR"; }
const char *name4() const override { return "STAR"; }
private:
Vector3f path[10]; //航点
int path_num; //当前航点
void generate_path(); //生成航线
// wp controller
void pos_control_start(); //
void pos_control_run(); //
};
4、更改copter.h文件 (大概第208行,不同版本源码位置不同),添加对ModeDrawStar的友元类声明,代码如下
friend class ModeGuided;
friend class ModeDrawStar;
5、更改copter.h文件 (大概第945行,不同版本源码位置不同),参照其它类型,创建ModeDrawStar类型对象 mode_drawstar,代码如下
#if MODE_DRAWSTAR_ENABLED == ENABLED
ModeDrawStar mode_drawstar;
#endif
6、更改GCS_Mavlink.cpp文件 (大概第32行,不同版本源码位置不同),参照其它类型,添加对我们自定义类型DRAWSTAR的处理,代码如下
case Mode::Number::GUIDED:
case Mode::Number::DRAWSTAR:
case Mode::Number::CIRCLE:
7、创建mode_DrawStar.cpp文件 代码如下
#include "Copter.h"
#if MODE_DRAWSTAR_ENABLED == ENABLED
// init - initialise guided controller
bool ModeDrawStar::init(bool ignore_checks)
{
// start in velaccel control mode
path_num = 0; //
generate_path(); //
pos_control_start(); //
return true;
}
void ModeDrawStar::generate_path(){
float radius_cm = 1000.0;
wp_nav->get_wp_stopping_point(path[0]);
path[1] = path[0] + Vector3f(1.0f, 0, 0) * radius_cm;
path[2] = path[0] + Vector3f(-cosf(radians(36.0f)), -sinf(radians(36.0f)), 0) * radius_cm;
path[3] = path[0] + Vector3f(sinf(radians(18.0f)), cosf(radians(18.0f)), 0) * radius_cm;
path[4] = path[0] + Vector3f(sinf(radians(18.0f)), -cosf(radians(18.0f)), 0) * radius_cm;
path[5] = path[0] + Vector3f(-cosf(radians(36.0f)), sinf(radians(36.0f)), 0) * radius_cm;
path[6] = path[1];
}
// run - runs the guided controller
// should be called at 100hz or more
void ModeDrawStar::run()
{
if (path_num < 6) { // 五角星航线尚未走完
if (wp_nav->reached_wp_destination()) { // 到达某个端点
path_num++;
wp_nav->set_wp_destination(path[path_num], false); // 将下一个航点位置设置为导航控制模块的目标位置
}
} else if ((path_num == 6) && wp_nav->reached_wp_destination()) { // 五角星航线运行完成,自动进入Loiter模式
gcs().send_text(MAV_SEVERITY_INFO, "Draw star finished, now go into loiter mode");
copter.set_mode(Mode::Number::LOITER, ModeReason::MISSION_END); // 切换到loiter模式
}
pos_control_run(); // 位置控制器
}
// 更改自guided模式的wp_control_start initialise guided mode's waypoint navigation controller
void ModeDrawStar::pos_control_start()
{
// initialise waypoint and spline controller
wp_nav->wp_and_spline_init();
// initialise wpnav to stopping point
//Vector3f stopping_point;
//wp_nav->get_wp_stopping_point(stopping_point);
// no need to check return status because terrain data is not used
wp_nav->set_wp_destination(path[0], false);
// initialise yaw
auto_yaw.set_mode_to_default(false);
}
// 源自guided模式的wp_control_run run guided mode's waypoint navigation controller
void ModeDrawStar::pos_control_run()
{
// process pilot's yaw input
float target_yaw_rate = 0;
if (!copter.failsafe.radio && use_pilot_yaw()) {
// get pilot's desired yaw rate
target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->norm_input_dz());
if (!is_zero(target_yaw_rate)) {
auto_yaw.set_mode(AUTO_YAW_HOLD);
}
}
// if not armed set throttle to zero and exit immediately
if (is_disarmed_or_landed()) {
// do not spool down tradheli when on the ground with motor interlock enabled
make_safe_ground_handling(copter.is_tradheli() && motors->get_interlock());
return;
}
// set motors to full range
motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
// run waypoint controller
copter.failsafe_terrain_set_status(wp_nav->update_wpnav());
// call z-axis position controller (wpnav should have already updated it's alt target)
pos_control->update_z_controller();
// call attitude controller
if (auto_yaw.mode() == AUTO_YAW_HOLD) {
// roll & pitch from waypoint controller, yaw rate from pilot
attitude_control->input_thrust_vector_rate_heading(wp_nav->get_thrust_vector(), target_yaw_rate);
} else if (auto_yaw.mode() == AUTO_YAW_RATE) {
// roll & pitch from waypoint controller, yaw rate from mavlink command or mission item
attitude_control->input_thrust_vector_rate_heading(wp_nav->get_thrust_vector(), auto_yaw.rate_cds());
} else {
// roll, pitch from waypoint controller, yaw heading from GCS or auto_heading()
attitude_control->input_thrust_vector_heading(wp_nav->get_thrust_vector(), auto_yaw.yaw());
}
}
#endif
3 仿真查看结果
1、启动copter仿真,会重新编译代码,使用MP链接仿真器
2、仿真器界面进行控制,切换到我们自定义的飞行模式DRAWSTAR(29)
// 解锁
// 注意,在AUTO模式下是禁止解锁的,如果无法解锁,请先检查一下飞控是否处于AUTO模式
// 可通过“mode loiter”命令将飞控切到loiter模式,然后解锁起飞,之后再切到其他模式
arm throttle
// 将油门推到一个较高的位置,起飞
rc 3 1800
// 将油门放到中位
rc 3 1500
// 切换到五角星航线模式
mode 29 // 注意,对于新的master版本例程,此处应为mode 29 不同版本数字不同
3、MP查看仿真结果