Advertisement
errypuu

PID Line Follower Pololu3pi

May 12th, 2014
230
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.07 KB | None | 0 0
  1. /*
  2.  * PID3piLineFollower - demo code for the Pololu 3pi Robot
  3.  *
  4.  * This code will follow a black line on a white background, using a
  5.  * PID-based algorithm.
  6.  *
  7.  * http://www.pololu.com/docs/0J21
  8.  * http://www.pololu.com
  9.  * http://forum.pololu.com
  10.  *
  11.  */
  12.  
  13. // The following libraries will be needed by this demo
  14. #include <Pololu3pi.h>
  15. #include <PololuQTRSensors.h>
  16. #include <OrangutanMotors.h>
  17. #include <OrangutanAnalog.h>
  18. #include <OrangutanLEDs.h>
  19. #include <OrangutanLCD.h>
  20. #include <OrangutanPushbuttons.h>
  21. #include <OrangutanBuzzer.h>
  22.  
  23. Pololu3pi robot;
  24. unsigned int sensors[5]; // an array to hold sensor values
  25. unsigned int last_proportional = 0;
  26. long integral = 0;
  27.  
  28.  
  29. // This include file allows data to be stored in program space.  The
  30. // ATmega168 has 16k of program space compared to 1k of RAM, so large
  31. // pieces of static data should be stored in program space.
  32. #include <avr/pgmspace.h>
  33.  
  34. // Introductory messages.  The "PROGMEM" identifier causes the data to
  35. // go into program space.
  36. const char welcome_line1[] PROGMEM = " Pololu";
  37. const char welcome_line2[] PROGMEM = "3\xf7 Robot";
  38. const char demo_name_line1[] PROGMEM = "PID Line";
  39. const char demo_name_line2[] PROGMEM = "follower";
  40.  
  41. // A couple of simple tunes, stored in program space.
  42. const char welcome[] PROGMEM = ">g32>>c32";
  43. const char go[] PROGMEM = "L16 cdegreg4";
  44.  
  45. // Data for generating the characters used in load_custom_characters
  46. // and display_readings.  By reading levels[] starting at various
  47. // offsets, we can generate all of the 7 extra characters needed for a
  48. // bargraph.  This is also stored in program space.
  49. const char levels[] PROGMEM = {
  50.   0b00000,
  51.   0b00000,
  52.   0b00000,
  53.   0b00000,
  54.   0b00000,
  55.   0b00000,
  56.   0b00000,
  57.   0b11111,
  58.   0b11111,
  59.   0b11111,
  60.   0b11111,
  61.   0b11111,
  62.   0b11111,
  63.   0b11111
  64. };
  65.  
  66. // This function loads custom characters into the LCD.  Up to 8
  67. // characters can be loaded; we use them for 7 levels of a bar graph.
  68. void load_custom_characters()
  69. {
  70.   OrangutanLCD::loadCustomCharacter(levels + 0, 0); // no offset, e.g. one bar
  71.   OrangutanLCD::loadCustomCharacter(levels + 1, 1); // two bars
  72.   OrangutanLCD::loadCustomCharacter(levels + 2, 2); // etc...
  73.   OrangutanLCD::loadCustomCharacter(levels + 3, 3);
  74.   OrangutanLCD::loadCustomCharacter(levels + 4, 4);
  75.   OrangutanLCD::loadCustomCharacter(levels + 5, 5);
  76.   OrangutanLCD::loadCustomCharacter(levels + 6, 6);
  77.   OrangutanLCD::clear(); // the LCD must be cleared for the characters to take effect
  78. }
  79.  
  80. // This function displays the sensor readings using a bar graph.
  81. void display_readings(const unsigned int *calibrated_values)
  82. {
  83.   unsigned char i;
  84.  
  85.   for (i=0;i<5;i++) {
  86.     // Initialize the array of characters that we will use for the
  87.     // graph.  Using the space, an extra copy of the one-bar
  88.     // character, and character 255 (a full black box), we get 10
  89.     // characters in the array.
  90.     const char display_characters[10] = { ' ', 0, 0, 1, 2, 3, 4, 5, 6, 255 };
  91.  
  92.     // The variable c will have values from 0 to 9, since
  93.     // calibrated values are in the range of 0 to 1000, and
  94.     // 1000/101 is 9 with integer math.
  95.     char c = display_characters[calibrated_values[i] / 101];
  96.  
  97.     // Display the bar graph character.
  98.     OrangutanLCD::print(c);
  99.   }
  100. }
  101.  
  102. // Initializes the 3pi, displays a welcome message, calibrates, and
  103. // plays the initial music.  This function is automatically called
  104. // by the Arduino framework at the start of program execution.
  105. void setup()
  106. {
  107.   unsigned int counter; // used as a simple timer
  108.  
  109.   // This must be called at the beginning of 3pi code, to set up the
  110.   // sensors.  We use a value of 2000 for the timeout, which
  111.   // corresponds to 2000*0.4 us = 0.8 ms on our 20 MHz processor.
  112.   robot.init(2000);
  113.  
  114.   load_custom_characters(); // load the custom characters
  115.  
  116.   // Play welcome music and display a message
  117.   OrangutanLCD::printFromProgramSpace(welcome_line1);
  118.   OrangutanLCD::gotoXY(0, 1);
  119.   OrangutanLCD::printFromProgramSpace(welcome_line2);
  120.   OrangutanBuzzer::playFromProgramSpace(welcome);
  121.   delay(1000);
  122.  
  123.   OrangutanLCD::clear();
  124.   OrangutanLCD::printFromProgramSpace(demo_name_line1);
  125.   OrangutanLCD::gotoXY(0, 1);
  126.   OrangutanLCD::printFromProgramSpace(demo_name_line2);
  127.   delay(1000);
  128.  
  129.   // Display battery voltage and wait for button press
  130.   while (!OrangutanPushbuttons::isPressed(BUTTON_B))
  131.   {
  132.     int bat = OrangutanAnalog::readBatteryMillivolts();
  133.  
  134.     OrangutanLCD::clear();
  135.     OrangutanLCD::print(bat);
  136.     OrangutanLCD::print("mV");
  137.     OrangutanLCD::gotoXY(0, 1);
  138.     OrangutanLCD::print("Press B");
  139.  
  140.     delay(100);
  141.   }
  142.  
  143.   // Always wait for the button to be released so that 3pi doesn't
  144.   // start moving until your hand is away from it.
  145.   OrangutanPushbuttons::waitForRelease(BUTTON_B);
  146.   delay(1000);
  147.  
  148.   // Auto-calibration: turn right and left while calibrating the
  149.   // sensors.
  150.   for (counter=0; counter<80; counter++)
  151.   {
  152.     if (counter < 20 || counter >= 60)
  153.       OrangutanMotors::setSpeeds(40, -40);
  154.     else
  155.       OrangutanMotors::setSpeeds(-40, 40);
  156.  
  157.     // This function records a set of sensor readings and keeps
  158.     // track of the minimum and maximum values encountered.  The
  159.     // IR_EMITTERS_ON argument means that the IR LEDs will be
  160.     // turned on during the reading, which is usually what you
  161.     // want.
  162.     robot.calibrateLineSensors(IR_EMITTERS_ON);
  163.  
  164.     // Since our counter runs to 80, the total delay will be
  165.     // 80*20 = 1600 ms.
  166.     delay(20);
  167.   }
  168.   OrangutanMotors::setSpeeds(0, 0);
  169.  
  170.   // Display calibrated values as a bar graph.
  171.   while (!OrangutanPushbuttons::isPressed(BUTTON_B))
  172.   {
  173.     // Read the sensor values and get the position measurement.
  174.     unsigned int position = robot.readLine(sensors, IR_EMITTERS_ON);
  175.  
  176.     // Display the position measurement, which will go from 0
  177.     // (when the leftmost sensor is over the line) to 4000 (when
  178.     // the rightmost sensor is over the line) on the 3pi, along
  179.     // with a bar graph of the sensor readings.  This allows you
  180.     // to make sure the robot is ready to go.
  181.     OrangutanLCD::clear();
  182.     OrangutanLCD::print(position);
  183.     OrangutanLCD::gotoXY(0, 1);
  184.     display_readings(sensors);
  185.  
  186.     delay(100);
  187.   }
  188.   OrangutanPushbuttons::waitForRelease(BUTTON_B);
  189.  
  190.   OrangutanLCD::clear();
  191.  
  192.   OrangutanLCD::print("Go!");      
  193.  
  194.   // Play music and wait for it to finish before we start driving.
  195.   OrangutanBuzzer::playFromProgramSpace(go);
  196.   while(OrangutanBuzzer::isPlaying());
  197. }
  198.  
  199. // The main function.  This function is repeatedly called by
  200. // the Arduino framework.
  201. void loop()
  202. {
  203.   // Get the position of the line.  Note that we *must* provide
  204.   // the "sensors" argument to read_line() here, even though we
  205.   // are not interested in the individual sensor readings.
  206.   unsigned int position = robot.readLine(sensors, IR_EMITTERS_ON);
  207.  
  208.   // The "proportional" term should be 0 when we are on the line.
  209.   int proportional = (int)position - 2000;
  210.  
  211.   // Compute the derivative (change) and integral (sum) of the
  212.   // position.
  213.   int derivative = proportional - last_proportional;
  214.   integral += proportional;
  215.  
  216.   // Remember the last position.
  217.   last_proportional = proportional;
  218.  
  219.   // Compute the difference between the two motor power settings,
  220.   // m1 - m2.  If this is a positive number the robot will turn
  221.   // to the right.  If it is a negative number, the robot will
  222.   // turn to the left, and the magnitude of the number determines
  223.   // the sharpness of the turn.  You can adjust the constants by which
  224.   // the proportional, integral, and derivative terms are multiplied to
  225.   // improve performance.
  226.   int power_difference = proportional/20 + integral/10000 + derivative*3/2;
  227.  
  228.   // Compute the actual motor settings.  We never set either motor
  229.   // to a negative value.
  230.   const int maximum = 60;
  231.   if (power_difference > maximum)
  232.     power_difference = maximum;
  233.   if (power_difference < -maximum)
  234.     power_difference = -maximum;
  235.  
  236.   if (power_difference < 0)
  237.     OrangutanMotors::setSpeeds(maximum + power_difference, maximum);
  238.   else
  239.     OrangutanMotors::setSpeeds(maximum, maximum - power_difference);
  240. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement