Gear shifting code when solving a maze

Hi all,
I’m in a competition with my friends to create the fastest robot in a maze setting. I’m trying to create a constant gear that will result in long run times; the maximum gear is determined by the most challenging regions of track; therefore I need to shift my gears in challenging regions. I want to use the twenty most recent past vales of my ‘proportional’ term to adaptively change the speed of my robot. To do this I want to find a way to store the 20 most recent values of ‘proportional.’ I have to do this using a queue. Can someone look over my code and help me design this??

/*
 * This code will follow a black line on a white background, using an adaptive
 * PID-based algorithm.
 *
 * https://www.pololu.com/docs/0J21
 * https://www.pololu.com
 * https://forum.pololu.com
 *
 */

// The 3pi include file must be at the beginning of any program that
// uses the Pololu AVR library and 3pi.
#include <pololu/3pi.h>

// This include file allows data to be stored in program space.  The
// ATmega168 has 16k of program space compared to 1k of RAM, so large
// pieces of static data should be stored in program space.
#include <avr/pgmspace.h>
// Introductory messages.  The "PROGMEM" identifier causes the data to
// go into program space.
#include "maze.h"
#include "robotModel.h"
#include "useCurses.h"
#include <stdio.h>
#include <stdlib.h>

const char welcome_line1[] PROGMEM = " Pololu";
const char welcome_line2[] PROGMEM = "3\xf7 Robot";
const char demo_name_line1[] PROGMEM = "PID Line";
const char demo_name_line2[] PROGMEM = "follower";

// A couple of simple tunes, stored in program space.
const char welcome[] PROGMEM = ">g32>>c32";
const char go[] PROGMEM = "L16 cdegreg4";

const char increase[] PROGMEM = "L16 dd";
const char decrease[] PROGMEM = "L16 bb";

void run_proportional(int proportional, int speed);
void initialize();
int input_gear(int gear);


// Data for generating the characters used in load_custom_characters
// and display_readings.  By reading levels[] starting at various
// offsets, we can generate all of the 7 extra characters needed for a
// bargraph.  This is also stored in program space.
const char levels[] PROGMEM = {
	0b00000,
	0b00000,
	0b00000,
	0b00000,
	0b00000,
	0b00000,
	0b00000,
	0b11111,
	0b11111,
	0b11111,
	0b11111,
	0b11111,
	0b11111,
	0b11111
};


// 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.
void load_custom_characters()
{
	lcd_load_custom_character(levels+0,0); // no offset, e.g. one bar
	lcd_load_custom_character(levels+1,1); // two bars
	lcd_load_custom_character(levels+2,2); // etc...
	lcd_load_custom_character(levels+3,3);
	lcd_load_custom_character(levels+4,4);
	lcd_load_custom_character(levels+5,5);
	lcd_load_custom_character(levels+6,6);
	clear(); // the LCD must be cleared for the characters to take effect
}

// This function displays the sensor readings using a bar graph.
void display_readings(const unsigned int *calibrated_values)
{
	unsigned char i;

	for(i=0;i<5;i++) {
		// Initialize the array of characters that we will use for the
		// graph.  Using the space, an extra copy of the one-bar
		// character, and character 255 (a full black box), we get 10
		// characters in the array.
		const char display_characters[10] = {' ',0,0,1,2,3,4,5,6,255};

		// The variable c will have values from 0 to 9, since
		// calibrated values are in the range of 0 to 1000, and
		// 1000/101 is 9 with integer math.
		char c = display_characters[calibrated_values[i]/101];

		// Display the bar graph character.
		print_character(c);
	}
}


// Initializes the 3pi, displays a welcome message, calibrates, and
// plays the initial music.
void initialize()
{
	unsigned int counter; // used as a simple timer
	unsigned int sensors[5]; // an array to hold sensor values

	// This must be called at the beginning of 3pi code, to set up the
	// sensors.  We use a value of 2000 for the timeout, which
	// corresponds to 2000*0.4 us = 0.8 ms on our 20 MHz processor.
	pololu_3pi_init(2000);
	load_custom_characters(); // load the custom characters

	// Play welcome music and display a message
	print_from_program_space(welcome_line1);
	lcd_goto_xy(0,1);
	print_from_program_space(welcome_line2);
	play_from_program_space(welcome);
	delay_ms(1000);

	clear();
	print_from_program_space(demo_name_line1);
	lcd_goto_xy(0,1);
	print_from_program_space(demo_name_line2);
	delay_ms(1000);

	// Display battery voltage and wait for button press
	while(!button_is_pressed(BUTTON_B))
	{
		int bat = read_battery_millivolts();

		clear();
		print_long(bat);
		print("mV");
		lcd_goto_xy(0,1);
		print("Press B");

		delay_ms(100);
	}

	// Always wait for the button to be released so that 3pi doesn't
	// start moving until your hand is away from it.
	wait_for_button_release(BUTTON_B);
	delay_ms(1000);

	// Auto-calibration: turn right and left while calibrating the
	// sensors.
	for(counter=0;counter<80;counter++)
	{
		if(counter < 20 || counter >= 60)
			set_motors(40,-40);
		else
			set_motors(-40,40);

		// This function records a set of sensor readings and keeps
		// track of the minimum and maximum values encountered.  The
		// IR_EMITTERS_ON argument means that the IR LEDs will be
		// turned on during the reading, which is usually what you
		// want.
		calibrate_line_sensors(IR_EMITTERS_ON);

		// Since our counter runs to 80, the total delay will be
		// 80*20 = 1600 ms.
		delay_ms(20);
	}
	set_motors(0,0);

}




//-------------------------------------------------------------------
// This is the main function, where the code starts.  All C programs
// must have a main() function defined somewhere.
//-------------------------------------------------------------------
int main()
{
	unsigned int sensors[5]={0}; // an array to hold sensor values
	unsigned int last_proportional=0;
	int proportional=0;
    int derivative=0;
    int lap_index=-1;                   // starts the lap when the mark orthogonal to the track is detected
	long integral=0;
    int gear = 2;                       // default gear
    unsigned long start_time;           // variable to store the starting time
  
    // set up the 3pi
	initialize();

    // Allows user to change gears using buttons.
    //--------------------------------------------

    gear = input_gear(gear);

    // Start the program.
    //--------------------

    clear();
	print("Go!");

	// Play music and wait for it to finish before we start driving.
	play_from_program_space(go);
	while(is_playing());

    unsigned long time = get_ms();

    // This is the "main loop" - it will run forever.
	while(1)
	{

        // Get the position of the line.
		unsigned int position = read_line(sensors,IR_EMITTERS_ON);


		// The "proportional" term should be 0 when we are on the line.
		proportional = ((int)position) - 2000;
		derivative = proportional - last_proportional;
		integral += proportional;
		last_proportional = proportional;


        // GEAR SWITCHING CODE GOES HERE

        print ("\n Enter")

        //----------------------------


        // CALL PROPORTIONAL CONTROLLER WITH DIFFERENT SPEED SETTINGS
        //------------------------------------------------------------

        switch (gear) {
            case 1:   run_proportional(proportional, 64);
                break;
            case 2:   run_proportional(proportional, 128);
                break;
            case 3:   run_proportional(proportional, 164);
                break;
            case 4:   run_proportional(proportional, 192);
                break;
            case 5:   run_proportional(proportional, 232);
                break;
            }





        // Increase lap index if all sensors are active; i.e., mark has been reached
        //---------------------------------------------------------------------------
        if (sensors[0]>600 && sensors[1]>600 && sensors[2]>600 && sensors[3]>600 && sensors[4]>600 && (get_ms()-time)>100)
        {
            lap_index++;
            time = get_ms();
        }

        if(lap_index == 0)           // First mark: set the start time
        {
            start_time = time;
        }
        else if (lap_index == 1 ) {  // Terminate and wait indefinitely in while loop if total number of laps exceed 1
            set_motors(0,0);
            clear();
            left_led(0);
            right_led(0);
            position = read_line(sensors,IR_EMITTERS_OFF);

            lcd_goto_xy(0,0);
            print("RUN TIME");
            lcd_goto_xy(0,1);
            print_long(get_ms() - start_time);
            while(1);
        }

    }
	// This part of the code is never reached.  A robot should
	// never reach the end of its program, or unpredictable behavior
	// will result as random code starts getting executed.  If you
	// 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);
}


//--------------------------------------------------------------------------------------
// This is the main line following code. It sets the speed of the individual motors to
// speed + powerdiff and speed - powerdiff. Here, powerdiff is determined as
// the current error weighted by 128/2000.
// The motor speeds are always restricted to be in the range [0,255]
//--------------------------------------------------------------------------------------

void run_proportional(int proportional, int speed)
{

    float factor = 128/2000.0; // factor tuned so that proportional*factor in [-128,128]
    float computed = (float)(proportional);
    int power_difference = (int)(computed*factor);

    // Compute the actual motor settings.  We never set either motor
    // to a negative value or greater than 255.

    int lspeed = speed + power_difference;
    int rspeed = speed - power_difference;

    if(lspeed < 0)   lspeed = 0;
    if(rspeed < 0)   rspeed = 0;
    if(lspeed > 255) lspeed = 255;
    if(rspeed > 255) rspeed = 255;

    set_motors(lspeed, rspeed);

    return;
}


//--------------------------------------------------------------------------------------
// This function allows the users to increase or decrease the gears using the buttons
//--------------------------------------------------------------------------------------

int input_gear(int gear)
{
    unsigned char buttons = BUTTON_A;


    clear();
    lcd_goto_xy(0,0);
    print("A:< gear");
    lcd_goto_xy(0,1);
    print("C:> gear");
    delay_ms(1000);
    clear();
    lcd_goto_xy(0,0);
    print("B:OK");
    lcd_goto_xy(0,1);
    print("Gear "); print_long(gear);


    buttons = wait_for_button(ANY_BUTTON);
    while (buttons != BUTTON_B)
    {
        if (buttons == BUTTON_C) {
            gear = gear + 1;
            if(gear >5)  gear = 5;
            clear(); lcd_goto_xy(0,0); print("<  OK  >");
            lcd_goto_xy(0,1); print("Gear "); print_long(gear);
        }
        else
        {
            gear = gear - 1;
            if (gear<1) gear = 1;
            clear(); lcd_goto_xy(0,0); print("<  OK  >");
            lcd_goto_xy(0,1); print("Gear "); print_long(gear);
        }

    buttons = wait_for_button(ANY_BUTTON);
    }
    return(gear);

}

Sorry posted the wrong code! :blush:

/*
 * This code will follow a black line on a white background, using an adaptive
 * PID-based algorithm.
 *
 * https://www.pololu.com/docs/0J21
 * https://www.pololu.com
 * https://forum.pololu.com
 *
 */

// The 3pi include file must be at the beginning of any program that
// uses the Pololu AVR library and 3pi.
#include <pololu/3pi.h>

// This include file allows data to be stored in program space.  The
// ATmega168 has 16k of program space compared to 1k of RAM, so large
// pieces of static data should be stored in program space.
#include <avr/pgmspace.h>
// Introductory messages.  The "PROGMEM" identifier causes the data to
// go into program space.
#include "maze.h"
#include "robotModel.h"
#include "useCurses.h"
#include <stdio.h>
#include <stdlib.h>

const char welcome_line1[] PROGMEM = " Pololu";
const char welcome_line2[] PROGMEM = "3\xf7 Robot";
const char demo_name_line1[] PROGMEM = "PID Line";
const char demo_name_line2[] PROGMEM = "follower";

// A couple of simple tunes, stored in program space.
const char welcome[] PROGMEM = ">g32>>c32";
const char go[] PROGMEM = "L16 cdegreg4";

const char increase[] PROGMEM = "L16 dd";
const char decrease[] PROGMEM = "L16 bb";

void run_proportional(int proportional, int speed);
void run_pid(int proportional, int derivative, int integral, int speed);
void initialize();
int input_gear(int gear);


// Data for generating the characters used in load_custom_characters
// and display_readings.  By reading levels[] starting at various
// offsets, we can generate all of the 7 extra characters needed for a
// bargraph.  This is also stored in program space.
const char levels[] PROGMEM = {
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b11111,
    0b11111,
    0b11111,
    0b11111,
    0b11111,
    0b11111,
    0b11111
};


// 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.
void load_custom_characters()
{
    lcd_load_custom_character(levels+0,0); // no offset, e.g. one bar
    lcd_load_custom_character(levels+1,1); // two bars
    lcd_load_custom_character(levels+2,2); // etc...
    lcd_load_custom_character(levels+3,3);
    lcd_load_custom_character(levels+4,4);
    lcd_load_custom_character(levels+5,5);
    lcd_load_custom_character(levels+6,6);
    clear(); // the LCD must be cleared for the characters to take effect
}

// This function displays the sensor readings using a bar graph.
void display_readings(const unsigned int *calibrated_values)
{
    unsigned char i;

    for(i=0;i<5;i++) {
        // Initialize the array of characters that we will use for the
        // graph.  Using the space, an extra copy of the one-bar
        // character, and character 255 (a full black box), we get 10
        // characters in the array.
        const char display_characters[10] = {' ',0,0,1,2,3,4,5,6,255};

        // The variable c will have values from 0 to 9, since
        // calibrated values are in the range of 0 to 1000, and
        // 1000/101 is 9 with integer math.
        char c = display_characters[calibrated_values[i]/101];

        // Display the bar graph character.
        print_character(c);
    }
}


// Initializes the 3pi, displays a welcome message, calibrates, and
// plays the initial music.
void initialize()
{
    unsigned int counter; // used as a simple timer
    unsigned int sensors[5]; // an array to hold sensor values

    // This must be called at the beginning of 3pi code, to set up the
    // sensors.  We use a value of 2000 for the timeout, which
    // corresponds to 2000*0.4 us = 0.8 ms on our 20 MHz processor.
    pololu_3pi_init(2000);
    load_custom_characters(); // load the custom characters

    // Play welcome music and display a message
    print_from_program_space(welcome_line1);
    lcd_goto_xy(0,1);
    print_from_program_space(welcome_line2);
    play_from_program_space(welcome);
    delay_ms(1000);

    clear();
    print_from_program_space(demo_name_line1);
    lcd_goto_xy(0,1);
    print_from_program_space(demo_name_line2);
    delay_ms(1000);

    // Display battery voltage and wait for button press
    while(!button_is_pressed(BUTTON_B))
    {
        int bat = read_battery_millivolts();

        clear();
        print_long(bat);
        print("mV");
        lcd_goto_xy(0,1);
        print("Press B");

        delay_ms(100);
    }

    // Always wait for the button to be released so that 3pi doesn't
    // start moving until your hand is away from it.
    wait_for_button_release(BUTTON_B);
    delay_ms(1000);

    // Auto-calibration: turn right and left while calibrating the
    // sensors.
    for(counter=0;counter<80;counter++)
    {
        if(counter < 20 || counter >= 60)
            set_motors(40,-40);
        else
            set_motors(-40,40);

        // This function records a set of sensor readings and keeps
        // track of the minimum and maximum values encountered.  The
        // IR_EMITTERS_ON argument means that the IR LEDs will be
        // turned on during the reading, which is usually what you
        // want.
        calibrate_line_sensors(IR_EMITTERS_ON);

        // Since our counter runs to 80, the total delay will be
        // 80*20 = 1600 ms.
        delay_ms(20);
    }
    set_motors(0,0);

}




//-------------------------------------------------------------------
// This is the main function, where the code starts.  All C programs
// must have a main() function defined somewhere.
//-------------------------------------------------------------------
int main()
{
    unsigned int sensors[5]={0}; // an array to hold sensor values
    unsigned int last_proportional=0;
    int proportional=0;
    int derivative=0;
    int lap_index=-1;                   // starts the lap when the mark orthogonal to the track is detected
    long integral=0;
    int gear = 2;                       // default gear
    unsigned long start_time;           // variable to store the starting time
                                        // used for timing

    Maze maze; //structure to store the maze

    Robot robot; //structure for robot



    // set up the 3pi
    initialize();

    // Allows user to change gears using buttons.
    //--------------------------------------------

    gear = input_gear(gear);

    // Start the program.
    //--------------------

    clear();
    print("Go!");

    // Play music and wait for it to finish before we start driving.
    play_from_program_space(go);
    while(is_playing());

    unsigned long time = get_ms();

    // This is the "main loop" - it will run forever.
    while(1)
    {

        // Get the position of the line.
        unsigned int position = read_line(sensors,IR_EMITTERS_ON);


        // The "proportional" term should be 0 when we are on the line.
        proportional = ((int)position) - 2000;
        derivative = proportional - last_proportional;
        integral += proportional;
        last_proportional = proportional;


        // GEAR SWITCHING CODE: YOUR CODE HERE

        print ("\n Enter")

        //----------------------------


        // CALL PROPORTIONAL CONTROLLER WITH DIFFERENT SPEED SETTINGS
        //------------------------------------------------------------

        switch (gear) {
            case 1:   run_proportional(proportional, 64);
                break;
            case 2:   run_proportional(proportional, 128);
                break;
            case 3:   run_proportional(proportional, 164);
                break;
            case 4:   run_proportional(proportional, 192);
                break;
            case 5:   run_proportional(proportional, 232);
                break;
            }





        // Increase lap index if all sensors are active; i.e., mark has been reached
        //---------------------------------------------------------------------------
        if (sensors[0]>600 && sensors[1]>600 && sensors[2]>600 && sensors[3]>600 && sensors[4]>600 && (get_ms()-time)>100)
        {
            lap_index++;
            time = get_ms();
        }

        if(lap_index == 0)           // First mark: set the start time
        {
            start_time = time;
        }
        else if (lap_index == 1 ) {  // Terminate and wait indefinitely in while loop if total number of laps exceed 1
            set_motors(0,0);
            clear();
            left_led(0);
            right_led(0);
            position = read_line(sensors,IR_EMITTERS_OFF);

            lcd_goto_xy(0,0);
            print("RUN TIME");
            lcd_goto_xy(0,1);
            print_long(get_ms() - start_time);
            while(1);
        }

    }
    // This part of the code is never reached.  A robot should
    // never reach the end of its program, or unpredictable behavior
    // will result as random code starts getting executed.  If you
    // 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);
}


//--------------------------------------------------------------------------------------
// Strategy 1
// This is the main line following code. It sets the speed of the individual motors to
// speed + powerdiff and speed - powerdiff. Here, powerdiff is determined as
// the current error weighted by 128/2000.
// The motor speeds are always restricted to be in the range [0,255]
//--------------------------------------------------------------------------------------

void run_proportional(int proportional, int speed)
{

    float factor = 128/2000.0; // factor tuned so that proportional*factor in [-128,128]
    float computed = (float)(proportional);
    int power_difference = (int)(computed*factor);
void run_pid(int proportional, int derivative, int integral, int speed)
    // Compute the actual motor settings.  We never set either motor
    // to a negative value or greater than 255.

    int lspeed = speed + power_difference;
    int rspeed = speed - power_difference;

    if(lspeed < 0)   lspeed = 0;
    if(rspeed < 0)   rspeed = 0;
    if(lspeed > 255) lspeed = 255;
    if(rspeed > 255) rspeed = 255;

    set_motors(lspeed, rspeed);

    return;
}

//--------------------------------------------------------------------------------------
// Strategy 2
// This is the main line following code. It sets the speed of the individual motors to
// speed + powerdiff and speed - powerdiff. Here, powerdiff is determined as
// the current error weighted by 128/2000.
// The motor speeds are always restricted to be in the range [0,255]
//--------------------------------------------------------------------------------------

void run_pid(int proportional, int derivative, int integral, int speed)
{

    float factor = 128/2000.0; // factor tuned so that proportional*factor in [-128,128]
    float computed = (float)(proportional);
    int power_difference = (int)(computed*factor);

    // Compute the actual motor settings.  We never set either motor
    // to a negative value or greater than 255.

    power_difference = proportional + (integral*0.001) + (derivative*20);

    int lspeed = speed + power_difference;
    int rspeed = speed - power_difference;

    if(lspeed < 0)   lspeed = 0;
    if(rspeed < 0)   rspeed = 0;
    if(lspeed > 255) lspeed = 255;
    if(rspeed > 255) rspeed = 255;

    set_motors(lspeed, rspeed);

    return;
}

run_gear_shifting(int proportional, int derivative, int integral, int speed)

//--------------------------------------------------------------------------------------
// This function allows the users to increase or decrease the gears using the buttons
//--------------------------------------------------------------------------------------

int input_gear(int gear)
{
    unsigned char buttons = BUTTON_A;


    clear();
    lcd_goto_xy(0,0);
    print("A:< gear");
    lcd_goto_xy(0,1);
    print("C:> gear");
    delay_ms(1000);
    clear();
    lcd_goto_xy(0,0);
    print("B:OK");
    lcd_goto_xy(0,1);
    print("Gear "); print_long(gear);


    buttons = wait_for_button(ANY_BUTTON);
    while (buttons != BUTTON_B)
    {
        if (buttons == BUTTON_C) {
            gear = gear + 1;
            if(gear >5)  gear = 5;
            clear(); lcd_goto_xy(0,0); print("<  OK  >");
            lcd_goto_xy(0,1); print("Gear "); print_long(gear);
        }
        else
        {
            gear = gear - 1;
            if (gear<1) gear = 1;
            clear(); lcd_goto_xy(0,0); print("<  OK  >");
            lcd_goto_xy(0,1); print("Gear "); print_long(gear);
        }

    buttons = wait_for_button(ANY_BUTTON);
    }
    return(gear);

}

Hi.

Do you have a gearbox on your robot? Can you ask a more specific question, for example a question about what exactly you are having trouble with at the moment? Have you made any progress toward your goal? What program components do you think you need to build to achieve what you want to do?

- Ryan