mode_attitude.c 15 KB

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