通过本节课,讲解如何添加自定义的飞行模式,帮助大家深入了解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 crashDRAWSTAR = 29, // five-points star waypoints
3、更改mode.h文件 参照ModeGuided类型,在其后添加ModeDrawStar类型定义,代码如下
class ModeDrawStar : public Mode {public:// inherit constructorusing 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 controllervoid 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 == ENABLEDModeDrawStar 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 controllerbool ModeDrawStar::init(bool ignore_checks){// start in velaccel control modepath_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 morevoid 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 controllervoid ModeDrawStar::pos_control_start(){// initialise waypoint and spline controllerwp_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 usedwp_nav->set_wp_destination(path[0], false);// initialise yawauto_yaw.set_mode_to_default(false);}// 源自guided模式的wp_control_run run guided mode's waypoint navigation controllervoid ModeDrawStar::pos_control_run(){// process pilot's yaw inputfloat target_yaw_rate = 0;if (!copter.failsafe.radio && use_pilot_yaw()) {// get pilot's desired yaw ratetarget_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 immediatelyif (is_disarmed_or_landed()) {// do not spool down tradheli when on the ground with motor interlock enabledmake_safe_ground_handling(copter.is_tradheli() && motors->get_interlock());return;}// set motors to full rangemotors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);// run waypoint controllercopter.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 controllerif (auto_yaw.mode() == AUTO_YAW_HOLD) {// roll & pitch from waypoint controller, yaw rate from pilotattitude_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 itemattitude_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查看仿真结果

