This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| et:projects:3pi:solutions [2015/11/12 12:22] – kaupo.raid | et:projects:3pi:solutions [2020/07/20 09:00] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 147: | Line 147: | ||
| ==3Pi PID regulaatoriga joonejärgimine== | ==3Pi PID regulaatoriga joonejärgimine== | ||
| <code c> | <code c> | ||
| + | |||
| /* | /* | ||
| * 3pi-linefollower-pid - demo code for the Pololu 3pi Robot | * 3pi-linefollower-pid - demo code for the Pololu 3pi Robot | ||
| - | * | + | |
| * This code will follow a black line on a white background, using a | * This code will follow a black line on a white background, using a | ||
| * PID-based algorithm. | * PID-based algorithm. | ||
| Line 158: | Line 159: | ||
| * | * | ||
| */ | */ | ||
| - | + | ||
| // The 3pi include file must be at the beginning of any program that | // The 3pi include file must be at the beginning of any program that | ||
| // uses the Pololu AVR library and 3pi. | // uses the Pololu AVR library and 3pi. | ||
| #include < | #include < | ||
| - | //#include < | + | |
| // This include file allows data to be stored in program space. | // This include file allows data to be stored in program space. | ||
| // ATmega168 has 16k of program space compared to 1k of RAM, so large | // ATmega168 has 16k of program space compared to 1k of RAM, so large | ||
| // pieces of static data should be stored in program space. | // pieces of static data should be stored in program space. | ||
| #include < | #include < | ||
| - | + | ||
| - | uint8_t pval; | + | |
| - | uint8_t ival; | + | |
| - | uint8_t dval1; | + | |
| - | uint8_t dval2; | + | |
| // Introductory messages. | // Introductory messages. | ||
| // go into program space. | // go into program space. | ||
| Line 178: | Line 175: | ||
| const char demo_name_line1[] PROGMEM = "PID Line"; | const char demo_name_line1[] PROGMEM = "PID Line"; | ||
| const char demo_name_line2[] PROGMEM = " | const char demo_name_line2[] PROGMEM = " | ||
| - | + | ||
| // A couple of simple tunes, stored in program space. | // A couple of simple tunes, stored in program space. | ||
| const char welcome[] PROGMEM = "> | const char welcome[] PROGMEM = "> | ||
| const char go[] PROGMEM = "L16 cdegreg4"; | const char go[] PROGMEM = "L16 cdegreg4"; | ||
| - | + | ||
| // Data for generating the characters used in load_custom_characters | // Data for generating the characters used in load_custom_characters | ||
| // and display_readings. | // and display_readings. | ||
| // offsets, we can generate all of the 7 extra characters needed for a | // offsets, we can generate all of the 7 extra characters needed for a | ||
| // bargraph. | // bargraph. | ||
| - | const char levels[] PROGMEM = | + | const char levels[] PROGMEM = { |
| - | { | + | 0b00000, |
| - | 0b00000, | + | 0b00000, |
| - | 0b00000, | + | 0b00000, |
| - | 0b00000, | + | 0b00000, |
| - | 0b00000, | + | 0b00000, |
| - | 0b00000, | + | 0b00000, |
| - | 0b00000, | + | 0b00000, |
| - | 0b00000, | + | 0b11111, |
| - | 0b11111, | + | 0b11111, |
| - | 0b11111, | + | 0b11111, |
| - | 0b11111, | + | 0b11111, |
| - | 0b11111, | + | 0b11111, |
| - | 0b11111, | + | 0b11111, |
| - | 0b11111, | + | 0b11111 |
| - | 0b11111 | + | |
| }; | }; | ||
| - | + | ||
| // This function loads custom characters into the LCD. Up to 8 | // This function loads custom characters into the LCD. Up to 8 | ||
| // characters can be loaded; we use them for 7 levels of a bar graph. | // characters can be loaded; we use them for 7 levels of a bar graph. | ||
| void load_custom_characters() | void load_custom_characters() | ||
| { | { | ||
| - | | + | lcd_load_custom_character(levels+0, |
| - | lcd_load_custom_character(levels+1, | + | lcd_load_custom_character(levels+1, |
| - | lcd_load_custom_character(levels+2, | + | lcd_load_custom_character(levels+2, |
| - | lcd_load_custom_character(levels+3, | + | lcd_load_custom_character(levels+3, |
| - | lcd_load_custom_character(levels+4, | + | lcd_load_custom_character(levels+4, |
| - | lcd_load_custom_character(levels+5, | + | lcd_load_custom_character(levels+5, |
| - | lcd_load_custom_character(levels+6, | + | lcd_load_custom_character(levels+6, |
| - | clear(); // the LCD must be cleared for the characters to take effect | + | clear(); // the LCD must be cleared for the characters to take effect |
| } | } | ||
| - | + | ||
| // This function displays the sensor readings using a bar graph. | // This function displays the sensor readings using a bar graph. | ||
| void display_readings(const unsigned int *calibrated_values) | void display_readings(const unsigned int *calibrated_values) | ||
| { | { | ||
| - | | + | unsigned char i; |
| - | + | ||
| - | for(i=0; i<5; i++) | + | for(i=0; |
| - | | + | // Initialize the array of characters that we will use for the |
| - | // Initialize the array of characters that we will use for the | + | // graph. |
| - | // graph. | + | // character, and character 255 (a full black box), we get 10 |
| - | // character, and character 255 (a full black box), we get 10 | + | // characters in the array. |
| - | // characters in the array. | + | const char display_characters[10] = {' ', |
| - | const char display_characters[10] = {' ', | + | |
| - | + | // The variable c will have values from 0 to 9, since | |
| - | // The variable c will have values from 0 to 9, since | + | // calibrated values are in the range of 0 to 1000, and |
| - | // calibrated values are in the range of 0 to 1000, and | + | // 1000/101 is 9 with integer math. |
| - | // 1000/101 is 9 with integer math. | + | char c = display_characters[calibrated_values[i]/ |
| - | char c = display_characters[calibrated_values[i]/ | + | |
| - | + | // Display the bar graph character. | |
| - | // Display the bar graph character. | + | print_character(c); |
| - | print_character(c); | + | } |
| - | } | + | |
| } | } | ||
| - | + | ||
| // Initializes the 3pi, displays a welcome message, calibrates, and | // Initializes the 3pi, displays a welcome message, calibrates, and | ||
| // plays the initial music. | // plays the initial music. | ||
| void initialize() | void initialize() | ||
| { | { | ||
| - | | + | unsigned int counter; // used as a simple timer |
| - | unsigned int sensors[5]; // an array to hold sensor values | + | unsigned int sensors[5]; // an array to hold sensor values |
| - | + | ||
| - | // This must be called at the beginning of 3pi code, to set up the | + | // This must be called at the beginning of 3pi code, to set up the |
| - | // sensors. | + | // sensors. |
| - | // corresponds to 2000*0.4 us = 0.8 ms on our 20 MHz processor. | + | // corresponds to 2000*0.4 us = 0.8 ms on our 20 MHz processor. |
| - | pololu_3pi_init(2000); | + | pololu_3pi_init(2000); |
| - | load_custom_characters(); | + | load_custom_characters(); |
| - | + | ||
| - | // Play welcome music and display a message | + | // Play welcome music and display a message |
| - | print_from_program_space(welcome_line1); | + | print_from_program_space(welcome_line1); |
| - | lcd_goto_xy(0, | + | lcd_goto_xy(0, |
| - | print_from_program_space(welcome_line2); | + | print_from_program_space(welcome_line2); |
| - | play_from_program_space(welcome); | + | play_from_program_space(welcome); |
| - | delay_ms(1000); | + | delay_ms(1000); |
| - | + | ||
| - | clear(); | + | clear(); |
| - | print_from_program_space(demo_name_line1); | + | print_from_program_space(demo_name_line1); |
| - | lcd_goto_xy(0, | + | lcd_goto_xy(0, |
| - | print_from_program_space(demo_name_line2); | + | print_from_program_space(demo_name_line2); |
| - | delay_ms(1000); | + | delay_ms(1000); |
| - | + | ||
| - | // Display battery voltage and wait for button press | + | // Display battery voltage and wait for button press |
| - | while(!button_is_pressed(BUTTON_B)) | + | while(!button_is_pressed(BUTTON_B)) |
| - | { | + | { |
| - | int bat = read_battery_millivolts(); | + | int bat = read_battery_millivolts(); |
| - | + | ||
| - | clear(); | + | clear(); |
| - | print_long(bat); | + | print_long(bat); |
| - | print(" | + | print(" |
| - | lcd_goto_xy(0, | + | lcd_goto_xy(0, |
| - | print(" | + | print(" |
| - | + | ||
| - | delay_ms(100); | + | delay_ms(100); |
| - | } | + | } |
| - | + | ||
| - | // Always wait for the button to be released so that 3pi doesn' | + | // Always wait for the button to be released so that 3pi doesn' |
| - | // start moving until your hand is away from it. | + | // start moving until your hand is away from it. |
| - | wait_for_button_release(BUTTON_B); | + | wait_for_button_release(BUTTON_B); |
| - | delay_ms(1000); | + | delay_ms(1000); |
| - | + | ||
| - | // Auto-calibration: | + | // Auto-calibration: |
| - | // sensors. | + | // sensors. |
| - | for(counter=0; | + | for(counter=0; |
| - | { | + | { |
| - | if(counter < 20 || counter >= 60) | + | if(counter < 20 || counter >= 60) |
| - | set_motors(40, | + | set_motors(40, |
| - | else | + | else |
| - | set_motors(-40, | + | set_motors(-40, |
| - | + | ||
| - | // This function records a set of sensor readings and keeps | + | // This function records a set of sensor readings and keeps |
| - | // track of the minimum and maximum values encountered. | + | // track of the minimum and maximum values encountered. |
| - | // IR_EMITTERS_ON argument means that the IR LEDs will be | + | // IR_EMITTERS_ON argument means that the IR LEDs will be |
| - | // turned on during the reading, which is usually what you | + | // turned on during the reading, which is usually what you |
| - | // want. | + | // want. |
| - | calibrate_line_sensors(IR_EMITTERS_ON); | + | calibrate_line_sensors(IR_EMITTERS_ON); |
| - | + | ||
| - | // Since our counter runs to 80, the total delay will be | + | // Since our counter runs to 80, the total delay will be |
| - | // 80*20 = 1600 ms. | + | // 80*20 = 1600 ms. |
| - | delay_ms(20); | + | delay_ms(20); |
| - | } | + | } |
| - | set_motors(0, | + | set_motors(0, |
| - | + | ||
| - | // Display calibrated values as a bar graph. | + | // Display calibrated values as a bar graph. |
| - | while(!button_is_pressed(BUTTON_B)) | + | while(!button_is_pressed(BUTTON_B)) |
| - | { | + | { |
| - | // Read the sensor values and get the position measurement. | + | // Read the sensor values and get the position measurement. |
| - | unsigned int position = read_line(sensors, | + | unsigned int position = read_line(sensors, |
| - | + | ||
| - | // Display the position measurement, | + | // Display the position measurement, |
| - | // (when the leftmost sensor is over the line) to 4000 (when | + | // (when the leftmost sensor is over the line) to 4000 (when |
| - | // the rightmost sensor is over the line) on the 3pi, along | + | // the rightmost sensor is over the line) on the 3pi, along |
| - | // with a bar graph of the sensor readings. | + | // with a bar graph of the sensor readings. |
| - | // to make sure the robot is ready to go. | + | // to make sure the robot is ready to go. |
| - | clear(); | + | clear(); |
| - | print_long(position); | + | print_long(position); |
| - | lcd_goto_xy(0, | + | lcd_goto_xy(0, |
| - | display_readings(sensors); | + | display_readings(sensors); |
| - | + | ||
| - | delay_ms(100); | + | delay_ms(100); |
| - | } | + | } |
| - | wait_for_button_release(BUTTON_B); | + | wait_for_button_release(BUTTON_B); |
| - | + | ||
| - | clear(); | + | clear(); |
| - | print(" | + | |
| - | + | print(" | |
| + | |||
| + | // Play music and wait for it to finish before we start driving. | ||
| + | play_from_program_space(go); | ||
| + | while(is_playing()); | ||
| } | } | ||
| - | + | ||
| // This is the main function, where the code starts. | // This is the main function, where the code starts. | ||
| // must have a main() function defined somewhere. | // must have a main() function defined somewhere. | ||
| int main() | int main() | ||
| { | { | ||
| - | | + | unsigned int sensors[5]; // an array to hold sensor values |
| - | unsigned int last_proportional=0; | + | unsigned int last_proportional=0; |
| - | long integral=0; | + | long integral=0; |
| - | currentIdx | + | |
| - | + | // set up the 3pi | |
| - | // set up the 3pi | + | initialize(); |
| - | initialize(); | + | |
| - | //int val =0; | + | // This is the "main loop" - it will run forever. |
| - | //char lisa=0; | + | while(1) |
| - | int x=18; // | + | { |
| - | int y=0; //int | + | // Get the position of the line. Note that we *must* provide |
| - | int z1=4, | + | // the " |
| - | int max = 150; | + | // are not interested in the individual sensor readings. |
| - | int butp = 0; | + | unsigned int position = read_line(sensors, |
| - | /* pval = eeprom_read_byte((uint8_t*)10); | + | |
| - | ival = eeprom_read_byte((uint8_t*)11); | + | // The " |
| - | dval1 =eeprom_read_byte((uint8_t*)12); | + | int proportional = ((int)position) - 2000; |
| - | dval2 =eeprom_read_byte((uint8_t*)13); | + | |
| - | while(1) | + | // Compute the derivative (change) and integral (sum) of the |
| - | { | + | // position. |
| - | + | int derivative = proportional - last_proportional; | |
| - | if(butp ==0) | + | integral += proportional; |
| - | { | + | |
| - | if(button_is_pressed(BUTTON_C)) | + | // Remember the last position. |
| - | { | + | last_proportional = proportional; |
| - | x++; | + | |
| - | } | + | // Compute the difference between the two motor power settings, |
| - | else if(button_is_pressed(BUTTON_A)) | + | // m1 - m2. If this is a positive number the robot will turn |
| - | { | + | // to the right. |
| - | x--; | + | // turn to the left, and the magnitude of the number determines |
| - | } | + | // the sharpness of the turn. |
| - | print(" | + | int power_difference = proportional/ |
| - | lcd_goto_xy(0, | + | |
| - | print_long(x); | + | // Compute the actual motor settings. |
| - | delay_ms(100); | + | // to a negative value. |
| - | } | + | const int max = 60; |
| - | else if(butp==1) | + | if(power_difference > max) |
| - | { | + | power_difference = max; |
| - | if(button_is_pressed(BUTTON_C)) | + | if(power_difference < -max) |
| - | { | + | power_difference = -max; |
| - | y++;; | + | |
| - | } | + | if(power_difference < 0) |
| - | else if(button_is_pressed(BUTTON_A)) | + | set_motors(max+power_difference, |
| - | { | + | else |
| - | y--; | + | set_motors(max, |
| - | } | + | } |
| - | print(" | + | |
| - | lcd_goto_xy(0, | + | // This part of the code is never reached. |
| - | print_long(y); | + | // never reach the end of its program, or unpredictable behavior |
| - | delay_ms(100); | + | // will result as random code starts getting executed. |
| - | } | + | // really want to stop all actions at some point, set your motors |
| - | else if(butp==2) | + | // to 0,0 and run the following command to loop forever: |
| - | { | + | // |
| - | if(button_is_pressed(BUTTON_C)) | + | // while(1); |
| - | { | + | |
| - | z1++; | + | |
| - | } | + | |
| - | else if(button_is_pressed(BUTTON_A)) | + | |
| - | { | + | |
| - | z1--; | + | |
| - | } | + | |
| - | print(" | + | |
| - | lcd_goto_xy(0, | + | |
| - | print_long(z1); | + | |
| - | delay_ms(100); | + | |
| - | } | + | |
| - | else if(butp==3) | + | |
| - | { | + | |
| - | if(button_is_pressed(BUTTON_C)) | + | |
| - | { | + | |
| - | z2++; | + | |
| - | } | + | |
| - | else if(button_is_pressed(BUTTON_A)) | + | |
| - | { | + | |
| - | z2--; | + | |
| - | } | + | |
| - | print(" | + | |
| - | lcd_goto_xy(0, | + | |
| - | print_long(z2); | + | |
| - | delay_ms(100); | + | |
| - | } | + | |
| - | else if(butp==4) | + | |
| - | { | + | |
| - | if(button_is_pressed(BUTTON_C)) | + | |
| - | { | + | |
| - | max++; | + | |
| - | } | + | |
| - | else if(button_is_pressed(BUTTON_A)) | + | |
| - | { | + | |
| - | max--; | + | |
| - | } | + | |
| - | if(max >= 255) | + | |
| - | { | + | |
| - | max = 255; | + | |
| - | } | + | |
| - | if(max <= 20) | + | |
| - | { | + | |
| - | max = 20; | + | |
| - | } | + | |
| - | print(" | + | |
| - | lcd_goto_xy(0, | + | |
| - | print_long(max); | + | |
| - | delay_ms(50); | + | |
| - | } | + | |
| - | + | ||
| - | else if(butp > 4) break; | + | |
| - | if(button_is_pressed(BUTTON_B)) | + | |
| - | { | + | |
| - | butp++; | + | |
| - | delay_ms(200); | + | |
| - | } | + | |
| - | clear(); | + | |
| - | } | + | |
| - | + | ||
| - | clear(); | + | |
| - | print(" | + | |
| - | lcd_goto_xy(0, | + | |
| - | print(" | + | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | // This is the "main loop" - it will run forever. | + | |
| - | while(1) | + | |
| - | { | + | |
| - | if (currentIdx < MELODY_LENGTH && !is_playing()) | + | |
| - | | + | |
| - | // play note at max volume | + | |
| - | play_note(note[currentIdx], | + | |
| - | currentIdx++; | + | |
| - | } | + | |
| - | if(currentIdx >= 95) currentIdx = 0; | + | |
| - | | + | |
| - | // the " | + | |
| - | // are not interested in the individual sensor readings. | + | |
| - | unsigned int position = read_line(sensors, | + | |
| - | + | ||
| - | // The " | + | |
| - | int proportional = ((int)position) - 2000; | + | |
| - | + | ||
| - | // Compute the derivative (change) and integral (sum) of the | + | |
| - | // position. | + | |
| - | int derivative = proportional - last_proportional; | + | |
| - | integral += proportional; | + | |
| - | + | ||
| - | // Remember the last position. | + | |
| - | last_proportional = proportional; | + | |
| - | + | ||
| - | // Compute the difference between the two motor power settings, | + | |
| - | // m1 - m2. If this is a positive number the robot will turn | + | |
| - | // to the right. | + | |
| - | // turn to the left, and the magnitude of the number determines | + | |
| - | // the sharpness of the turn. | + | |
| - | int power_difference = proportional/ | + | |
| - | + | ||
| - | // Compute the actual motor settings. | + | |
| - | // to a negative value. | + | |
| - | + | ||
| - | if(power_difference > max) | + | |
| - | power_difference = max; | + | |
| - | if(power_difference < -max) | + | |
| - | power_difference = -max; | + | |
| - | + | ||
| - | if(power_difference < 0) | + | |
| - | set_motors(max+power_difference, | + | |
| - | else | + | |
| - | set_motors(max, | + | |
| - | } | + | |
| - | + | ||
| - | // This part of the code is never reached. | + | |
| - | // never reach the end of its program, or unpredictable behavior | + | |
| - | // will result as random code starts getting executed. | + | |
| - | // really want to stop all actions at some point, set your motors | + | |
| - | // to 0,0 and run the following command to loop forever: | + | |
| - | // | + | |
| - | // while(1); | + | |
| } | } | ||
| - | + | ||
| // Local Variables: ** | // Local Variables: ** | ||
| // mode: C ** | // mode: C ** | ||
| Line 521: | Line 399: | ||
| // indent-tabs-mode: | // indent-tabs-mode: | ||
| // end: ** | // end: ** | ||
| - | |||
| </ | </ | ||