3Pi Problems

->> Hello, I have worked with the 3pi robot some time , and was using the Arduino program to program it, and remember it was not one of the newer versions , and one day the program crashed, could not use it anymore, then I installed a newer version and since then could not use it , the 3pi code remained the same , and since then has already two months or so, sending the same code , only with PID improvements ( competed with him in a local competition, I won ), to make the calibration of the sensors everything happens naturally and the bar graph correctly shows the working sensors, but when push to start , the robot does not follow the line (white on the case , has always been, and with black background ) , time walks with it, time is in black wandering randomly . Now as part of the tests by Arduino is rather hard to configure to use the 3pi , I am using atmel studio , and yet the error persists. Thank you.

arduino code

// The following libraries will be needed by this demo
#include <Pololu3pi.h>
#include <PololuQTRSensors.h>
#include <OrangutanMotors.h>
#include <OrangutanAnalog.h>
#include <OrangutanLEDs.h>
#include <OrangutanLCD.h>
#include <OrangutanPushbuttons.h>
#include <OrangutanBuzzer.h>
#include <millis.h>

Pololu3pi robot;
unsigned int sensors[5]; // an array to hold sensor values
unsigned int last_proportional = 0;
long integral = 0;

int inicial, tempo, tempovolta;

// 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.
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";

// 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 = {

// 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()
  OrangutanLCD::loadCustomCharacter(levels + 0, 0); // no offset, e.g. one bar
  OrangutanLCD::loadCustomCharacter(levels + 1, 1); // two bars
  OrangutanLCD::loadCustomCharacter(levels + 2, 2); // etc...
  OrangutanLCD::loadCustomCharacter(levels + 3, 3);
  OrangutanLCD::loadCustomCharacter(levels + 4, 4);
  OrangutanLCD::loadCustomCharacter(levels + 5, 5);
  OrangutanLCD::loadCustomCharacter(levels + 6, 6);
  OrangutanLCD::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.

// Initializes the 3pi, displays a welcome message, calibrates, and
// plays the initial music.  This function is automatically called
// by the Arduino framework at the start of program execution.
void setup()
  unsigned int counter; // used as a simple timer

  // 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.

  load_custom_characters(); // load the custom characters

  // Play welcome music and display a message
  OrangutanLCD::gotoXY(0, 1);

  OrangutanLCD::gotoXY(0, 1);

  // Display battery voltage and wait for button press
  while (!OrangutanPushbuttons::isPressed(BUTTON_B))
    int bat = OrangutanAnalog::readBatteryMillivolts();

    OrangutanLCD::gotoXY(0, 1);
    OrangutanLCD::print("Press B");


  // Always wait for the button to be released so that 3pi doesn't
  // start moving until your hand is away from it.

  // Auto-calibration: turn right and left while calibrating the
  // sensors.
  for (counter=0; counter<80; counter++)
    if (counter < 20 || counter >= 60)
      OrangutanMotors::setSpeeds(40, -40);
      OrangutanMotors::setSpeeds(-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.

    // Since our counter runs to 80, the total delay will be
    // 80*20 = 1600 ms.
  OrangutanMotors::setSpeeds(0, 0);

  // Display calibrated values as a bar graph.
  while (!OrangutanPushbuttons::isPressed(BUTTON_B))
    // Read the sensor values and get the position measurement.
    unsigned int position = robot.readLine(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.
    OrangutanLCD::gotoXY(0, 1);



  OrangutanLCD::gotoXY(0, 1);

  // Play music and wait for it to finish before we start driving.

// The main function.  This function is repeatedly called by
// the Arduino framework.
void loop()
  tempo = millis();
  tempovolta = tempo-inicial;
  // Get the position of the line.  Note that we *must* provide
  // the "sensors" argument to read_line() here, even though we
  // are not interested in the individual sensor readings.
  unsigned int position = robot.readLine(sensors, IR_EMITTERS_ON);

  // The "proportional" term should be 0 when we are on the line.
  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.  If it is a negative number, the robot will
  // turn to the left, and the magnitude of the number determines
  // the sharpness of the turn.  You can adjust the constants by which
  // the proportional, integral, and derivative terms are multiplied to
  // improve performance.
  int power_difference = proportional/7 + derivative*4; 
  // int power_difference = proportional/20 + integral/10000 + derivative*3/7 p 100                          lento demais
  // proportional/7 + derivative*4  p 220                                                                    time_lap = 9.5s
  // proportional/20 + integral/10000 + derivative*10 p 250                                                  time_lap = 9.3s
  // proportional/10 + integral/20000 + derivative*6  p 250                                                  time_lap = 8.1s
  // proportional/10 + integral/20000 + derivative*7  p 250                                                  time_lap = 8.0s
  // proportional/10 + integral/20000 + derivative*8  p 250                                                  time_lap = 8.0s
  // proportional/10 + integral/30000 + derivative*9  p 250                                                  time_lap = 8.1s
  // Compute the actual motor settings.  We never set either motor
  // to a negative value.
  const int maximum = 220;
  if (power_difference > maximum)
    power_difference = maximum;
  if (power_difference < -maximum)
    power_difference = -maximum;

  if (power_difference < 0)
    OrangutanMotors::setSpeeds(maximum + power_difference, maximum);
    OrangutanMotors::setSpeeds(maximum, maximum - power_difference);

  //while( tempovolta >= 10000){
    //OrangutanMotors::setSpeeds(0, 0);


It was hard to follow your post, but it sounds like the line following code you currently have on your 3pi is not working well and you want to reprogram it. Is that correct?

Are you currently using the Arduino IDE or Atmel Studio to program it? Do you get any error messages during programming?

If you are using the Arduino IDE, I recommend reading the guide for programming the 3pi from the Arduino IDE which was recently updated. If you are using a new version, you will probably need to follow the updated instructions in the guide to reconfigure your Arduino IDE.


[PROBLEM SOLVED] It looks like the problem was in the Arduino IDE, now i’m using Atmel studio, and all works fine!! Thank you guys


I’m glad you got it working. Thanks for letting us know.