Advertisement
Guest User

Untitled

a guest
Apr 27th, 2013
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.50 KB | None | 0 0
  1. /* This code is going to be used to control the line following and autobalancing portion
  2. of our robot.*/
  3.  
  4. //needed for I2C protocol
  5. #include "Wire.h"
  6.  
  7. //These next three libraries are all open source and specific to our IMU, motor shield, and IR
  8. #include "I2Cdev.h"
  9. #include "MPU6050.h"
  10. #include "DualMC33926MotorShield.h"
  11. #include <QTRSensors.h>
  12.  
  13. //Basic math library
  14. #include <math.h>
  15.  
  16. /*Define all of the variables for the program*/
  17. //Create variables of type MPU6050 (IMU) and Dual...(motor shield)
  18. MPU6050 accelgyro;
  19. DualMC33926MotorShield md;
  20.  
  21. //define the ultrasonic pins and variables
  22. #define echoPin 11 // Echo Pin
  23. #define trigPin 6// Trigger Pin
  24. double duration;
  25. double USerror;
  26. double USintegralError = 0;
  27. double USsetpoint;
  28. double USduration;
  29. double UScorrection;
  30. float Kp1;
  31. float USkp;
  32. float USki;
  33.  
  34. //timing for the program
  35. float dt = 0.0001;
  36. float time = dt/1000;
  37.  
  38. //establish the variables that the IMU will be assigning
  39. int16_t ax, ay, az;
  40. int16_t gx, gy, gz;
  41.  
  42. //Accelerometer variables
  43. float AccY_Offset = -270;
  44. double AccY = 0;//Acceleration after offset is taken into account
  45. double gravity;//Acceleration due to gravity
  46. double tiltAcc;//Tilt angle found by accelerometer
  47.  
  48. //Gyroscope Variables
  49. float GyroX_Offset = -140;
  50. double tiltRate;//Gyro reading after taking into account the offset
  51. double previoustiltRate = 0.0;//Used for the numeric integration to find the angle
  52.  
  53. //filter
  54. float alpha = 0.99;//Constant used for the high and low(1-alpha) pass filters
  55. double angle = 0;//Need an initial angle to start the program
  56.  
  57. //The gain values for the program
  58. float kp = 0;
  59. float ki = 0;
  60. float kd = 0;
  61. float mid;//Desired setpoint
  62. float setpoint;//Setpoint that can change dynamically throughout the program
  63.  
  64. //range of acceptable degrees that robot can span without touching the ground
  65. int range = 80;
  66.  
  67. //define all of the error variables
  68. double error;
  69. double previousError = 0;
  70. double pastError = 0.0;
  71. double derivError = 0;
  72.  
  73. //line following sensor declaration
  74. #define NUM_SENSORS   3  // number of sensors used
  75. #define TIMEOUT       2500  // waits for 2500 us for sensor outputs to go low
  76. #define EMITTER_PIN   2     // emitter is controlled by digital pin 2
  77.  
  78. // sensors 0 through 2 are connected to digital pins 2,3 and 5
  79. QTRSensorsRC qtrrc((unsigned char[]) {2,3,5},
  80.   NUM_SENSORS, TIMEOUT, EMITTER_PIN);
  81. unsigned int sensorValues[NUM_SENSORS];
  82. float midIR;
  83.  
  84. //define motor variables
  85. int correction;
  86. int power = 400;
  87.  
  88. //define on the fly PID tuning variables
  89. int a;
  90. int array[] = {0,0};
  91. int counter;
  92.  
  93.  
  94. //StopIfFault() halts the motors if an error occurs, such as too much or too little current draw.
  95. void stopIfFault()
  96. {
  97.   //md.getFault() is a built in function of the motor shield
  98.   if (md.getFault())
  99.   {
  100.     Serial.println("fault");//display the fault message to the Serial monitor
  101.     md.setM2Speed(0);//set the speed of motor 2 to zero
  102.     md.setM1Speed(0);//set the speed of motor 1 to zero
  103.     while(1);//stop the program indefinitely to prevent any damage to electronics
  104.   }
  105. }
  106.  
  107. /*This getAngle() function takes in the IMU data and performs the calculations necessary to obtain
  108. reliable, accurate tilt angle measurements. The angle is calculated using both the accelerometer and
  109. the gyroscope separately and then a high pass filter is applied to the gyro, a low pass to the
  110. accelerometer, and the results are added. This is a simple complimentary filter that was inspired
  111. by a presentation by MIT entitled "The Balance Filter"*/
  112. double getAngle(){
  113.     // read raw accel/gyro measurements from device and assign to respective variables
  114.     accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  115.    
  116.     // calculate tilt angle from accelerometer
  117.     AccY = (ay - AccY_Offset);//Take into account the accelerometer's offset
  118.     gravity = sqrt((square(az) + square(AccY)));//
  119.     tiltAcc = asin(AccY/gravity)*180/PI;//use the acceleration components to find tilt and convert to degrees
  120.    
  121.     // calculate tilt angle from gyroscope
  122.     tiltRate = (gx - GyroX_Offset)*90/(131*250);//account for offset and span
  123.     //previoustiltRate = tiltRate;
  124.     angle = alpha*(angle + dt*(previoustiltRate + tiltRate)) + (1-alpha)*(tiltAcc);//complimentary filter 0.005 instead of dt
  125.     previoustiltRate = tiltRate;
  126.  
  127.     return angle;
  128. }
  129.  
  130. /*This function reads in the IMU data and finds the motor values needed to balance*/
  131. int balance() {
  132.     //Balance PID values used for tuning
  133.     kp = 550;
  134.     ki = 350;
  135.     kd = 100;
  136.     mid = -0.85;//Desired setpoint
  137.    
  138.   //Retrieve the angle and find the errors for the PID algorithm  
  139.   angle = getAngle();//call the function used to find the filtered IMU tilt angle
  140.   //Serial.println(angle);//print the angle to the Serial monitor
  141.   error = angle - setpoint;//calculate the error
  142.   error = (error/range);//normalize the error with respect to the range
  143.   pastError = 0.9*(pastError + error);//Integral error with a decay factor to expel accumulated errors
  144.   derivError = (error - previousError);//Derivative error proportional to the change in error
  145.   previousError = error;//reassign the current error as the previous error for the next loop
  146.   correction = (power/100)*(kp*error + ki*pastError + kd*derivError);//The sum of the gain values and errors
  147.  
  148.  
  149.   /*This portion of the code will adjust the setpoint depending on how far the robot is leaning. If the robot is
  150.   leaning far forward, the setpoint is moved further back to increase the observed error and therefore the response.*/
  151.   if (angle > mid + 0.750)//If the angle is much greater than the setpoint, move the setpoint back
  152.   {
  153.     setpoint = mid - 0.25;
  154.   }
  155.   else if (correction < mid - 0.750)//If the angle is much smaller than the setpoint, move the setpoint forward
  156.   {
  157.     setpoint = mid + 0.25;
  158.   }
  159.   else//If the angle is within an acceptable range, maintain the same setpoint
  160.   {
  161.     setpoint = mid;
  162.   }
  163.  
  164.   return correction; //use the correction value in the line following portion
  165. }
  166.  
  167. void lineFollow(double correction){
  168.     //These should be replaced with the readings from the outer sensors and 2500 for the tape
  169.     //midIR = (qtrrc.calibratedMinimumOn[2]+qtrrc.calibratedMaximumOn[0])/2 ;//Desired setpoint
  170.     int alpha = 100;
  171.     //read in the raw IR data
  172.     qtrrc.read(sensorValues);
  173.         correction = -correction;
  174.     //ZigZag
  175.     if ((sensorValues[0] <= 1250) && (sensorValues[2] <= 1250))
  176.     {
  177.          md.setM2Speed(correction);
  178.          md.setM1Speed(correction);
  179.          stopIfFault();
  180.                  //Serial.println("forward");
  181.     }
  182.     else if ((sensorValues[0] > 1250)&&(sensorValues[2] < 1250))
  183.     {
  184.          md.setM2Speed(correction+alpha);  
  185.          md.setM1Speed(correction-alpha);
  186.          stopIfFault();
  187.                  //Serial.println("Right");
  188.     }
  189.     else if ((sensorValues[2] > 1250)&&(sensorValues[0] < 1250))
  190.     {
  191.          md.setM2Speed(correction-alpha);  
  192.          md.setM1Speed(correction+alpha);
  193.          stopIfFault();
  194.                  // Serial.println("Left");
  195.     }
  196.         else
  197.         {
  198.           md.setM2Speed(correction);  
  199.           md.setM1Speed(correction);
  200.           stopIfFault();
  201.          // Serial.println("Shit");
  202.         }
  203. }
  204.  
  205. long ultrasonicDuration(){
  206.    //pulse the ultrasonic to detect the time it takes to reflect. Use this time as the error for balancing
  207.   duration = 0;
  208.   for(int i = 0; i <10; i++)
  209.   {
  210.     digitalWrite(trigPin, LOW);
  211.     delayMicroseconds(2);
  212.  
  213.     digitalWrite(trigPin, HIGH);
  214.     delayMicroseconds(10);
  215.    
  216.     digitalWrite(trigPin, LOW);
  217.     duration = pulseIn(echoPin, HIGH)+duration;
  218.   }
  219.   //if ((duration/10) > 750)
  220.   //{
  221.   //  return 165;//return the setpoint so that the motors don't go crazy
  222.  // }
  223.  // else
  224.  // {
  225.     return duration/10;
  226. //  }
  227. }
  228.  
  229. void ultrasonicBalanceZigZag(){
  230.   USduration = ultrasonicDuration();
  231.   USsetpoint = 150;
  232.   USerror = USduration - USsetpoint;
  233.   Kp1 = 230;
  234.   if (USduration == -1)//bad reading
  235.   {
  236.       md.setM1Speed(0);
  237.       md.setM2Speed(0);
  238.  
  239.   }
  240.   else if(USduration > USsetpoint+20)
  241.   {
  242.     md.setM1Speed(-Kp1);
  243.     md.setM2Speed(-Kp1);
  244.   }
  245.   else if(USduration < USsetpoint+20)
  246.   {
  247.     md.setM1Speed(Kp1);
  248.     md.setM2Speed(Kp1);
  249.   }
  250.  
  251.   Serial.println(USduration);
  252.  
  253. }
  254. double ultrasonicBalancePID(){
  255.   USduration = ultrasonicDuration();
  256.   USsetpoint = 185;
  257.   USerror = USduration - USsetpoint;
  258.   USkp = 2.8;
  259.   USki = 0.015;
  260.   USintegralError = (USerror + USintegralError)*0.9;
  261.   correction = USkp*USerror + USki*USintegralError;
  262.   md.setM1Speed(-correction);
  263.   md.setM2Speed(-correction);
  264.   //Serial.println(USduration);
  265.   Serial.println(USduration);
  266.   return correction;
  267. }
  268.  
  269. void setup() {
  270.     // join I2C bus
  271.     Wire.begin();
  272.  
  273.     // initialize serial communication
  274.     Serial.begin(115200);
  275.  
  276.     // initialize device
  277.     accelgyro.initialize();
  278.  
  279.     //initialize motor shield
  280.     md.init();
  281.    
  282.     //initialize ultrasonic
  283.     pinMode(trigPin, OUTPUT);
  284.     pinMode(echoPin, INPUT);
  285.  
  286. }
  287.  
  288. void loop(){
  289.     /*the logic here is to find the motor power needed to stay balanced (say 100 to each motor).
  290.     then send this value to the lineFollow() program which will determine where on the line the robot
  291.     is. Then the motor commands will be shifted (120 to left and 80 to right for example) so that
  292.     the robot will zig zag on the line and have the same net balancing amount. When I run this code however,
  293.     the robot goes crazy after balancing for a small moment.*/
  294.     //correction = balance();
  295.     //lineFollow(correction);
  296.         //correction = ultrasonicBalancePID();
  297.         //lineFollow(correction);
  298.         ultrasonicBalanceZigZag();
  299.        
  300. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement