BALA2.ino 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. Description: BALA2 stand and run in balance.
  3. Note: click the device power button and Long press button B will setup calibration mode.
  4. at calibration mode Press the A/C key to increase or decrease the correction value.
  5. When it is adjusted to a satisfactory value, press the B key to save the parameter.
  6. */
  7. #define M5STACK_MPU6886
  8. #include <M5Stack.h>
  9. #include "freertos/FreeRTOS.h"
  10. #include "imu_filter.h"
  11. #include "MadgwickAHRS.h"
  12. #include "bala.h"
  13. #include "pid.h"
  14. #include "calibration.h"
  15. extern uint8_t bala_img[41056];
  16. static void PIDTask(void *arg);
  17. static void draw_waveform();
  18. static float angle_point = -1.5;
  19. float kp = 24.0f, ki = 0.0f, kd = 90.0f;
  20. float s_kp = 15.0f, s_ki = 0.075f, s_kd = 0.0f;
  21. bool calibration_mode = false;
  22. Bala bala;
  23. PID pid(angle_point, kp, ki, kd);
  24. PID speed_pid(0, s_kp, s_ki, s_kd);
  25. // the setup routine runs once when M5Stack starts up
  26. void setup(){
  27. // Initialize the M5Stack object
  28. M5.begin(true, false, false, false);
  29. Serial.begin(115200);
  30. M5.IMU.Init();
  31. int16_t x_offset, y_offset, z_offset;
  32. float angle_center;
  33. calibrationInit();
  34. if (M5.BtnB.isPressed()) {
  35. calibrationGryo();
  36. calibration_mode = true;
  37. }
  38. calibrationGet(&x_offset, &y_offset, &z_offset, &angle_center);
  39. Serial.printf("x: %d, y: %d, z:%d, angle: %.2f", x_offset, y_offset, z_offset, angle_center);
  40. angle_point = angle_center;
  41. pid.SetPoint(angle_point);
  42. SemaphoreHandle_t i2c_mutex;;
  43. i2c_mutex = xSemaphoreCreateMutex();
  44. bala.SetMutex(&i2c_mutex);
  45. ImuTaskStart(x_offset, y_offset, z_offset, &i2c_mutex);
  46. xTaskCreatePinnedToCore(PIDTask, "pid_task", 4 * 1024, NULL, 4, NULL, 1);
  47. M5.Lcd.drawJpg(bala_img, 41056);
  48. if (calibration_mode) {
  49. M5.Lcd.setCursor(0, 0);
  50. M5.Lcd.printf("calibration mode");
  51. }
  52. }
  53. // the loop routine runs over and over again forever
  54. void loop() {
  55. static uint32_t next_show_time = 0;
  56. vTaskDelay(pdMS_TO_TICKS(5));
  57. if(millis() > next_show_time) {
  58. draw_waveform();
  59. next_show_time = millis() + 10;
  60. }
  61. M5.update();
  62. if (M5.BtnA.wasPressed()) {
  63. angle_point += 0.25;
  64. pid.SetPoint(angle_point);
  65. }
  66. if (M5.BtnB.wasPressed()) {
  67. if (calibration_mode) {
  68. calibrationSaveCenterAngle(angle_point);
  69. }
  70. }
  71. if (M5.BtnC.wasPressed()) {
  72. angle_point -= 0.25;
  73. pid.SetPoint(angle_point);
  74. }
  75. }
  76. static void PIDTask(void *arg) {
  77. float bala_angle;
  78. float motor_speed = 0;
  79. int16_t pwm_speed;
  80. int16_t pwm_output;
  81. int16_t pwm_angle;
  82. int32_t encoder = 0;
  83. int32_t last_encoder = 0;
  84. uint32_t last_ticks = 0;
  85. pid.SetOutputLimits(1023, -1023);
  86. pid.SetDirection(-1);
  87. speed_pid.SetIntegralLimits(40, -40);
  88. speed_pid.SetOutputLimits(1023, -1023);
  89. speed_pid.SetDirection(1);
  90. for(;;) {
  91. vTaskDelayUntil(&last_ticks, pdMS_TO_TICKS(5));
  92. // in imu task update, update freq is 200HZ
  93. bala_angle = getAngle();
  94. // Get motor encoder value
  95. bala.UpdateEncoder();
  96. encoder = bala.wheel_left_encoder + bala.wheel_right_encoder;
  97. // motor_speed filter
  98. motor_speed = 0.8 * motor_speed + 0.2 * (encoder - last_encoder);
  99. last_encoder = encoder;
  100. if(fabs(bala_angle) < 70) {
  101. pwm_angle = (int16_t)pid.Update(bala_angle);
  102. pwm_speed = (int16_t)speed_pid.Update(motor_speed);
  103. pwm_output = pwm_speed + pwm_angle;
  104. if(pwm_output > 1023) { pwm_output = 1023; }
  105. if(pwm_output < -1023) { pwm_output = -1023; }
  106. bala.SetSpeed(pwm_output, pwm_output);
  107. } else {
  108. pwm_angle = 0;
  109. bala.SetSpeed(0, 0);
  110. bala.SetEncoder(0, 0);
  111. speed_pid.SetIntegral(0);
  112. }
  113. }
  114. }
  115. static void draw_waveform() {
  116. #define MAX_LEN 120
  117. #define X_OFFSET 100
  118. #define Y_OFFSET 95
  119. #define X_SCALE 3
  120. static int16_t val_buf[MAX_LEN] = {0};
  121. static int16_t pt = MAX_LEN - 1;
  122. val_buf[pt] = constrain((int16_t)(getAngle() * X_SCALE), -50, 50);
  123. if (--pt < 0) {
  124. pt = MAX_LEN - 1;
  125. }
  126. for (int i = 1; i < (MAX_LEN); i++) {
  127. uint16_t now_pt = (pt + i) % (MAX_LEN);
  128. M5.Lcd.drawLine(i + X_OFFSET, val_buf[(now_pt + 1) % MAX_LEN] + Y_OFFSET, i + 1 + X_OFFSET, val_buf[(now_pt + 2) % MAX_LEN] + Y_OFFSET, TFT_BLACK);
  129. if (i < MAX_LEN - 1) {
  130. M5.Lcd.drawLine(i + X_OFFSET, val_buf[now_pt] + Y_OFFSET, i + 1 + X_OFFSET, val_buf[(now_pt + 1) % MAX_LEN] + Y_OFFSET, TFT_GREEN);
  131. }
  132. }
  133. }