通过本节课,讲解如何添加自定义的飞行模式,帮助大家深入了解APM固件二次开发的流程。

1 功能目标

添加一种“五角星航线模式”飞行模式:切入此模式后,飞控自动按照“五角星航线”进行自动飞行。

2 添加代码

说明:飞行模式定义于mode.h文件中,Mode为基类型,类型ModeGuided即对应引导模式,以此为参照,创建我们自己的飞行模式,名称为DRAWSTAR,
类型名为ModeDrawStar。

使用Vscode打开ardupilot文件夹。(4.0.x版本源码)
进入ArduCopter文件夹
1、更改config.h文件 (大概第273行,不同版本源码位置不同),添加MODE_DRAWSTAR_ENABLED定义,代码如下

  1. //////////////////////////////////////////////////////////////////////////////
  2. // Drawstar mode - draw five-pointed star ----waypoint
  3. #ifndef MODE_DRAWSTAR_ENABLED
  4. # define MODE_DRAWSTAR_ENABLED ENABLED
  5. #endif

2、更改mode.h文件 在enumclassNumber : uint8_t { }中,参照其它类型,添加DRAWSTAR,代码如下,
此处设定DRAWSTAR模式为29,不同版本代码的值不同,在源代码最下方依次序添加

  1. TURTLE = 28, // Flip over after crash
  2. DRAWSTAR = 29, // five-points star waypoints

3、更改mode.h文件 参照ModeGuided类型,在其后添加ModeDrawStar类型定义,代码如下

  1. class ModeDrawStar : public Mode {
  2. public:
  3. // inherit constructor
  4. using Mode::Mode;
  5. Number mode_number() const override { return Number::DRAWSTAR; }
  6. bool init(bool ignore_checks) override;
  7. void run() override;
  8. bool requires_GPS() const override { return true; } // 此模式需要有GPS定位
  9. bool has_manual_throttle() const override { return false; } // 此模式不允许手动控制油门
  10. bool allows_arming(AP_Arming::Method method) const override { return false; } // 不允许在此模式下解锁
  11. bool is_autopilot() const override { return true; } // 此模式为自动飞行控制
  12. bool has_user_takeoff(bool must_navigate) const override { return false; } // 不允许在此模式下直接起飞(必须是在空中切到此模式)
  13. bool in_guided_mode() const override { return true; } // 此模式是一种引导的模式
  14. protected:
  15. const char *name() const override { return "DRAW_STAR"; }
  16. const char *name4() const override { return "STAR"; }
  17. private:
  18. Vector3f path[10]; //航点
  19. int path_num; //当前航点
  20. void generate_path(); //生成航线
  21. // wp controller
  22. void pos_control_start(); //
  23. void pos_control_run(); //
  24. };

4、更改copter.h文件 (大概第208行,不同版本源码位置不同),添加对ModeDrawStar的友元类声明,代码如下

  1. friend class ModeGuided;
  2. friend class ModeDrawStar;

5、更改copter.h文件 (大概第945行,不同版本源码位置不同),参照其它类型,创建ModeDrawStar类型对象 mode_drawstar,代码如下

  1. #if MODE_DRAWSTAR_ENABLED == ENABLED
  2. ModeDrawStar mode_drawstar;
  3. #endif

6、更改GCS_Mavlink.cpp文件 (大概第32行,不同版本源码位置不同),参照其它类型,添加对我们自定义类型DRAWSTAR的处理,代码如下

  1. case Mode::Number::GUIDED:
  2. case Mode::Number::DRAWSTAR:
  3. case Mode::Number::CIRCLE:

7、创建mode_DrawStar.cpp文件 代码如下

  1. #include "Copter.h"
  2. #if MODE_DRAWSTAR_ENABLED == ENABLED
  3. // init - initialise guided controller
  4. bool ModeDrawStar::init(bool ignore_checks)
  5. {
  6. // start in velaccel control mode
  7. path_num = 0; //
  8. generate_path(); //
  9. pos_control_start(); //
  10. return true;
  11. }
  12. void ModeDrawStar::generate_path(){
  13. float radius_cm = 1000.0;
  14. wp_nav->get_wp_stopping_point(path[0]);
  15. path[1] = path[0] + Vector3f(1.0f, 0, 0) * radius_cm;
  16. path[2] = path[0] + Vector3f(-cosf(radians(36.0f)), -sinf(radians(36.0f)), 0) * radius_cm;
  17. path[3] = path[0] + Vector3f(sinf(radians(18.0f)), cosf(radians(18.0f)), 0) * radius_cm;
  18. path[4] = path[0] + Vector3f(sinf(radians(18.0f)), -cosf(radians(18.0f)), 0) * radius_cm;
  19. path[5] = path[0] + Vector3f(-cosf(radians(36.0f)), sinf(radians(36.0f)), 0) * radius_cm;
  20. path[6] = path[1];
  21. }
  22. // run - runs the guided controller
  23. // should be called at 100hz or more
  24. void ModeDrawStar::run()
  25. {
  26. if (path_num < 6) { // 五角星航线尚未走完
  27. if (wp_nav->reached_wp_destination()) { // 到达某个端点
  28. path_num++;
  29. wp_nav->set_wp_destination(path[path_num], false); // 将下一个航点位置设置为导航控制模块的目标位置
  30. }
  31. } else if ((path_num == 6) && wp_nav->reached_wp_destination()) { // 五角星航线运行完成,自动进入Loiter模式
  32. gcs().send_text(MAV_SEVERITY_INFO, "Draw star finished, now go into loiter mode");
  33. copter.set_mode(Mode::Number::LOITER, ModeReason::MISSION_END); // 切换到loiter模式
  34. }
  35. pos_control_run(); // 位置控制器
  36. }
  37. // 更改自guided模式的wp_control_start initialise guided mode's waypoint navigation controller
  38. void ModeDrawStar::pos_control_start()
  39. {
  40. // initialise waypoint and spline controller
  41. wp_nav->wp_and_spline_init();
  42. // initialise wpnav to stopping point
  43. //Vector3f stopping_point;
  44. //wp_nav->get_wp_stopping_point(stopping_point);
  45. // no need to check return status because terrain data is not used
  46. wp_nav->set_wp_destination(path[0], false);
  47. // initialise yaw
  48. auto_yaw.set_mode_to_default(false);
  49. }
  50. // 源自guided模式的wp_control_run run guided mode's waypoint navigation controller
  51. void ModeDrawStar::pos_control_run()
  52. {
  53. // process pilot's yaw input
  54. float target_yaw_rate = 0;
  55. if (!copter.failsafe.radio && use_pilot_yaw()) {
  56. // get pilot's desired yaw rate
  57. target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->norm_input_dz());
  58. if (!is_zero(target_yaw_rate)) {
  59. auto_yaw.set_mode(AUTO_YAW_HOLD);
  60. }
  61. }
  62. // if not armed set throttle to zero and exit immediately
  63. if (is_disarmed_or_landed()) {
  64. // do not spool down tradheli when on the ground with motor interlock enabled
  65. make_safe_ground_handling(copter.is_tradheli() && motors->get_interlock());
  66. return;
  67. }
  68. // set motors to full range
  69. motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
  70. // run waypoint controller
  71. copter.failsafe_terrain_set_status(wp_nav->update_wpnav());
  72. // call z-axis position controller (wpnav should have already updated it's alt target)
  73. pos_control->update_z_controller();
  74. // call attitude controller
  75. if (auto_yaw.mode() == AUTO_YAW_HOLD) {
  76. // roll & pitch from waypoint controller, yaw rate from pilot
  77. attitude_control->input_thrust_vector_rate_heading(wp_nav->get_thrust_vector(), target_yaw_rate);
  78. } else if (auto_yaw.mode() == AUTO_YAW_RATE) {
  79. // roll & pitch from waypoint controller, yaw rate from mavlink command or mission item
  80. attitude_control->input_thrust_vector_rate_heading(wp_nav->get_thrust_vector(), auto_yaw.rate_cds());
  81. } else {
  82. // roll, pitch from waypoint controller, yaw heading from GCS or auto_heading()
  83. attitude_control->input_thrust_vector_heading(wp_nav->get_thrust_vector(), auto_yaw.yaw());
  84. }
  85. }
  86. #endif

3 仿真查看结果

1、启动copter仿真,会重新编译代码,使用MP链接仿真器
2、仿真器界面进行控制,切换到我们自定义的飞行模式DRAWSTAR(29)

  1. // 解锁
  2. // 注意,在AUTO模式下是禁止解锁的,如果无法解锁,请先检查一下飞控是否处于AUTO模式
  3. // 可通过“mode loiter”命令将飞控切到loiter模式,然后解锁起飞,之后再切到其他模式
  4. arm throttle
  5. // 将油门推到一个较高的位置,起飞
  6. rc 3 1800
  7. // 将油门放到中位
  8. rc 3 1500
  9. // 切换到五角星航线模式
  10. mode 29 // 注意,对于新的master版本例程,此处应为mode 29 不同版本数字不同

3、MP查看仿真结果
image.png