Advertisement
Guest User

Untitled

a guest
Mar 18th, 2019
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 13.45 KB | None | 0 0
  1. #include <Wire.h>
  2. #include <Servo.h>
  3. #include "Sensor_9DOF.h"
  4. #include "Button.h"
  5. #include "config.h"
  6.  
  7. /**************************************************************************/
  8. // Globals
  9. Sensor9DOF Sensor_9DOF = Sensor9DOF();
  10. Servo Fan1;
  11. Servo Fan2;
  12.  
  13. Button button1;
  14. Button button2;
  15.  
  16. // Important measured values for control
  17. float R             = 0.0;
  18. float Phi_deg       = 0.0;
  19. float error_int_deg = 0.0;
  20. float p_deg_s       = 0.0;
  21. float p_deg_s_filt  = 0.0;
  22. float time_s        = 0.0;
  23. unsigned long update_time;
  24. unsigned long time_delay;
  25. float cmd_PD = 0.0;
  26.  
  27. int controlled_fan_PWM = FAN_OFF;
  28. int controlled_fan2_PWM = FAN_OFF;
  29.  
  30. // Limit switch variables
  31. bool manual_calibration = false;   // <<<<<<<<< Turn to true to set up calibration with fans off (on tutors instruction)
  32. bool limits_calibrated = false;
  33.  
  34.  
  35. /**************************************************************************/
  36. /* Some notes:
  37.  * 1) The sensor data cannot be updated within the timer function as
  38.  *    the timer blocks interrupts which are used to handle the IC2
  39.  *    connection with the sensor board. Here the "quick an dirty" solution
  40.  *    to update the sensor data in the main loop has been choosen.
  41.  * 2) The roll angle is integrated from the roll rate with a simple
  42.  *    trapezodial rule
  43.  */
  44. /**************************************************************************/
  45.  
  46. //==========================================================================================//
  47. //                  >>>>>>>>>>>>> STUDENTS: Start here <<<<<<<<<<<<<
  48.  
  49. /*
  50.  
  51. Operation instructions:
  52.  
  53. Part A:
  54. 1)  Plug the arduino in (Do not turn on the power supplies)
  55. 2)  Pick gains and control function
  56. 3)  Check with tutor that your gains and control function are adequate
  57. 4)  Set R = 0 in the setput_output function
  58. 5)  Press the arrow in the top left corner to compile and load the program
  59. 6)  Manually press the limit switches
  60. 7)  Observe how the values change printed to the console as you manually move the mount
  61. 8)  Send a character from the console to the arduino to kill the program
  62. 9)  Alter gains and start again
  63.  
  64. Part B:
  65. 1)  Make sure the program is in the killed state from part A
  66. 2)  Depending on the tutors’ instructions set manual_calibration to true or false
  67. 3)  Set R to the step function in the setput_output function
  68. 4)  Check with tutor that your gains and control function are adequate
  69. 5)  Get tutor to turn the power supplies on
  70. 6)  Press the arrow in the top left corner to compile and load the program
  71. 7)  If manual_calibration = true manually press the limit switches the get away from the mount
  72.     If manual_calibration = false just wait
  73. 8)  DO NOT GO NEAR THE RIG THE SECOND THE FANS START
  74.       If you want to kill the program at any time send a character from the console to the arduino
  75. 9)  Observe the behavior of your gains
  76. 10) Send a character from the console to the arduino to kill the program
  77. 11) Alter gains and start again
  78.  
  79. */
  80.  
  81. // Change (or create) your parameters here
  82. // Please keep Kp < 2.5 , Kd < 0.7*Kp, Ki < Kp
  83. float Kp          = 2.2;
  84. float Kd          = 0.6*Kp;
  85. float Ki          = 0.3*Kp;
  86.  
  87. float PID_control ()
  88. {
  89.    float control;
  90.    //====================================================//
  91.  
  92.   /*
  93.    *start to work here and create a PD controller
  94.    *cmd_PD is the angle command of the servo in degrees
  95.    *You can use the following:
  96.    * - Kp
  97.    * - Kd
  98.    * - Ki
  99.    * - R             (reference input)
  100.    * - Phi_deg       (roll angle)
  101.    * - p_deg_s_filt  (filtered roll rate)
  102.    * - error_int_deg (integrated roll angle error)
  103.    */  
  104.  
  105.   control = Kp*(R-Phi_deg)+Kd*(0-p_deg_s_filt)+Ki*(error_int_deg);
  106.  
  107.   //====================================================//  
  108.   return control;
  109. }
  110.  
  111. void setpoint_output()
  112. {
  113.   // Use R = 0 for part a of the lab when the fans are not turned on
  114.   // Comment out otherwise
  115.   //R = 0;
  116.  
  117.   // Use R = -15 <--> 15 for the rest of the lab
  118.   // This changes the setpoint every 15 seconds
  119.   int step_time;
  120.   step_time = 15; //<< time in seconds steps occur
  121.   R = 20.0 - 20.0*((float)((update_time-time_delay)/1000%(2*step_time)/step_time));
  122. }
  123.  
  124. //                  >>>>>>>>>>>>> STUDENTS: end here <<<<<<<<<<<<<
  125. //==========================================================================================//  
  126.  
  127.  
  128. void setup() {
  129.   // Serial init
  130.   Serial.begin(115200);
  131.   Serial.println("#ENEL321 fan control (╯°□°)╯");
  132.   Serial.println("#");
  133.  
  134.   // Fans init
  135.   Fan1.attach(FAN_1_PIN);
  136.   Fan2.attach(FAN_2_PIN);
  137.  
  138.   // Set fans to lower limit (off)
  139.   Fan1.writeMicroseconds(FAN_OFF);
  140.   Fan2.writeMicroseconds(FAN_OFF);
  141.   delay(200);
  142.  
  143.   // Gyro init
  144.   Sensor_9DOF.init();
  145.   Sensor_9DOF.static_calibration();
  146.   Sensor_9DOF.update_gyro_readings();
  147.  
  148.   // Limit switch init
  149.   button1.init_Button(LIMIT_1_PIN, true, 5, false);
  150.   button2.init_Button(LIMIT_2_PIN, true, 5, false);
  151.   Serial.println("#");
  152.   Serial.println("#Starting limit switch calibration:...");
  153.  
  154.   update_time = millis() + DT_MS;
  155. }
  156.  
  157. void loop() {
  158.   bool limit_reached = false;
  159.  
  160.   //update roll rate from sensor
  161.   Sensor_9DOF.update_gyro_readings();
  162.   p_deg_s = Sensor_9DOF.getP()*180.0/PI;
  163.   button1.get_Button_pressed();
  164.   button2.get_Button_pressed();
  165.  
  166.   if (update_time <= millis())
  167.   {
  168.       //update time
  169.       update_time += DT_MS;
  170.       time_s += DT;
  171.    
  172.     // After gyro calibration contiually update the roll
  173.     update_roll();
  174.    
  175.     if(limits_calibrated)
  176.     {
  177.       // Update control loop once the system has calibrated
  178.       update_control(PID_control);
  179.  
  180.       // Print data to the computer
  181.       print_updates();
  182.      
  183.       // Test to see if limit switches have been pressed
  184.       // Will cause program to stop if they have for safety
  185.       if (update_buttons())
  186.       {
  187.         limit_reached = true;
  188.       }
  189.     }
  190.     else
  191.     {
  192.       // At the start of the program go through a calibration procedue
  193.       // to find the angles the switches are pressed
  194.       update_calibration();
  195.     }
  196.    
  197.     // Kill Switch via console commands (and character sent)
  198.     if (Serial.available())
  199.     {
  200.       char c;
  201.       c = Serial.read();
  202.       if (c>0)
  203.       {
  204.         limit_reached = true;
  205.       }
  206.     }
  207.      
  208.   }
  209.  
  210.   delay(1);
  211.  
  212.   // Exit program if limit switches pressed
  213.   if (limit_reached)
  214.   {
  215.     Serial.print("#Kill switch acitvated pressed cutting engines please reset...");
  216.     while(1)
  217.     {
  218.       Fan1.writeMicroseconds(FAN_OFF);
  219.       Fan2.writeMicroseconds(FAN_OFF);
  220.     }
  221.   }
  222. }
  223.  
  224.  
  225. /**************************************************************************/
  226. // Updates the roll angle and other variables for use in control
  227. void update_roll()
  228. {
  229.   static float Phi_deg_pre   = 0.0;
  230.   static float p_deg_s_pre   = 0.0;
  231.   static float moving_average_filter_array[FILTER_SIZE] = {0.0};
  232.   float sum_filter = 0.0;
  233.  
  234.  
  235.   //Integrate roll rate with trapezodial rule
  236.   Phi_deg     = Phi_deg + (p_deg_s + p_deg_s_pre)/2.0*DT;  // << Control variable
  237.   p_deg_s_pre = p_deg_s;
  238.  
  239.   //Integrate roll error with trapezodial rule
  240.   error_int_deg = error_int_deg + ((R - Phi_deg) + (R-Phi_deg_pre))/2.0*DT;  // << Control variable
  241.   Phi_deg_pre = Phi_deg;
  242.  
  243.   if (error_int_deg > ERROR_INT_SATURATION)
  244.   {
  245.     error_int_deg = ERROR_INT_SATURATION;
  246.   }
  247.   else if (error_int_deg < -ERROR_INT_SATURATION)
  248.   {
  249.     error_int_deg = -ERROR_INT_SATURATION;
  250.   }
  251.    
  252.   //update moving average filter for PD control
  253.   //the first entry is the oldest one
  254.   for (int ii=0; ii <FILTER_SIZE-1 ; ii++)
  255.   {
  256.     moving_average_filter_array[ii] = moving_average_filter_array[ii+1];
  257.     sum_filter += moving_average_filter_array[ii];
  258.   }
  259.  
  260.   moving_average_filter_array[FILTER_SIZE-1] = p_deg_s;
  261.   sum_filter += moving_average_filter_array[FILTER_SIZE-1];
  262.  
  263.   p_deg_s_filt = sum_filter / FILTER_SIZE;  // << Control variable
  264. }
  265.  
  266. /**************************************************************************/
  267. // Update the output to the controlled fan based on the input readings
  268. void update_control(float (*control_func)())
  269. {
  270.   static int  controlled_fan_PWM_pre = FAN_OFF;
  271.   static bool first_run = true;
  272.  
  273.   if (first_run)
  274.   {
  275.     time_delay = update_time;
  276.     first_run = false;
  277.   }
  278.  
  279.   // Update the setpoint position
  280.   setpoint_output();
  281.  
  282.   //switch sign to handle integration direction of servos
  283.   cmd_PD = -(*control_func)();
  284.  
  285.   //limit the control output
  286.   if (cmd_PD > CONTROL_LIMIT)
  287.   {
  288.     cmd_PD = CONTROL_LIMIT;
  289.   }
  290.   if (cmd_PD < -CONTROL_LIMIT)
  291.   {
  292.     cmd_PD = -CONTROL_LIMIT;
  293.   }
  294.  
  295.   //convert control output (angle in deg) into PWM signal by using a linear interpolation
  296.   controlled_fan_PWM = (int)(mapping_float(cmd_PD,
  297.                                       -CONTROL_LIMIT,
  298.                                       CONTROL_LIMIT,
  299.                                       FAN_LOW,
  300.                                       FAN_HIGH));
  301.   controlled_fan2_PWM = (int)(mapping_float(-cmd_PD,
  302.                                       -CONTROL_LIMIT,
  303.                                       CONTROL_LIMIT,
  304.                                       FAN_LOW,
  305.                                       FAN_HIGH));
  306.  
  307.   //convert servo angle into PWM signal
  308.   //only update PWM if command has changed
  309.   if (controlled_fan_PWM != controlled_fan_PWM_pre)
  310.   {
  311.     Fan1.writeMicroseconds(controlled_fan_PWM);
  312.     Fan2.writeMicroseconds(controlled_fan2_PWM);
  313.   }
  314.  
  315.   controlled_fan_PWM_pre = controlled_fan_PWM;
  316. }
  317.  
  318.  
  319. /**************************************************************************/
  320. // Limit switch calibration procedure for the system
  321. void update_calibration()
  322. {
  323.   static float limit1_ang = 0.0;
  324.   static float limit2_ang = 0.0;
  325.   static bool limit1_pressed = false;
  326.   static bool limit2_pressed = false;
  327.   static bool enter_delay = false;
  328.   static unsigned long delay_cal = 0;
  329.   bool limit1_press = false;
  330.   bool limit2_press = false;
  331.   static bool first_run = true;
  332.  
  333.   if (first_run)
  334.   {
  335.     time_delay = update_time;
  336.     first_run = false;
  337.   }
  338.  
  339.   // Read buttons
  340.   limit1_press = button1.get_Button_pressed();
  341.   limit2_press = button2.get_Button_pressed();
  342.  
  343.   // Turn on fan 1 slowly to find the first limit switch's position
  344.   if (!limit1_pressed && !limit2_pressed && !manual_calibration)
  345.   {
  346.     int fan_up;
  347.  
  348.     fan_up = FAN_SLOW_TURN + (update_time-time_delay)/30;
  349.     if (fan_up > FAN_HIGH)
  350.     {
  351.       fan_up = FAN_HIGH;
  352.     }
  353.     Fan1.writeMicroseconds(fan_up);
  354.   }
  355.  
  356.     // Turn on fan 2 slowly to find the first limit switch's position
  357.   if (limit1_pressed && !limit2_pressed && !manual_calibration)
  358.   {
  359.     int fan_up;
  360.  
  361.     fan_up = FAN_SLOW_TURN + (update_time-time_delay)/30;
  362.     if (fan_up > FAN_HIGH)
  363.     {
  364.       fan_up = FAN_HIGH;
  365.     }
  366.     Fan2.writeMicroseconds(fan_up);
  367.   }
  368.  
  369.   // If first limit switch has been pressed record the angle
  370.   // and turn the system in the other direction
  371.   if (limit1_press && !limit1_pressed)
  372.   {
  373.     limit1_ang = Phi_deg;
  374.     limit1_pressed = true;
  375.     first_run = true;
  376.     Serial.println("#Limit switch 1 pressed");
  377.     Fan1.writeMicroseconds(FAN_OFF);
  378.    
  379.   }
  380.  
  381.   // If the second limit switch has been pressed record the angle
  382.   // and turn the fans off
  383.   if (limit2_press && !limit2_pressed)
  384.   {
  385.     limit2_ang = Phi_deg;
  386.     limit2_pressed = true;
  387.     Serial.println("#Limit switch 2 pressed");
  388.     Fan2.writeMicroseconds(FAN_OFF);
  389.   }
  390.  
  391.   // If both switches have been pressed set the mid point between the
  392.   // two limit switch positions as the zero point so the setpoint is
  393.   // the maximum position away from the limits
  394.   if(limit1_pressed && limit2_pressed && !delay_cal)
  395.   {
  396.     float diff;
  397.     float temp;
  398.  
  399.     diff = limit1_ang - limit2_ang;
  400.     temp = diff/2;
  401.     Phi_deg = Phi_deg - limit2_ang - temp;
  402.     limit2_ang = -temp;
  403.     limit1_ang = limit2_ang + diff;
  404.  
  405.     enter_delay = true;
  406.     delay_cal = update_time;
  407.     Serial.print("#Calibration complete control starting in ");
  408.     Serial.print(CONTROL_START_DELAY/1000);
  409.     Serial.println(" seconds");
  410.   }
  411.  
  412.   // Delay the system before entering the control loop
  413.   if (enter_delay && ((delay_cal+CONTROL_START_DELAY) < update_time))
  414.   {
  415.     limits_calibrated = true;
  416.     Serial.println("Gains:");
  417.     Serial.println("Kp,Ki,Kd");
  418.     Serial.print(Kp);
  419.     Serial.print(",");
  420.     Serial.print(Ki);
  421.     Serial.print(",");
  422.     Serial.println(Kd);
  423.     Serial.println("Time (s),Setpoint (deg),Phi (deg),Roll rate (deg/s),Error int (deg), PPM_diff");
  424.   }
  425. }
  426.  
  427.  
  428. /**************************************************************************/
  429. // In the control loop test to see if the limit switches have been pressed
  430. bool update_buttons()
  431. {
  432.   bool limit1_press = false;
  433.   bool limit2_press = false;
  434.  
  435.   // Read buttons
  436.   limit1_press = button1.get_Button_pressed();
  437.   limit2_press = button2.get_Button_pressed();
  438.  
  439.   if (limit1_press || limit2_press)
  440.   {
  441.     Fan1.writeMicroseconds(FAN_OFF);
  442.     Fan2.writeMicroseconds(FAN_OFF);
  443.     return true;
  444.   }
  445.   return false;
  446. }
  447.  
  448. /**************************************************************************/
  449. // Print updates for post analysis
  450. void print_updates()
  451. {
  452. //  Serial.print("$>");
  453.   Serial.print(time_s);
  454.   Serial.print(",");
  455.   Serial.print(R);
  456.   Serial.print(",");
  457.   Serial.print(Phi_deg);
  458.   Serial.print(",");
  459.   Serial.print(p_deg_s_filt);
  460.   Serial.print(",");
  461.   Serial.print(error_int_deg);
  462.   Serial.print(",");
  463.   Serial.print(controlled_fan_PWM-controlled_fan2_PWM);
  464.   Serial.println();
  465. }
  466.  
  467. // PS : Please do not code like this... (╯°□°)╯︵ ┻━┻
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement