mode_attitude.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. #include "mode_attitude.h"
  2. #include "auto_pilot.h"
  3. #include "control_attitude.h"
  4. #include "control_rate.h"
  5. #include "control_throttle.h"
  6. #include "euler.h"
  7. #include "flight_mode.h"
  8. #include "helpler_funtions.h"
  9. #include "math.h"
  10. #include "matrix.h"
  11. #include "params.h"
  12. #include "soft_imu.h"
  13. #include "soft_port_uart4.h"
  14. #include "soft_rc_input.h"
  15. #include "my_math.h"
  16. #include "soft_motor_output.h"
  17. #include "mode_gcs_tax_launch_run.h"
  18. struct controller_xy _cxy;
  19. bool attitude_init(void)
  20. {
  21. init_attitude_head();
  22. butter2_filter_init(&_cxy.vt_ff_flt[0], 200, 10);
  23. butter2_filter_init(&_cxy.vt_ff_flt[1], 200, 10);
  24. return true;
  25. }
  26. float dist_comp[2] = {0.0f};
  27. void control_xy(struct controller_xy *cxy, float dt)
  28. {
  29. const float P_KP = pid_v_pos.dist_p;
  30. const float V_KP = pid_v_pos.speed_p;
  31. const float V_KI = pid_v_pos.acc_i;
  32. const float V_KD = pid_v_pos.acc_p;
  33. cxy->pc[0] = pid_m_posx.loc_c * 0.01f;
  34. cxy->pc[1] = pid_m_posy.loc_c * 0.01f;
  35. cxy->vc[0] = pid_m_posx.vel_c * 0.01f;
  36. cxy->vc[1] = pid_m_posy.vel_c * 0.01f;
  37. cxy->ac[0] = pid_m_posx.acc_c * 0.01f;
  38. cxy->ac[1] = pid_m_posy.acc_c * 0.01f;
  39. /* 按需重置控制器 */
  40. if (cxy->reset)
  41. {
  42. cxy->reset = false;
  43. cxy->pt[0] = cxy->pc[0];
  44. cxy->pt[1] = cxy->pc[1];
  45. cxy->vt[0] = cxy->vc[0];
  46. cxy->vt[1] = cxy->vc[1];
  47. cxy->at[0] = cxy->ac[0];
  48. cxy->at[1] = cxy->ac[1];
  49. cxy->ve_integ[0] = cxy->ve_integ[1] = 0;
  50. cxy->pos_integ[0] = cxy->pos_integ[1] = 0;
  51. butter2_filter_reset(&cxy->vt_ff_flt[0], 0);
  52. butter2_filter_reset(&cxy->vt_ff_flt[1], 0);
  53. }
  54. /*将无人机调整到互定位的桶的中心*/
  55. for (int i = 0; i < 2; i++)
  56. {
  57. if (cxy->pt[i] > 0.1f)
  58. {
  59. cxy->pt[i] -= 0.002f;
  60. }
  61. else if (cxy->pt[i] < -0.1f)
  62. {
  63. cxy->pt[i] += 0.002f;
  64. }
  65. }
  66. float vt[2] = {0}, ve[2] = {0};
  67. static float target_pos_shift[2] = {0};
  68. for (int i = 0; i < 2; ++i)
  69. {
  70. // /*如果位置积分持续存在,则需要将位置向相反的方向移动,否则会丢失互定位*/
  71. // if(fabsf(cxy->pos_integ[i]) > 0.2f) // 0.2~1.0m 的误差区间,是消除稳态误差的关键阶段 —— 积分项缓慢累加,精准 “拉回” 目标点,同时避免震荡
  72. // {
  73. // target_pos_shift[i] += (cxy->pos_integ[i] * 1.0f - target_pos_shift[i]) * 0.001f;
  74. // }
  75. // else // 若位置误差 <0.2m,说明已接近目标点,积分项继续累加可能导致 “积分震荡”(来回穿越目标点
  76. // {
  77. target_pos_shift[i] = 0.0f;
  78. //}
  79. vt[i] = (cxy->pt[i] + target_pos_shift[i] - cxy->pc[i]) * P_KP;
  80. // if(fabsf(cxy->pt[i] + target_pos_shift[i] - cxy->pc[i]) < 3.0f
  81. // &&fabsf(cxy->pt[i] + target_pos_shift[i] - cxy->pc[i]) > 1.0f )
  82. // cxy->pos_integ[i] += (cxy->pt[i] + target_pos_shift[i] - cxy->pc[i]) * dt * V_KI;
  83. // cxy->pos_integ[i] = constrain_float(cxy->pos_integ[i], -2.0f, 2.0f);
  84. // 若位置误差 > 1.0m,说明载体离目标点还很远,此时优先用比例项产生大速度指令快速逼近,积分项累加反而可能导致超调
  85. }
  86. #if 0
  87. for (int i = 0; i < 2; ++i)
  88. {
  89. /*如果位置积分持续存在,则需要将位置向相反的方向移动,否则会丢失互定位*/
  90. if(fabsf(cxy->pos_integ[i]) > 0.2f)
  91. {
  92. // 优化1:加快目标位置偏移响应速度(系数从0.001→0.01),快速抵消积分饱和影响
  93. target_pos_shift[i] += (cxy->pos_integ[i] * 1.0f - target_pos_shift[i]) * 0.01f;
  94. }
  95. else
  96. {
  97. target_pos_shift[i] = 0.0f;
  98. }
  99. // 速度指令 = 修正后的位置误差 × 位置环比例系数(P_KP)
  100. vt[i] = (cxy->pt[i] + target_pos_shift[i] - cxy->pc[i]) * P_KP;
  101. // 优化2:缩小积分触发区间(从1~3m→0.2~1.0m),仅小误差时积分,避免大误差饱和
  102. if(fabsf(cxy->pt[i] + target_pos_shift[i] - cxy->pc[i]) < 1.0f
  103. && fabsf(cxy->pt[i] + target_pos_shift[i] - cxy->pc[i]) > 0.2f )
  104. {
  105. // 积分累积:误差×时间步长×积分系数
  106. cxy->pos_integ[i] += (cxy->pt[i] + target_pos_shift[i] - cxy->pc[i]) * dt * V_KI;
  107. }
  108. // 优化3:减小积分饱和值(从±2.0f→±0.5f),避免加速度额外偏移过大
  109. cxy->pos_integ[i] = constrain_float(cxy->pos_integ[i], -0.5f, 0.5f);
  110. // 优化4:添加积分衰减逻辑,无误差时快速清零,避免积分残留
  111. cxy->pos_integ[i] *= 0.98f;
  112. }
  113. #endif
  114. dist_comp[0] = target_pos_shift[0];
  115. dist_comp[1] = target_pos_shift[1];
  116. Vector_ConstrainNorm(vt, 2, 2.0f);
  117. /* 限制目标速度增量 */
  118. const float ACC_MAX = GRAVITY_MSS * tanf(DEG_TO_RAD * 35.0f);
  119. float delt_vt[2] = {0};
  120. for (int i = 0; i < 2; ++i)
  121. {
  122. delt_vt[i] = vt[i] - cxy->vt[i];
  123. }
  124. Vector_ConstrainNorm(delt_vt, 2, ACC_MAX * dt);
  125. for (int i = 0; i < 2; ++i)
  126. {
  127. vt[i] = cxy->vt[i] + delt_vt[i];
  128. }
  129. for (int i = 0; i < 2; ++i)
  130. {
  131. ve[i] = vt[i] - (1.0f * cxy->vc[i]);
  132. }
  133. for (int i = 0; i < 2; ++i)
  134. {
  135. float ve_integ = cxy->ve_integ[i] + dt * ve[i] * V_KI;
  136. cxy->ve_integ[i] = constrain_float(ve_integ, -10.0f, 10.0f);
  137. }
  138. float vt_ff[2] = {delt_vt[0] * V_KD / dt, delt_vt[1] * V_KD / dt};
  139. Vector_ConstrainNorm(vt_ff, 2, 2.0f);
  140. for (int i = 0; i < 2; ++i)
  141. {
  142. vt_ff[i] = butter2_filter_apply(&cxy->vt_ff_flt[i], vt_ff[i]);
  143. }
  144. float at[2] = {0};
  145. for (int i = 0; i < 2; ++i)
  146. {
  147. at[i] = V_KP * ve[i] + cxy->ve_integ[i] + vt_ff[i] - V_KD * 1.5f * cxy->ac[i] + cxy->pos_integ[i];
  148. }
  149. Vector_ConstrainNorm(at, 2, 10.0f);
  150. float delt_at[2] = {0};
  151. for (int i = 0; i < 2; ++i)
  152. {
  153. delt_at[i] = at[i] - cxy->at[i];
  154. }
  155. Vector_ConstrainNorm(delt_at, 2, 35.0f * dt);
  156. for (int i = 0; i < 2; ++i)
  157. {
  158. at[i] = cxy->at[i] + delt_at[i];
  159. }
  160. for (int i = 0; i < 2; ++i)
  161. {
  162. cxy->vt[i] = vt[i];
  163. cxy->at[i] = at[i];
  164. }
  165. }
  166. #define _ATT_CXY_0_RATIO (-0.8f) // 比例暂时以1除以积分周期(s)为准
  167. #define _ATT_CXY_1_RATIO (-0.8f)
  168. #define _ATT_HWD_INT_PERIOD (5.0f) // 以5s为积分周期
  169. #define _ATT_ROLL_THRESHOLD (5.0f) // ROLL角度阈值(度)
  170. #define _ATT_PITCH_THRESHOLD (5.0f) // PITCH角度阈值(度)
  171. #define _ATT_ANGLE_PREIOD (3.0f) // 角度变化阈值时间周期(秒)
  172. #define _ATT_GO_BACK_TIME_PERIOD (5.0f) // 打反向运动时常
  173. #define _ATT_GO_BACK_EULER_ANGLE (15.0f) // 打反向欧拉角阈值(度)
  174. typedef enum
  175. {
  176. HDW_STATE_ACC_INT = 0, // 加速度积分
  177. HDW_STATE_BACK_EULER, // 打反向欧拉角
  178. HDW_STATE_RECOVER // 恢复阶段
  179. } hdw_state_t;
  180. typedef struct
  181. {
  182. hdw_state_t state;
  183. uint32_t state_enter_t;
  184. // 加速度积分
  185. bool acc_int_active;
  186. uint32_t acc_int_start_t;
  187. float acc_int_x;
  188. float acc_int_y;
  189. // 姿态监控
  190. bool angle_monitor_triggered;
  191. uint32_t angle_over_start_t;
  192. bool roll_triggered;
  193. bool pitch_triggered;
  194. // 反向欧拉
  195. bool euler_dir_set;
  196. int8_t roll_dir; // -1 / 0 / +1
  197. int8_t pitch_dir;
  198. } hdw_ctx_t;
  199. static hdw_ctx_t hdw_ctx = {
  200. .state = HDW_STATE_ACC_INT,
  201. .state_enter_t = 0,
  202. .acc_int_active = false,
  203. .acc_int_start_t = 0,
  204. .acc_int_x = 0.0f,
  205. .acc_int_y = 0.0f,
  206. .angle_monitor_triggered = false,
  207. .angle_over_start_t = 0,
  208. .roll_triggered = false,
  209. .pitch_triggered = false,
  210. .euler_dir_set = false,
  211. .roll_dir = 0,
  212. .pitch_dir = 0,
  213. };
  214. static inline void no_hdw_reset(hdw_ctx_t *ctx)
  215. {
  216. ctx->state = HDW_STATE_ACC_INT;
  217. ctx->state_enter_t = 0;
  218. ctx->acc_int_active = false;
  219. ctx->acc_int_start_t = 0;
  220. ctx->acc_int_x = 0.0f;
  221. ctx->acc_int_y = 0.0f;
  222. ctx->angle_monitor_triggered = false;
  223. ctx->angle_over_start_t = 0;
  224. }
  225. static inline void no_hdw_enter_state(hdw_ctx_t *ctx, hdw_state_t new_state)
  226. {
  227. ctx->state = new_state;
  228. ctx->state_enter_t = micros();
  229. // 状态切换通用清理
  230. ctx->angle_monitor_triggered = false;
  231. ctx->acc_int_active = false;
  232. }
  233. // 无互定位下状态机
  234. static void hdw_run_no_insgps(hdw_ctx_t *ctx, float dt)
  235. {
  236. float ax_cmd = 0.0f;
  237. float ay_cmd = 0.0f;
  238. switch (ctx->state)
  239. {
  240. /*================ 1. 加速度积分 =================*/
  241. case HDW_STATE_ACC_INT:
  242. {
  243. if (!ctx->acc_int_active)
  244. {
  245. ctx->acc_int_x = 0;
  246. ctx->acc_int_y = 0;
  247. ctx->acc_int_start_t = micros();
  248. ctx->acc_int_active = true;
  249. }
  250. ctx->acc_int_x += pid_m_posx.acc_c * dt * 0.01f;
  251. ctx->acc_int_y += pid_m_posy.acc_c * dt * 0.01f;
  252. // 水平方向无加速度时应该是姿态角为0度
  253. // 姿态异常检测
  254. // float att_abs = fmaxf(fabsf(pid_m_roll.angle_c),
  255. // fabsf(pid_m_pitch.angle_c));
  256. // if (att_abs > 8.0f)
  257. // {
  258. // // 姿态开始不可信,慢慢衰减积分
  259. // ctx->acc_int_x *= 0.98f;
  260. // ctx->acc_int_y *= 0.98f;
  261. // }
  262. ax_cmd = constrain_float(ctx->acc_int_x * _ATT_CXY_0_RATIO, -3.0f, 3.0f);
  263. ay_cmd = constrain_float(ctx->acc_int_y * _ATT_CXY_1_RATIO, -3.0f, 3.0f);
  264. // 姿态异常检测
  265. if ((fabsf(pid_m_roll.angle_t - pid_m_roll.angle_c) > _ATT_ROLL_THRESHOLD ||
  266. fabsf(pid_m_pitch.angle_t - pid_m_pitch.angle_c) > _ATT_PITCH_THRESHOLD) )
  267. {
  268. if(ctx->angle_monitor_triggered == false)
  269. {
  270. ctx->angle_monitor_triggered = true;
  271. ctx->angle_over_start_t = micros();
  272. }
  273. if (micros() - ctx->angle_over_start_t > _ATT_ANGLE_PREIOD * 1e6)
  274. {
  275. bool roll_over = fabsf(pid_m_roll.angle_t - pid_m_roll.angle_c) > _ATT_ROLL_THRESHOLD;
  276. bool pitch_over = fabsf(pid_m_pitch.angle_t - pid_m_pitch.angle_c) > _ATT_PITCH_THRESHOLD;
  277. ctx->roll_triggered = roll_over;
  278. ctx->pitch_triggered = pitch_over;
  279. ctx->euler_dir_set = false;
  280. angle_plan_run_cnt++;
  281. no_hdw_enter_state(ctx, HDW_STATE_BACK_EULER);
  282. }
  283. }else
  284. {
  285. ctx->angle_monitor_triggered = false;
  286. }
  287. // 周期性重置积分
  288. if (micros() - ctx->acc_int_start_t > _ATT_HWD_INT_PERIOD * 1e6)
  289. {
  290. ctx->acc_int_x = 0;
  291. ctx->acc_int_y = 0;
  292. // float leak = dt / _HWD_INT_PERIOD;
  293. // ctx->acc_int_x *= (1.0f - leak);
  294. // ctx->acc_int_y *= (1.0f - leak);
  295. ctx->acc_int_start_t = micros();
  296. }
  297. break;
  298. }
  299. /*================ 2. 打反向欧拉 =================*/
  300. case HDW_STATE_BACK_EULER:
  301. {
  302. if (!ctx->euler_dir_set)
  303. {
  304. ctx->roll_dir = (pid_m_roll.angle_c > 0) ? 1 : -1;
  305. ctx->pitch_dir = (pid_m_pitch.angle_c > 0) ? 1 : -1;
  306. ctx->euler_dir_set = true;
  307. }
  308. if (micros() - ctx->state_enter_t > _ATT_GO_BACK_TIME_PERIOD * 1e6)
  309. {
  310. no_hdw_enter_state(ctx, HDW_STATE_ACC_INT);
  311. }
  312. break;
  313. }
  314. /*================ 3. 恢复 =================*/
  315. case HDW_STATE_RECOVER:
  316. {
  317. if (micros() - ctx->state_enter_t > 1.0f * 1e6) // 以0姿态角持续1秒
  318. {
  319. no_hdw_enter_state(ctx, HDW_STATE_ACC_INT);
  320. }
  321. break;
  322. }
  323. default:
  324. no_hdw_enter_state(ctx, HDW_STATE_ACC_INT);
  325. break;
  326. }
  327. /* 统一输出期望加速度 */
  328. _cxy.at[0] = ax_cmd; // 只有在加速度积分下有用 反向欧拉直接控制欧拉角覆盖期望加速度
  329. _cxy.at[1] = ay_cmd;
  330. }
  331. // 设置反向欧拉角
  332. static void no_hdw_apply_back_euler(hdw_ctx_t *ctx)
  333. {
  334. if (ctx->state != HDW_STATE_BACK_EULER)
  335. return;
  336. if (ctx->roll_triggered)
  337. pid_m_roll.angle_t = -ctx->roll_dir * _ATT_GO_BACK_EULER_ANGLE;
  338. else
  339. pid_m_roll.angle_t = 0;
  340. if (ctx->pitch_triggered)
  341. pid_m_pitch.angle_t = -ctx->pitch_dir * _ATT_GO_BACK_EULER_ANGLE;
  342. else
  343. pid_m_pitch.angle_t = 0;
  344. }
  345. void attitude_run(void)
  346. {
  347. hdw_ctx_t *ctx = &hdw_ctx;
  348. if (comp_rc_status == COMP_NORMAL && rc_signal_health == RC_SIGNAL_HEALTH)
  349. {
  350. if (ground_air_status == IN_AIR)
  351. {
  352. if(rc_in[RC_CH8] > 1500)
  353. {
  354. // if(ins.insgps_ok == INSGPS)
  355. // {
  356. // control_xy(&_cxy, fast_loop_dt);
  357. // no_hdw_reset(ctx); // 复位无互定位下的控制器
  358. // }
  359. // else
  360. // {
  361. // _cxy.reset = true; // 重置互定位控制器
  362. hdw_run_no_insgps(ctx, fast_loop_dt); // 无互定位状态机
  363. //}
  364. float dcm_z[3] = {_cxy.at[0], _cxy.at[1], GRAVITY_MSS};
  365. Vector_Normalize(dcm_z, 3);
  366. float dcm_y[3] = {0, 1, 0};
  367. dcm_y[2] = -(dcm_z[0] * dcm_y[0] + dcm_z[1] * dcm_y[1]) / dcm_z[2];
  368. Vector_Normalize(dcm_y, 3);
  369. float dcm_x[3] = {0, 0, 0};
  370. Vector_CrossProduct_3D(dcm_y, dcm_z, dcm_x);
  371. float dcm[3][3];
  372. for (int i = 0; i < 3; ++i)
  373. {
  374. dcm[i][0] = dcm_x[i];
  375. dcm[i][1] = dcm_y[i];
  376. dcm[i][2] = dcm_z[i];
  377. }
  378. euler_angle_t euler = {0};
  379. Euler_ByDcm(dcm, &euler);
  380. pid_m_roll.angle_t = apply(euler.roll * RAD_TO_DEG, t_roll_last, 15.0f, fast_loop_dt);
  381. pid_m_pitch.angle_t = apply(euler.pitch * RAD_TO_DEG, t_pitch_last, 15.0f, fast_loop_dt);
  382. no_hdw_apply_back_euler(ctx); // 打反向欧拉角时 覆盖期望欧拉
  383. t_roll_last = pid_m_roll.angle_t;
  384. t_pitch_last = pid_m_pitch.angle_t;
  385. }
  386. else
  387. {
  388. _cxy.reset = true;
  389. get_pilot_desired_lean_angles(rc_in[RC_ROLL], rc_in[RC_PITCH]);
  390. }
  391. }
  392. else
  393. {
  394. _cxy.reset = true;
  395. get_pilot_desired_lean_angles(rc_in[RC_ROLL], rc_in[RC_PITCH]);
  396. /* 清除内环积分 */
  397. clear_rate_i_item(&pid_m_roll);
  398. clear_rate_i_item(&pid_m_pitch);
  399. clear_rate_i_item(&pid_m_yaw);
  400. }
  401. get_pilot_desired_climb_rate_fromrc(rc_in[RC_THR]);
  402. }
  403. else
  404. {
  405. _cxy.reset = true;
  406. get_pilot_desired_lean_angles(1500, 1500);
  407. get_pilot_desired_yaw_angle_fromrc(1500, fast_loop_dt);
  408. get_pilot_desired_climb_rate_fromrc(1500);
  409. }
  410. Calculate_Target_Az(fast_loop_dt);
  411. }
  412. void attitude_exit(void)
  413. {
  414. pid_m_posx.vel_i_item = 0.0f;
  415. pid_m_posy.vel_i_item = 0.0f;
  416. pid_m_posx.acc_filter_reset = true;
  417. pid_m_posy.acc_filter_reset = true;
  418. /* 在有落地上锁检测的模式都需要以下代码,以免进入触地怠速后切出到别的模式无法恢复油门控制
  419. */
  420. if (ground_air_status == IN_AIR && throttle_pidctrl_status == THROTTLE_ONGROUND_IDLE)
  421. {
  422. throttle_pidctrl_status = THROTTLE_INAIR_RUNNING;
  423. }
  424. }