Here’s the code that caused reset. Later, it worked fine when I deleted the really long line that plays “Canon” (line 341 in the program).
I don’t think it would cause RAM issues, as the music is not playing when you run the line-following segment, but I’m not an expert on these things. Thanks for helping!
/*
* 3pi-linefollower - demo code for the Pololu 3pi Robot (MODIFIED)
*
* This code will follow a black line on a white background, using a
* very simple algorithm. It demonstrates auto-calibration and use of
* the 3pi IR sensors, motor control, bar graphs using custom
* characters, and music playback, making it a good starting point for
* developing your own more competitive line follower.
*
* 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
// ATmegaxx8 has 16x more program space than 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.
const char welcome_line1[] PROGMEM = " Pololu";
const char welcome_line2[] PROGMEM = "3\xf7 Robot";
const char demo_name_line1[] PROGMEM = " Line ";
const char demo_name_line2[] PROGMEM = "Tracking";
// A couple of simple tunes, stored in program space.
const char welcome[] PROGMEM = ">g32>>c32";
const char go[] PROGMEM = "L16 cdegreg4";
// 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("!T480 L8 >c>f>g>>crrrr <cgec");
//delay_ms(1000);
clear();
print_from_program_space(welcome_line1);
lcd_goto_xy(0,1);
print_from_program_space(welcome_line2);
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);
if (bat<4000)
{
play("!T480 L8 >c16");
print("NO JUICE!");
}
else if (bat<4500)
{
play("!T480 L8 a16");
print("Low Battery");
delay_ms(100);
}
else if (bat<4800)
{
play("!T480 L8 f16");
print("Low Battery");
delay_ms(300);
}
else
{
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);
play("!T480 L8 >>gr>>g");
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);
// Display calibrated values as a bar graph.
while(!button_is_pressed(BUTTON_B))
{
// Read the sensor values and get the position measurement.
unsigned int position = read_line(sensors,IR_EMITTERS_ON);
// Display the position measurement, which will go from 0
// (when the leftmost sensor is over the line) to 4000 (when
// the rightmost sensor is over the line) on the 3pi, along
// with a bar graph of the sensor readings. This allows you
// to make sure the robot is ready to go.
clear();
print_long(position);
lcd_goto_xy(0,1);
display_readings(sensors);
delay_ms(100);
}
wait_for_button_release(BUTTON_B);
clear();
print("Onward!");
// Play music and wait for it to finish before we start driving.
play("!T240 L8 g>eR>e4>d>ca>c");
while (is_playing());
}
// This is the main function, where the code starts. All C programs
// must have a main() function defined somewhere.
int main()
{
play("!T480 L8 >c>f>g>>crrrr <cgec");
print("Welcome!");
delay_ms(1500);
clear();
print(" I am");
lcd_goto_xy(0,1);
print(" Melvin");
delay_ms(1500);
while(1)
{
int thing = 0;
clear();
print("B: Lines");
lcd_goto_xy(0,1);
print("C: Music");
delay_ms(100);
if (button_is_pressed(BUTTON_A))
{
play("!T720 >f>a>>c>f");
while(is_playing());
while(thing == 0)
{
int bat = read_battery_millivolts();
clear();
print_long(bat);
print("mV");
lcd_goto_xy(0,1);
if (bat<4000)
{
play("!T480 L8 >c16");
print("NO JUICE!");
}
else if (bat<4500)
{
play("!T480 L8 a16");
print("Low Battery");
delay_ms(100);
}
else if (bat<4800)
{
play("!T480 L8 f16");
print("Low Battery");
delay_ms(300);
}
else
{
print("B: Exit");
}
delay_ms(100);
if (button_is_pressed(BUTTON_B))
{
play("!T480 L8 >dr>d");
wait_for_button_release(BUTTON_B);
thing = 1;
}
}
}
if(button_is_pressed(BUTTON_C))
{
wait_for_button_release(BUTTON_C);
play("!T480 L4 ML c2dee2<g2<a1");
while (is_playing());
int song = 0;
int songmenu = 1;
while (songmenu == 1)
{
clear();
lcd_goto_xy(0,0);
if (song == 0)
{
print("Zelda");
if (button_is_pressed(BUTTON_B))
{
play("!T480 L8 cg>c");
wait_for_button_release(BUTTON_B);
delay_ms(500);
play("!T240 L4 ML <b16d16 MS g2d2.gg8a8b8>c8 ML f16a16>c16 MS >d1r>d>d6>e-6>f6 ML b-16>e-16 MS >g1r6>g6>g6>g6>f6>e-6 ML b-16>d16>f3 MS >e-6>d1>d2 ML e-16g16 MS >c>c8>d8>e-1>d>c ML d16g16 MS b-b-8>c8>d1>cb- ML c+16e16 MS aa8b8>c+1>e2 ML f+16a16 MS >dd8d8dd8d8dd8d8d6e-6f6g1");
// First verse: ML <b16d16 MS g2d2.gg8a8b8>c8 ML f16a16>c16 MS >d1r>d>d6>e-6>f6 ML b-16>e-16 MS >g1r6>g6>g6>g6>f6>e-6 ML b-16>d16>f3 MS >e-6>d1>d2 ML e-16g16 MS >c>c8>d8>e-1>d>c ML d16g16 MS b-b-8>c8>d1>cb- ML c+16e16 MS aa8b8>c+1>e2 ML f+16a16 MS >dd8d8dd8d8dd8d8ef+
}
}
if (song == 1)
{
print("Ocelot");
if (button_is_pressed(BUTTON_B))
{
play("!T480 L8 cg>c");
wait_for_button_release(BUTTON_B);
delay_ms(500);
play("!T240 L8 MS g >ec>e4a32>d16.>ca>c<f>ca>c>d<g>c4 >ec>e4a32>d16.>ca>c<g>cgece<g<<g >ec>e4a32>d16.>ca>c<f>ca>c>d<g>c4 c4>e4<a16>g16>e>d>c<g>cgec<ccr");
}
}
if (song == 2)
{
print("Tetris");
if (button_is_pressed(BUTTON_B))
{
play("!T480 L8 cg>c");
wait_for_button_release(BUTTON_B);
delay_ms(500);
play("!T240 L8 MS >e<eb>c>d>e16>d16>cba<aa>c>e<a>d>cb<g+b>c>d<e>e<e>c<aarae<bc d>d<d>f>ad16d16>g>f>e<cr>c>e<g>d>cb<g+b>c>d<e>e<e>c<aa<aa");
}
}
if (song == 3)
{
print("Canon");
if (button_is_pressed(BUTTON_B))
{
play("!T480 L8 cg>c");
wait_for_button_release(BUTTON_B);
delay_ms(500);
play("!T80 L8 ML >ddf+a>c+<ac+eb<bdf+a<f+<ac+ g<g<bdf+<d<f+<ag<g<bda<ac+e >f+df+a>e<ac+e>d<bdf+>c+<f+<ac+ b<g<bda<d<f+<ab<g<bd>c+<age f+df+da<a>c+<a>d<b>f+<b>a<f+a<f+ b<gg<ga<da<dg<g>d<g>c+<ag>c+ >d16d16>c+>ddc+16<a16aef+d16<b16>d>c+b>c+16<f+16>f+>a>b >g16<g16>f+>e>g>f+16d16>e>d>c+b16<g16agf+e16<a16gf+e >a>f+16>g16>a>f+16>g16>a16a16b16>c+16>d16>e16>f+16>g16>f+>d16>e16>f+f+16g16a16b16a16g16a16f+16g16a16 gb16a16gf+16e16f+16e16d16e16f+16g16a16b16gb16a16b>c+16>d16a16b16>c+16>d16>e16>f+16>g16>a16 >f+f+gf+e>e>f+>e>df+dba<a<g<a <bbc+ba<a<g<a<bbab>c+c+bc+ >d4d4a4<a4b4<b4f+4<f+4g4<g4d4<d4g4<g4a4<a.f+32a32>d2");
// Third verse: >f+df+a>e<age>d<bdf+>c+<f+ec+ b<g<bda<da<ab<gbd>c+<age
}
}
if (song == 4)
{
print("Bells");
if (button_is_pressed(BUTTON_B))
{
play("!T480 L8 cg>c");
wait_for_button_release(BUTTON_B);
delay_ms(500);
play("!T180 L8 b-<gab-g<gb-<fab-g<fb-<e-ab-g<e-b-<dab-g<d b-<gab-g<gb-<fab-g<fb-<e-ab-g<e-b-<dab-g<d >d<g>c>db-<g>d<f>c>db-<f>d<e->c>db-<e->d<d>c>db-<d >d<g>c>db-<g>d<f>c>db-<f>d<e->c>db-<e->d<d>c<db-<d >g<g>g16r16>g>f>e->d<f>d16r16>d>cb->c<e->c16r16>c>d>cb-<dg16r16g16r16g<d def+gab->c>d>c<db-<d def+gab->c>d>c<db-<d >b-r>a>b->g");
}
}
lcd_goto_xy(0,1);
print("<A ^B C>");
delay_ms(100);
if (song == 5)
{
song = 0;
}
if (song == -1)
{
song = 4;
}
if (button_is_pressed(BUTTON_C))
{
play("!T720 L8 >dr>d");
wait_for_button_release(BUTTON_C);
song++;
}
if (button_is_pressed(BUTTON_A))
{
play("!T720 L8 drd");
wait_for_button_release(BUTTON_A);
song = song-1;
}
}
}
while(button_is_pressed(BUTTON_B))
{
play("!T480 L8 ML >c>e>g>>c>>d>>e4");
wait_for_button_release(BUTTON_B);
clear();
unsigned int sensors[5]; // an array to hold sensor values
// set up the 3pi
initialize();
int dop = 0;
while(dop<20)
{
set_motors(5*dop, 5*dop);
dop++;
delay_ms(20);
}
while(1)
{
unsigned int position = read_line(sensors,IR_EMITTERS_ON);
if(position < 200)
{
set_motors(0,100);
}
else if(position < 300)
{
set_motors(5,100);
}
else if(position < 400)
{
set_motors(10,100);
}
else if(position < 800)
{
set_motors(20,100);
}
else if(position < 1200)
{
set_motors(40,100);
}
else if(position < 1600)
{
set_motors(60,100);
}
else if(position < 1800)
{
set_motors(80,100);
}
else if(position < 2000)
{
set_motors(90,100);
}
else if(position < 2300)
{
set_motors(95,100);
}
else if(position < 2700)
{
set_motors(100,100);
}
else if(position < 3000)
{
set_motors(100,95);
}
else if(position < 3400)
{
set_motors(100,90);
}
else if(position < 3600)
{
set_motors(100,80);
}
else if(position < 3800)
{
set_motors(100,60);
}
else if(position < 4200)
{
set_motors(100,30);
}
else if(position < 4600)
{
set_motors(100,20);
}
else if(position < 4700)
{
set_motors(100,10);
}
else if(position < 4800)
{
set_motors(100,5);
}
else if(position < 5000)
{
set_motors(100,0);
}
}
}
}
}