heading_diff_ctrl_c.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /**
  2. ******************************************************************************
  3. * @file : heading_diff_ctrl_c.cpp
  4. * @author : wangyingjie
  5. * @brief : None
  6. * @attention : None
  7. * @date : 2025/5/23
  8. ******************************************************************************
  9. */
  10. #include "heading_diff_ctrl_c.h"
  11. //// 小船控制结构体
  12. //typedef struct
  13. //{
  14. // studio_pid heading_pid; // 方位角PID控制器
  15. // studio_point_c target; // 目标点
  16. // double base_throttle; // 基础油门
  17. // double left_throttle; // 左侧油门
  18. // double right_throttle; // 右侧油门
  19. //} diff_ctrl;
  20. // 初始化小船控制器
  21. void init_diff_ctrl(diff_ctrl *controller,
  22. const studio_point_c *target,
  23. double base_throttle, // 输入范围0~1.0
  24. double Kp,
  25. double Ki,
  26. double Kd)
  27. {
  28. init_pid(&controller->heading_pid, 0, 0, Kp, Ki, Kd, 1.0, 0.3);
  29. controller->target = *target;
  30. controller->base_throttle = base_throttle;
  31. controller->left_throttle = base_throttle;
  32. controller->right_throttle = base_throttle;
  33. }
  34. void reset_diff_ctrl_goal(diff_ctrl* controller, const studio_point_c* target)
  35. {
  36. controller->target = *target;
  37. set_goal(&controller->heading_pid, 0);
  38. }
  39. // 正确计算最短路径误差(返回-180~180°)
  40. double calculate_heading_error(double target_deg, double current_deg)
  41. {
  42. double error = target_deg - current_deg;
  43. error = fmod(error + 360.0, 360.0); // 转0~360°
  44. if (error > 180.0)
  45. {
  46. error -= 360.0;
  47. }
  48. return error;
  49. }
  50. double update_boat(diff_ctrl *controller, const studio_point_c *current_pos, double current_heading_deg)
  51. {
  52. // 1. 计算目标方位角(确保函数正确)
  53. const double target_deg = azimuth_angle_gcs_c(current_pos, &controller->target);
  54. // 2. 计算最短路径误差
  55. double error = calculate_heading_error(target_deg, current_heading_deg);
  56. double steer = 0.0;
  57. // 3. PID控制
  58. if (fabs(error) > 1.0) // 仅当误差超过1度时进行纠偏
  59. {
  60. set_goal(&controller->heading_pid, 0);
  61. steer = compute_pid(&controller->heading_pid, error);
  62. }
  63. else
  64. {
  65. }
  66. // 4. 差速控制(关键修正)
  67. controller->left_throttle = controller->base_throttle - steer;
  68. controller->right_throttle = controller->base_throttle + steer;
  69. // 5. 限幅保护
  70. controller->left_throttle = fmax(0.0, fmin(1.0, controller->left_throttle));
  71. controller->right_throttle = fmax(0.0, fmin(1.0, controller->right_throttle));
  72. return distance_squared_gcs_c(current_pos, &controller->target);
  73. }
  74. void simulate_movement(studio_point_c *current_pos, double *current_heading, double left_throttle, double right_throttle)
  75. {
  76. const double dt = 0.1; // 时间间隔(秒)
  77. const double max_speed = 2; // 最大速度(米/秒)
  78. const double turn_rate = 40; // 转向速率(度/秒 per 差速百分比)
  79. // 保存原始位置用于计算位移
  80. const studio_point_c original_pos = *current_pos;
  81. // 1. 计算航向变化 ---------------------------------------------
  82. double steer_diff = left_throttle - right_throttle;
  83. *current_heading += turn_rate * steer_diff * dt;
  84. *current_heading = fmod(*current_heading + 360.0, 360.0);
  85. // 2. 计算位移量(米)------------------------------------------
  86. double avg_throttle = (left_throttle + right_throttle) / 2.0;
  87. double speed = max_speed * avg_throttle;
  88. // 将航向角转换为弧度
  89. double radian = *current_heading * AO_M_PI / 180.0;
  90. // 计算东向和北向位移(单位:米)
  91. const double delta_east = speed * sin(radian) * dt; // 东向位移(+东/-西)
  92. const double delta_north = speed * cos(radian) * dt; // 北向位移(+北/-南)
  93. // 3. 通过投影转换更新位置 -------------------------------------
  94. *current_pos = lonlat_move_by(&original_pos, delta_east, delta_north);
  95. }