Line Following Robot with Arduino Shield


Here is a fairly basic robot application that implements a line following algorithm. This application uses off the shelf components along with a very basic chassis built from common materials. This could be a good weekend project. The Line-Follower chassis for this Demo was constructed with 2½” wide by ¼” thick poplar project wood purchased at a local home improvement center. Note that a box was also created to house the battery holder.



The Arduino Motor Shield is mounted to a chipKIT Uno32 Development Platform with all component connections made to the shield as indicated in labels next to component.  


The line following robot is programmed to basically avoid the color black. If both sensors see black, then the robot will back up until it no longer sees black. If one sensor sees black, then the robot will turn in the direction of that sensor until it no longer sees black. Other than that, if the robot doesn’t see black on either sensor, it will simply move for- ward. In this application, the black line is created using common electrical tape. The logic for this algorithm is shown below along with a graphical representation of the front of the line following bot for reference.  


 Marc McComb

The line following robot is programmed to basically avoid the color black. If both sensors see black, 
then the robot will back up until it no longer sees black. If one sensor sees black, then the robot will
turn in the direction of that sensor until it no longer see black. Other than that, if the robot doesn’t 
see black on either sensor, it will simply move forward. In this application, the black line is created 
using common electrical tape. 

This application uses the following hardware:
chipKITâ„¢ Uno32 available at 
Arduino Motor Shield available at: 
Sparkfun QRE1113 Line Sensor Board- Analog(Item #: ROB-09453) 

Software used:
The Aruino Motor shield is designed for a PWM on pin 11. Since the Uno32 doesn't have a hardware PWM 
on that pin, no worries, we just use Brian Schmaltzs SoftPWMServo library: 

You will need to make sure that you add the library. To do this:
1) Make sure that you have a folder in your Documents:/MPIDE folder called Libraries
2) Copy the SoftPWMServo library folder from C:\mpide-0023-windows-20120903\hardware\pic32\libraries 
    to the Libraries folder above
3) If MPIDE is open, close and reopen. 
4) Now all you have to do is go to the MPIDE toolbar and select Sketch>Import Library>SoftPWMServo

More info on libraries at:


#include <SoftPWMServo.h>

//Setting up the Hardware pins
// First the line following (IR) sensors
const int irLeft = 2; //Left line sensor is on pin A2
const int irRight = 3; //Right line sensor is on pin A3

//Setting up the Arduino Motor Shield
const int leftDIR = 12; 
const int rightDIR = 13;
const int leftPWM = 3;
const int rightPWM = 11;
const int leftBrake = 9;
const int rightBrake = 8;
const char bothSpeed = 100; //sets how fast the motors will spin (0 to 255)

//Here we set up variable that will hold the ADC value representing the line sensor values
int leftSees = 0; //A2 ADC value (0 to 1023)
int rightSees = 0; //A3 ADC value (0 to 1023)

void setup() 

  //Make sure to set all of our control signal pins as output
  pinMode(leftDIR, OUTPUT); 
  pinMode(rightDIR, OUTPUT); 
  pinMode(leftBrake, OUTPUT); 
  pinMode(rightBrake, OUTPUT); 

  //Next we make sure our brake signals are set LOW
  digitalWrite(leftBrake, LOW);
  digitalWrite(rightBrake, LOW);

void loop() 
    //Start by reading the left sensor on A2
  int leftEye = analogRead(irLeft);

  //delay a little bit

  //next read the right sensor connected A3
  int rightEye = analogRead(irRight);

  //Next, we run the motors based on the sensor reading

  //If both sensors see black (ADC value greater than 1000), then back up
  if ((leftEye >= 1000)&&(rightEye >= 1000)) reverse();

  //Otherwise, if only the left sensor sees black, then turn off the left motor
  //so the robot veer to the left
  else if ((leftEye >= 1000)&&(rightEye < 1000)) turnLeft();

  //Otherwise, if only the right sensor sees black, then turn off the right motor
  //so the robot veer to the right
  else if ((leftEye < 1000)&&(rightEye >= 1000)) turnRight();

  //Otherwise, move forward
  else forward();


//Turn right by turning off the right motor 
//i.e disable the PWM to that wheel
void turnRight(void)
  digitalWrite(leftDIR, HIGH); 
  digitalWrite(rightDIR, HIGH);
  SoftPWMServoPWMWrite(leftPWM, bothSpeed);
  SoftPWMServoPWMWrite(rightPWM, 0);

//Turn left by turning off the left motor
//i.e disable the PWM to that wheel
void turnLeft(void)
  digitalWrite(leftDIR, HIGH); 
  digitalWrite(rightDIR, HIGH);
  SoftPWMServoPWMWrite(leftPWM, 0);
  SoftPWMServoPWMWrite(rightPWM, bothSpeed);

//Move forward by enabling both wheels
void forward(void)
  digitalWrite(leftDIR, HIGH); 
  digitalWrite(rightDIR, HIGH);
  SoftPWMServoPWMWrite(leftPWM, bothSpeed);
  SoftPWMServoPWMWrite(rightPWM, bothSpeed);

//Reverse by enabling both wheels 
void reverse(void)
  digitalWrite(leftDIR, LOW); 
  digitalWrite(rightDIR, LOW);
  SoftPWMServoPWMWrite(leftPWM, bothSpeed);
  SoftPWMServoPWMWrite(rightPWM, bothSpeed);
VN:F [1.9.22_1171]
Rating: 6.9/10 (27 votes cast)
VN:F [1.9.22_1171]
Rating: +2 (from 2 votes)

chipKIT Software SPI Library

This article on chipKIT software SPI library is written by Gene Apperson, Digilent Inc.

At Digilent we have been working to extend the chipKIT software framework beyond its original Arduino-inspired roots. Recent enhancements enable the framework to be used with many different systems based on PIC32 MCUs. In order to support arbitrary hardware configurations, we implemented a general-purpose Serial Peripheral Interface (SPI) library that does not rely on dedicated hardware peripherals. The Software SPI (SoftSPI) library allows the creation of any number of software based (bit-banged) SPI ports.

Serial Peripheral Interface (SPI) is a four wire synchronous serial interface used by many integrated circuits and electronic devices. SPI devices can operate as either master slave devices. The four SPI signals are generally referred to as Slave Select (SS), Master Out, Slave In (MOSI), Master In, Slave Out (MISO), and Serial Clock (SCK). A master device generates SS, MOSI and SCK, and receives MISO. A slave device receives SS, MOSI, and SCK and generates MISO. The SS signal is used to enable the slave device, and this signal is only significant for slave devices. A master device can use any general purpose I/O pin to generate SS to enable a slave.

The SoftSPI library only supports operation as an SPI master device.

An SPI transaction begins with the master device bringing SS low. When the slave sees SS go low it becomes enabled and waits for the master to send data. The master shifts data out on MOSI and simultaneously shifts data in on MISO. The slave device receives data from the master on its MOSI pin and simultaneously sends data to the master on its MISO pin. Each time the master sends a byte to the slave, it simultaneously receives a byte from the slave. The master generates the clock signal (SCK) that is used to control the shifting of the data in both the master and the slave.

SPI devices can operate using one of four data transfer modes, and one of two shift directions. The transfer modes specify the idle state of the clock signal (idles high or idles low) the active edge of the clock, and the phase relationship between the active edge of the clock signal and the data. The modes are generally called mode 0 through mode 3. The shift direction specifies whether the data is shifted most significant bit first (shift left), or least significant bit first (shift right). The SoftSPI library header file defines symbols used to specify the transfer mode and shift direction. Refer to documentation for the SPI slave device being used to determine the transfer mode and shift direction to use. Most SPI devices use mode 0 with shift left.

The SoftSPI library defines an object class (SoftSPI) that is used to create a separate object instance for each desired SPI port. Each instance of the SoftSPI object class uses four specified digital pins for the SPI signals. The SoftSPI object class supports all four transfer modes, both shift directions, and setting the frequency of the clock signal.

To use the SoftSPI library, an object instance variable of the SoftSPI object class must be created:

/* Declare an instance of the SPI interface object */
SoftSPI    spi;

The object instance is initialized using functions to set mode, shift direction and clock speed. In this example, a 6uS delay between bytes is specified to accommodate a joystick peripheral:

/* Define digital pins for the SoftSPI port to use*/
#define  pinSS    24
#define  pinMOSI  25
#define  pinMISO  26
#define  pinSCK   27

/* Initialize the SPI port */
spi.begin(pinSS, pinMOSI, pinMISO, pinSCK);
spi.setDelay(6);  /* delay 6uS between bytes */

Data can then be transferred to a slave device by calling the various data transfer functions. This example communicates with Digilent’s PmodJSTK peripheral:

uint8_t    rgbSnd[5];
uint8_t    rgbRcv[5];
int      ib;
/* Initialize the transmit buffer */
for (ib = 0; ib < 5; ib++) {
rgbSnd[ib] = 0x50 + ib;
rgbSnd[0] = fbLedPmod + 0x80;  // First byte sets the LEDs

/* Bring SS low to begin the transaction */

/* Wait 10us for Pmod to become ready */

/* Send the data to the Pmod and get the response */
spi.transfer(5, rgbSnd, rgbRcv);

/* Bring SS high to end the transaction */
The SoftSPI Library is included with versions of the Multi-Platform IDE (MPIDE) dated 12/15/2011 or later. Complete documentation is available here.
VN:F [1.9.22_1171]
Rating: 10.0/10 (2 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Debouncing a Pushbutton


A pushbutton is a Mechanical Switch. Switches play an important and extensive role in practically every computer, microprocessor and microcontroller application. Mechanical switches are inexpensive, simple and reliable. However, switches can be very noisy electrically. When a switch, such as a pushbutton is pressed, the connection actually makes and breaks several, perhaps even hundreds, of times before the final switch state settles. The problem is known as switch bounce.

The consequences of uncorrected switch bounce can range from being just annoying to catastrophic.

A software technique called “Debouncing” is one way to solve this problem. Here’s how it works:

Usually, the switch is connected to a pin on the Microcontroller so that it maintains either a HIGH or LOW condition when the switch is open (not pressed). If the switch closes (is pressed) then that condition will change. The Microcontroller detects that change. Instead of reacting right away, the Microcontroller will wait a period of time, say 5 mS, to give the switch a chance to stop bouncing and then checks that pin again. If the pin still reads that the switch is closed, then the Microcontroller will do something about it.

In this tutorial, a pushbutton press (BTN1) will trigger LD1 to light. Otherwise, LD1 will be OFF.



This tutorial introduces the if/else statement. This type of statement gives your sketch the ability to make decisions based on conditions occurring outside of the Microcontroller or as a result of some sort of internal condition such as the result of some mathematical operation.

We recommend you read the following before proceeding:


Hardware Used:

The hardware used in this tutorial will be the chipKIT uC32 along with a chipKIT Basic I/O Shield both manufactured by Digilent Inc. The reference guide for each board, schematics and other resources are available on their individual homepages:



  1. Create a new sketch in MPIDE.
  2. Save the sketch with a meaningful name.
  3. Add the following code to your new sketch:
    int ledPin = 26;   // LED connected to digital pin 26
    int pbPin = 4;   //pushbutton BTN1 connected to digital pin 4
    int pbState = LOW; //this variable will hold the value or state of BTN1
                       // i.e. if not pressed, pbState = LOW, if pressed, pbState = HIGH
    void setup()
      pinMode(ledPin, OUTPUT);   // sets the digital pin 26 as output
      pinMode(pbPin, INPUT); //sets digital pin 4 as input
      digitalWrite(ledPin, LOW); //make sure LD1 is OFF
    void loop()
      pbState = digitalRead(pbPin); //read the value, HIGH or LOW, on the pushbutton pin
      if (pbState == HIGH) //is pbState HIGH indicating BTN1 is pressed??
      //if yes, do the code inside the curly braces. This is the debounce section
        delay(5); //wait 5 mS for any pushbutton bounce to disappear
        pbState = digitalRead(pbPin); //read the value on the pushbutton pin again
        if(pbState == HIGH) //is it still HIGH (pressed)
          digitalWrite(ledPin, HIGH); //Light LD1>
          digitalWrite(ledPin, LOW); //keep LD1 OFF
  4. In the MPIDE, verify that the chipKIT uC32 and the associated communication port are selected.
  5. Upload the code to the chipKIT Board.

Verifying Operation

After the sketch is sent to the chipKIT uC32 board’s Microcontroller, LED 1 (LD1) on the chipKIT Basic I/O Shield should light when pushbutton BTN1 is pressed.

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Changing PWM frequency and bit resolution


You have to bypass the analogWrite function in the abstraction layer and talk directly to the hardware to do this. You will need to program one of the timers, and one or more of the output compares to do this. The Output Compare units in the PIC32 can work from either Timer2 or Timer3. The analogWrite code uses Timer2. If you don’t need analogWrite to work, I would use Timer2. If you need analogWrite to work as well, use Timer3. The Output Compare sets the pin when the timer resets. The timer then counts up from 0. The Output Compare resets the pin when the the value in the timer matches the value in the ouput compare register. The counter continues to count up until the count value matches the value in the period register. The timer then resets and it all starts over again. Also at the end of a period the contents of the duty cycle buffer register(OCxRS) is loaded into the duty cycle register(OCxR). The frequency of the resulting PWM signal is determined by the clock speed of the timer, and the value in the period register. The clock speed of the timer is determined by the peripheral bus frequency and the prescaler selected. The peripheral bus frequency is 80 MHz (at least this is the default set by the boot loader). The prescaler can be selected to be 1:1, 1:2, 1:4, up to 1:256. So for example, with a 1:8 prescaler selected, the 80 MHz would be divided down to 10 MHz and that is the timer clock frequency (i.e. the timer counts up 1 every 100ns). The value in the period register determines when the counter resets. So, for example if you set the period register to 10000, you would get a reset at 10000*100ns, or every 1 ms. This is a frequency of 1 kHz. To get a 12-bit PWM, you could load the period register with 4096 (2^12). With the 1:8 prescaler, this would give a frequency of about 2.4 kHz.


The following code will initialize Timer2 with the 1:8 prescaler and a period value of 4096
T2CONCLR = T2_ON          // Turn the timer off
T2CON = T2_PS_1_8;        // Set prescaler
TMR2 = 0;                 // Clear the counter
PR2 = 4096;               // Set the period
T2CONSET = T2_ON;         // Turn the timer on
The following code will set output compare 1 to use Timer2 and a PWM value that would give a 50% duty cycle.
OC1R = 2048;              // Load initial value into duty cycle register
OC1RS = 2048;             // When a period finishes the contents of OC1RS is loaded to OC1R
OC1CON = OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE; // Set Timer2 as source | enable pwm mode without fault protection
This example code is taken (and slightly modified) from the code for analogWrite. This is in the file wiring_analog.c in the core files. These statements are all writing directly to the peripheral registers for Timer2 and Output Compare 1. For more complete details, you should refer to the Timer and Output Compare sections of the PIC32 Family Reference Manual that can be downloaded from the Microchip web site.
VN:F [1.9.22_1171]
Rating: 6.6/10 (9 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Debugging with ejtagproxy and GDB

Debugging without MPLAB is possible through ejtagproxy. You need a compatible ICSP adapter, like PICkit2 or PICkit3 (full list of compatible adapters is available on project homepage). Note that you can’t use PICkit2 with MPLAB, but it works with ejtagproxy. Obtain source, build. Obtain stock GDB source. Configure with –target=mipsel-elf32 . Build. Start ejtagproxy:
$ ejtagproxy
GDB proxy for Microchip PIC32 processors, Version 1.0.25
Copyright (C) 2012 Serge Vakulenko

EJTAGproxy comes with ABSOLUTELY NO WARRANTY; for details
use `--warranty' option. This is Open Source software. You are
welcome to redistribute it under certain conditions. Use the
'--copying' option for details.
ejtagproxy: waiting on TCP port 2000
Start GDB and point it to ELF file of your application:
$ pic32-gdb ~/repos/chipKIT-minimal-application/src/main.elf
Set the target to ejtagproxy:
(gdb) target remote localhost:2000
You should notice that ICSP adapter is now connected to target board. On my chipKIT Max32 this also results in board reset. The ejtagproxy willl print something like:
adapter: PICkit2 Version 2.32.0
processor: Microchip PIC32MX795F512L
processor: reset occured
hardware: 6 breakpoints, 2 watchpoints
oscillator: internal Fast RC
And GDB will connect to target:
Remote debugging using localhost:2000
0xbfc00000 in ?? ()
Now you can set breakpoints, watchpoints, etc. and run the application.
(gdb) break main
Breakpoint 1 at 0x9d00136c: file main.c, line 12.
(gdb) c
Unfortunately, when ejtagproxy is connected to target board everything is much slower than normally, so you have to wait a moment…
Breakpoint 1, main () at main.c:12

12			loop();
As you can see breakpoint was successfully activated in main() function. Now it’s possible to do further analysis:
(gdb) i reg
         zero       at       v0       v1       a0       a1       a2       a3
R0   00000000 ffbfffff ffffffff ffffffff 00000000 00000000 a000001c bf800000 
           t0       t1       t2       t3       t4       t5       t6       t7
R8   9d0011f0 00000000 00000020 04000000 00000000 00000000 00000000 00000000 
           s0       s1       s2       s3       s4       s5       s6       s7
R16  00000000 00100000 00000000 00000000 00000000 00000002 00000000 00000000 
           t8       t9       k0       k1       gp       sp       s8       ra
R24  00000000 00000000 00000000 00000000 a00081f0 a001ffe8 a001ffe8 9d001208 
           sr       lo       hi      bad    cause       pc
     00100000 00000019 00000001 cc37facd a0800034 9d00136c 
          fsr      fir
     can't read register 160 (fsr)
(gdb) disassemble 
Dump of assembler code for function main:
  0x9d00135c <+0>:	addiu	sp,sp,-24
  0x9d001360 <+4>:	sw	ra,20(sp)
  0x9d001364 <+8>:	sw	s8,16(sp)
  0x9d001368 <+12>:	move	s8,sp
=> 0x9d00136c <+16>:	jal	0x9d001328 <loop>
  0x9d001370 <+20>:	nop
  0x9d001374 <+24>:	j	0x9d00136c <main+16>
  0x9d001378 <+28>:	nop
End of assembler dump.
(gdb) stepi
loop () at main.c:1
1	void loop(void) {
(gdb) disassemble 
Dump of assembler code for function loop:
=> 0x9d001328 <+0>:	addiu	sp,sp,-16
  0x9d00132c <+4>:	sw	s8,12(sp)
  0x9d001330 <+8>:	move	s8,sp
  0x9d001334 <+12>:	li	v0,1
  0x9d001338 <+16>:	sw	v0,0(s8)
  0x9d00133c <+20>:	lw	v0,4(s8)
  0x9d001340 <+24>:	addiu	v0,v0,2
  0x9d001344 <+28>:	sw	v0,4(s8)
  0x9d001348 <+32>:	move	sp,s8
  0x9d00134c <+36>:	lw	s8,12(sp)
  0x9d001350 <+40>:	addiu	sp,sp,16
  0x9d001354 <+44>:	jr	ra
  0x9d001358 <+48>:	nop
End of assembler dump.
VN:F [1.9.22_1171]
Rating: 8.0/10 (1 vote cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Programming Microchip starter kits from MPIDE

Running on Microchip Starter Kits

MPIDE has been expanded explicitly to support all of the Microchip starter kits such as:
  • PIC32 Starter Kit
  • PIC32 USB Starter Kit
  • PIC32 Ethernet Starter Kit
  • Explorer 16 Starter Kit
Currently for all of these boards you will need some sort of USB to serial adapter. For all but the Exp-16 I use an FTDI cable that breaks out to pins. I connect those to pins on the expansion board for uart1. The PIC32 USB Starter Kit and PIC32 Ethernet Starter Kits are also compatible with the USB PIC32 bootloader. The Explorer-16 has an on-board DB-9 RS-232 connector. This is connected to UART2. The bootloader is configured to use UART2 for the Explorer-16 and the Serial ports for Arduino are remapped so that Serial.print goes to uart2 and Serial1.print goes to uart1. This is all done automatically so the user does not have to worry about it at all. In order to install the bootloader on any of these boards, you have to have one of the Microchip compatible programmers such as the MPLAB ICD 3 or PICkit 3. Ideally you should download MPLAB X IDE from microchip ( and use that to compile and burn the bootloader. The bootloader source and pre-compiled hex files are all on github. (

Using other PIC32 boards

As far as using MPIDE with other boards, the answer is YES, it should work with ANY PIC32 there is. The only limit might be it won’t work on chips smaller than 32K, And that’s because it hasn’t been tried on anything smaller. To get it to work on other boards, a few things have be be done.
  • First, the bootloader has to be burned onto the target board. The source is on github and MPLAB is used to compile and burn the bootloader. The multi-platform MPLAB-X was used on a Mac, but other versions should work as well.
  • If you using a chip that has not already been added to avrdude.conf, that has to be done.
  • You need to add a new entry to boards.txt and then you will be able to program the board directly from MPIDE.
VN:F [1.9.22_1171]
Rating: 10.0/10 (1 vote cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Running StickOS BASIC on a chipKIT board

Have you ever wished you could examine and manipulate the pins and peripherals of your MCU *interactively*, while it was live and connected to your embedded circuit, rather than using just “reset and run” debugging? If so, StickOS BASIC may be for you! With StickOS BASIC, you can log in to your MCU using nothing but a terminal emulator, and then take full control of the MCU from a command-line, just as if you had an In-Circuit Emulator. StickOS can run either in “slave” mode, tethered to and controlled by a host computer as a glorified intelligent I/O port, or it can run in “master” mode, programmed in BASIC, interactively debugged, and even configured to autorun its BASIC program autonomously. In StickOS BASIC, it is trivial to examine and manipulate I/O pins. I/O pins can be configured for digital input or output, analog input or output, servo output, or frequency output. Once a pin is configured, it can be bound to a BASIC variable, and from then on, examining or manipulating the pin is as simple as examining or manipulating the bound variable. For example, to configure pin 3 for servo output, bind it to the variable “motor1”, and then set it up for a 1ms (1000us) PWM pulse width is as easy as (interactively, at the command-line, or in a program):
    > dim motor1 as pin 3 for servo output
    > let motor1=1000
    > _
In StickOS BASIC, it is equally trivial to use timers, UARTs, advanced I2C or SPI peripherals, as well as HD44780-compatible LCDs and simple scanned keypads. And most importantly, it can all be done interactively — no more guessing what your MCU is up to! The StickOS debugger supports command-line program interruption, breakpoints, assertions, watchpoints, live variable (and pin) manipulation and examination, execution tracing and single-stepping, sampling profiling, and even edit-and-continue! When you’re ready to move up, you can then port your BASIC program to C using the MPLAB X StickOS Skeleton project, and take advantage of all the same pin/peripheral configuration, flash manipulation, etc., used by StickOS BASIC. A detailed introduction to StickOS on the chipKIT boards is here: An overview of the StickOS BASIC language features is in the Quick Reference guide, here: More information and downloads for the chipKIT boards are available here:
VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)