Help programming Push Buttons

Hey guys,

Im trying to get a feel for the 3PI by writing a program that starts the motors by pushing button A, and stopping them by pushing button C. My code is bellow, but my program seems to enter the loop of the motors moving, and won’t break out of it. Can anyone point out the reason for why it wont work?

#include <pololu/orangutan.h>

int main()
{
	lcd_init_printf();
	clear();	// clear the LCD
	

	while (1)
	{
		unsigned char button = get_single_debounced_button_press(ANY_BUTTON);
		if(button==BUTTON_A)
		{

			while(button!=BUTTON_C)
			{
				clear();
				print("Moving");
				set_motors(128,128);
				delay_ms(1000);
				set_motors(-128,-128);
				delay_ms(1000);
				set_motors(0,0);
				clear();
	
			}
		}
		if(button==BUTTON_B)
		{
			clear();
			print("B");
		}

		if(button==BUTTON_C)
		{
			clear();
			print("Stop");
			set_motors(0,0);
		}
	}
		
			
}

Thanks in advance!

Hello,

In the future, please format your “Code” button to make it more readable. Also, please simplify your code by removing all parts that are not necessary to demonstrate the problem (such as motor commands, lcd_init_printf, etc.)

Anyway, you have an infinite loop:

while(button!=BUTTON_C)
{
  clear();
  print("Moving");
  set_motors(128,128);
  delay_ms(1000);
  set_motors(-128,-128);
  delay_ms(1000);
  set_motors(0,0);
  clear();
}

Nothing in that loop will ever change the value of button, so the loop can never end. Instead, you should do something like:

while(1)
{
  while(!get_single_debounced_button_press(BUTTON_A))
  {
    // do stuff with the motors stopped
  }

  // start motors

  while(!get_single_debounced_button_press(BUTTON_C))
  {
    // do stuff with the motors running
  }

  // stop motors
}

-Paul

Hello.
Better yet would be something where you check it while delaying:

bool get_single_debounced_button_press_with_timeout(unsigned char buttons, unsigned int timeout_in_ms)
{
  unsigned long end = get_ms() + timeout_in_ms;
  unsigned char button_results;
  while(end > get_ms())
  {
    button_results = get_single_debounced_button_press(buttons);
    if (button_results)
    {
      return button_results;
    }
  }
  return 0;
}

Then your code would look something like:

while(1)
{
  clear();
  print("Moving");
  set_motors(128,128);
  if (get_single_debounced_button_press_with_timeout(BUTTON_C,1000)) break;
  set_motors(-128,-128);
  if (get_single_debounced_button_press_with_timeout(BUTTON_C,1000)) break;
  set_motors(0,0);
  clear();
}

- Ryan

Hey, sorry about the format…

Thanks for the quick reply. I have gotten it to work the way I want it to, but now I’m on to another question. After compiling, it says that I am already through with 22.6% of the program space. Does this mean that I have already taken up 22.6% of the space available n the 3PI that can store the code I write?

Also, this is my final code that I used. Can I make it more efficient?

while(1)
	{
		while(!get_single_debounced_button_press(BUTTON_A))
		{
			set_motors(0,0);
			print("Stopped");
			delay_ms(50);
			clear();
		}

		while(!get_single_debounced_button_press(BUTTON_C))
		{
			set_motors(128,128);
			print("Moving");
			delay_ms(50);
			clear();
		}

Thanks for your help!

Yes, it means that you have already used up 22.6% of the flash available on your 3pi. Unless you have an old 3pi, you should have a ATmega328P with 32K of flash.

Note that right now, since your code is so small, most of that program space is actually being taken up by the Pololu AVR Library function that you are calling. This means that your code can get more complicated, but as long as it still calls those same library functions, it won’t take up much additional space.

The ATmega328P has plenty of RAM (2K) and Flash (32K) so you shouldn’t worry too much about using it up.

Your program is not particularly inefficient. But since you asked, there are a couple little things you could do to improve it:

  • There is no need to repeatedly set the motors to the same value over and over again. Similarly, there is no need to print the same message to the LCD over and over again, so you can take that code out of the while loops.
  • You can store your strings in program space instead of RAM. This will save you some RAM and won’t cost you any program space.
  • You could probably save some program space by using the simpler, blocking wait_for_button_press() instead of get_single_debounced_button_press(). Try it and see!

If you follow all of these suggestions, your code would look like:

while(1)
{
    set_motors(0,0);
    clear();
    print_from_program_space(PSTR("Stopped"));
    wait_for_button(BUTTON_A);

    set_motors(128,128);
    clear();
    print_from_program_space(PSTR("Moving"));
    wait_for_button(BUTTON_C);
}

–David

Hello,

To save space, you want to make sure you are using the linker option suggested in section 7 of Pololu AVR user’s guide below the first picture in that section. That will only link in the functions you use.

-Ryan

Thanks for the replies guys! I havent gotten anywhere near filling up my space yet, so that has kinda taken a back seat for now.

My next goal is to try and get some IR sensors working. Ive used the Analog2 code as a base for my code, and come up with this. But I cant figure out why it doesn’t keep reading values. I have it written so that it constantly converts the values from PC5 and then averages them and uses the sum to compare the statements. If its greater than 200 then display that, if its not then break and display “20 samples”… Here is my code

        if (!analog_is_converting())     // if conversion is done...
   		{
      		sum += analog_conversion_result();  // get result
     		start_analog_conversion(PC5);   // start next conversion
     		
				if (++samples == 20)           // if 20 samples have been taken...
      			        {
        			avg = sum / 20;             // compute 20-sample average of ADC result
				samples = 0;
        			sum = 0;

					if (avg >= 200)
					{
						avg=0;
						red_led(1);
						delay_ms(500);
						print("avg>200 \n");
					}

					print("20 samp\n");
					delay_ms(500);
					clear();
					avg = 0;
      			}
		}

Hello,

What kind of IR sensors are you using, and how are they connected? You can simplify your setup a lot by removing the IR sensors and just connecting the analog input to either 5V or GND.

Also, please remove all averaging code, and simplify until you have the simplest possible program that does not work - then post your entire program and describe exactly how it failed. It will be extremely hard to help you without that!

-Paul