Blog Entry




Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

May 25, 2009 by , under Robotics.




Have you ever thought that most of our perception about the robot is based on the Hollywood movie! The famous 3CPO and R2D2 from Star Wars until the little cute garbage compacting robot named WALL-E; all of these machines are example of our dreams or should I say our quest to what we all think about the robot should be. Although the robot that we are going to build here is still far away from the technologies shown on those movies but at least it will give you an introductory to the robotics world. On this tutorial we will build BRAM which stand for Beginner’s Robot Autonomous Mobile, BRAM construction is designed to be easily built using some of the parts that you could easily found at home, this time we will use Microchip 8-Bits midrange PIC16F690 microcontroller as the BRAM’s brain.

Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

The first autonomous mobile robot is built by William Grey Walter around 1950 at the Burden Neurological Institute in Bristol as part of his research to model brain’s neuron. He built these three wheels robots named ELMER and ELSIE (Electro Mechanical Robot, Light Sensitive) which consists of just two electronic vacuum tubes that represent a simple 2 neurons, remember on those days transistors is just in their earlier stages; these two tube work as two stage amplifier to control a relays that connected to the two DC motors for the robot steering and locomotion.

The steering motor also connected to the photoelectric cell tube sensor and only rotates in one direction. On the dark environment the steering and the driving motor will turn slowly; when the photoelectric cell capture a bright enough light, the steering motor will stop rotate (relay 1 on) and the robot move toward it (light attracted). When the light becomes too bright, the steering motor starts to rotate (relay 2 on) and the robot simply turn away from the light (light avoided). The touch sensor switch is connected to the clear plastic shell (that’s why it’s being called tortoise, because it looks like a tortoise shell) that covered the robot’s body. When the shell bumped to the object, the two stages amplifier will start to oscillate because of the feedback signal generated by the closed touch switch until the robot successfully avoid the obstacle.

Using just a simple electronics neurons model, William Grey Walker is able to show a complex behavior caused by the combination of stimulus (sensors) and the interaction between these two electronics neuron. His works later on inspired many young generation roboticists such as Rodney A. Brooks (subsumption architecture) and Mark Tilden (BEAM) who pioneering a new approach to the robot’s artificial intelligent or known as the nature behavior based artificial intelligent.

Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

BRAM Chassis Construction

BRAM chassis use two CDs, the lower deck is use to hold the geared DC motor, battery power, caster and the robot’s bumper switches (whiskers) while the upper deck hold the robot’s motor driver, sensor’s board and the PICJazz 16F690 board. The following are the list of BRAM’s construction material parts:

  • Two CD/DVDs for the chassis
  • Two geared DC motor rated 4.5 to 5 volt with the wheel or you could use the modified servo motor (it’s a servo motor without the electronics’s control board)
  • One 3 x 1.5 volt AA battery holder with on-off switch
  • One plastic bead (usually it use for the neck less) and one paper clip for the caster
  • Two microswitches and two paper clips for the whisker or bumpers sensor (not shown on the above picture).
  • Nuts, bolts, PCB (printed circuit board) holders, double tape to hold all of these parts together.

Through these series of the pictures bellow you will get an idea of how to assemble BRAM’s parts; the first two picture show you how to assemble the BRAM’s caster and whisker:

Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

From the above picture you could see that I use a solder’s thin to join the modified paper clip to a microswitch actuator arm; make sure you clean both surfaces with the sand paper first before start soldering them together. What good about the BRAM’s chassis material; its easy to drill (made from polycarbonate plastic) and I bet you have plenty of these unused CD/DVD’s at home or if not just buy a new blank CDs. Bellow is the BRAM’s design drawing I used on this tutorial.

Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

The next two pictures show you how to put all these parts together to the BRAM’s chassis.

Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

BRAM’s Electronic Circuit and Program

What make building the robot is an art; because building a robot is the combination of mechanic, electronic and programming skills, those skills must also be combined with the system control and artificial intelligence knowledge to make a robust and intelligent robot; therefore many years ago this kind of capabilities only reside inside the university labs or highly budget research company.

Today’s with the introduction of cheap sophisticated microcontrollers and sensors the possibility of the amateur roboticists to build an entertaining or perhaps professional robots become widely open; especially with the introduction to the nature base artificial intelligent pioneered by Rodney A. Brooks and Mike Tilden which open a new approach to the mobile robot’s artificial intelligent, programming mobile robot become a reach of amateur roboticists.

Their approach actually is base on the simple question, why such as simple animal likes ant or cockroach could survive in such a very complex nature environment and yet not required a very complex brain? The answer to this question is; because this little creatures use what its called nature behavior based intelligent; unlike the classic approach to artificial intelligent which required a powerful computing power, this new approach make it possible for us to implement it on the 8-bit class microcontroller such as Microchip PIC16F690 microcontroller. This behavior based artificial intelligent model is simply tell us that we develop the robot’s behavior start from the very primitive form such as obstacle avoidance and slowly added a new more complex behavior on top of it.

Now take a look at the BRAM’s electronic circuit schematic bellow (for complete schematic of PICJazz 16F690 learning board you could download here and BRAM’s motor controller you could download here):

The DC geared motor is controlled by the two channels SGS-Thomson L293D motor driver chips, this chip is used to make circuit more simpler compared to the standard transistor’s base H-Bridge driver, the L293D chip is able to handle non repetitive current up to 1.2 A for each channels and its already equipped with the internal EMF (Electromotive Force) protection diodes.

The L293D enable input (ENABLE1 and ENABLE2) for both channels is controlled by PWM (Pulse Width Modulation) supplied by the PIC16F690 microcontroller RC3 port which configured as single output PWM , pulse steering mode. For more information about the PIC PWM please refer to my previous posted blog H-Bridge Microchip PIC Microcontroller PWM Motor Controller. The PWM width is controlled by user trimport attached to RA0 port, this make BRAM’s speed could be adjusted (faster or slower) by adjusting this 10K trimport.

Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

The LDR (Light Dependent Resistor) is use as light sensor, together with the 10K trimport works as the voltage divider circuit to the RC0 and RC1 ADC (Analog to Digital Converter) ports; the voltage supplied to this input will vary according to the light intensity, for more information of how this circuit work please refer to my previous posted blog Basic Servo Motor Controlling with Microchip PIC Microcontroller.

Using the well known R-2R ladder resistor circuit, BRAM’s use this simple 2-bits DAC (Digital to Analog Converter) circuit to read the two bumper switches (whiskers) through the PIC 16F690 microcontroller RC2 ADC port. For more information about the R-2R ladder circuit please refer to my previous posted blog Basic Resistor Circuit. There are two reasons why I am using the DAC circuit to read the switches. The first one, because I am using the output not just for reading the switch status but also use the value to generate random number for the avoidance behavior algorithm, the second one is; I could use just a single ADC microcontroller’s port to read many switches at the same time.

The following is the list of hardware and software used in this tutorial:

  • Resistors: 220 Ohm (1), 1K (1), 15K (1), 10 K (2)
  • Two LDR (Light Dependent Resistor)
  • Two Trimports: 10K
  • One White LED for BRAM’s Head Light
  • Two Microswitches for the bumper sensors (whikers)
  • One Transistor: 2N3904
  • PICJazz 16F690 learning board (schematic) from ermicro (build in one user’s trimport and one user’s switch)
  • Microchip PICKit2 Programmer
  • Microchip MPLAB IDE v8.3 or higher
  • HI-TECH C PRO for the PIC10/12/16 MCU family V9.60PL5 (Lite).

Now let’s take a look at the C code that make the BRAM’s brain:

// *****************************************************************************
//  File Name    : brampicphoto.c
//  Version      : 1.0
//  Description  : BRAM - Beginner's Robot Autonomous Mobile
//                 PIC Photovore I
//  Author       : RWB
//  Target       : PICJazz 16F690 Learning Board
//  Compiler     : HI-TECH C PRO for the PIC10/12/16 MCU family V9.60PL5 (Lite)
//  IDE          : Microchip MPLAB IDE v8.30
//  Programmer   : PICKit 2
//  Last Updated : 05 May 2009
// *****************************************************************************
#include <pic.h>
#include <stdlib.h>
#include <stdio.h>
/*   PIC Configuration Bit:
**   INTIO     - Using Internal RC No Clock
**   WDTDIS    - Wacthdog Timer Disable
**   PWRTEN    - Power Up Timer Enable
**   MCLREN    - Master Clear Enable
**   UNPROTECT - Code Un-Protect
**   UNPROTECT - Data EEPROM Read Un-Protect
**   BORDIS    - Borwn Out Detect Disable
**   IESODIS   - Internal External Switch Over Mode Disable
**   FCMDIS    - Monitor Clock Fail Safe Disable
*/
__CONFIG(INTIO & WDTDIS & PWRTEN & MCLREN & UNPROTECT \
  & UNPROTECT & BORDIS & IESODIS & FCMDIS);
// Using Internal Clock of 8 MHz
#define FOSC 8000000L
// Define Light Parameter
#define LIGHT_THRESHOLD  30
#define THRESHOLD_VALUE  50
#define MAX_THRESHOLD    180
// Define BRAM Steering
#define MOVE_FORWARD  0
#define TURN_LEFT     1
#define TURN_RIGHT    2
#define ROTATE_LEFT   3
#define ROTATE_RIGHT  4
#define MOVE_BACKWARD 5
#define FULL_STOP     6
// BRAM Debugging Mode, 0 - Debug Off, 1 - Debug On
#define BRAM_DEBUG    1
#if BRAM_DEBUG
  #define BAUD_RATE 9600
#endif
// Delay Function
#define	_delay_us(x) { unsigned char us; \
			         us = (x)/(12000000/FOSC)|1; \
			         while(--us != 0) continue; }
void _delay_ms(unsigned int ms)
{
  unsigned char i;
  do {
    i = 4;
    do {
      _delay_us(164);
    } while(--i);
  } while(--ms);
}
// BRAM UART Debugging Function
#if BRAM_DEBUG
void ansi_cl(void)
{
  // ANSI clear screen: cl=\E[H\E[J
  putchar(27);
  putchar('[');
  putchar('H');
  putchar(27);
  putchar('[');
  putchar('J');
}
void ansi_me(void)
{
  // ANSI turn off all attribute: me=\E[0m
  putchar(27);
  putchar('[');
  putchar('0');
  putchar('m');
}
void uart_init(void)
{
  TRISB5 = 1;          // Set Port B5 and B7 for UART Tx and Rx
  TRISB7 = 0;
  // Baud Rate formula for SYNC=0 (Async), BRG16=0 (8-bit), BRGH=0 (low speed)
  // 0.16% Error for 8 MHz Oscilator Clock. Actual Rate will be 9615.
  // BAUD_RATE = FOSC / (64 x (SPBRG + 1)) 

  SPBRG = (int)(FOSC/(64UL * BAUD_RATE)) - 1;
  TXSTA = 0b00100000;  // Async, 8 bit and Enable Transmit (TXEN=1)
  RCSTA = 0b10010000;  // Serial Port Enable, Async,8-bit and Enable Receipt (CREN=1)
  BAUDCTL=0;
}
void putch(unsigned char data)
{
  // Send Data when TXIF bit is ready
  while(!TXIF) continue;
  TXREG = data;
}
unsigned char getch(void) {
  // Get Data when RCIF bit is ready
  while(!RCIF) continue;
  return RCREG;
}
#endif
// BRAM Speed and Steering Functions
void BRAM_speed(unsigned char sp)
{
  // Adjust the PWM CCPR1L register
  CCPR1L=sp;
}
void BRAM_steer(unsigned char steer)
{
  switch(steer) {
    case MOVE_FORWARD:
      RC4=0; RC5=1;  // Right Motor On Forward
      RC6=1; RC7=0;  // Left Motor On Forward
      break;
    case TURN_LEFT:
      RC4=0; RC5=1;  // Right Motor On Forward
      RC6=0; RC7=0;  // Left Motor Off
      break;
    case TURN_RIGHT:
      RC4=0; RC5=0;  // Right Motor Off
      RC6=1; RC7=0;  // Left Motor On Forward
      break;
    case ROTATE_LEFT:
      RC4=0; RC5=1;  // Right Motor On Forward
      RC6=0; RC7=1;  // Left Motor On Reverse
      break;
    case ROTATE_RIGHT:
      RC4=1; RC5=0;  // Right Motor On Reverse
      RC6=1; RC7=0;  // Left Motor On Forward
      break;
    case MOVE_BACKWARD:
      RC4=1; RC5=0;  // Right Motor On Reverse
      RC6=0; RC7=1;  // Left Motor On Reverse
      break;
    case FULL_STOP:
      RC4=0; RC5=0;  // Right Motor Off
      RC6=0; RC7=0;  // Left Motor Off
      break;
  }
}
// BRAM Behaviour Functions
int random_number(void)
{
   unsigned char num;   

   num=(unsigned char) rand();
   return ((num % 300) + 20);
}
void BRAM_AvoidMode(unsigned char bump_sensor)
{
  static unsigned char turn_status = 0;
  turn_status ^= 0x01;
  // Process the Whisker Sensor
  if (bump_sensor > 50) {
    RA5=1;        // Turn On BRAM Head Light
#if BRAM_DEBUG
    printf("Whisker Value: %d\n\r",bump_sensor);
#endif
    // Initial Random Seed Number
    srand(bump_sensor);

    BRAM_steer(MOVE_BACKWARD);
    _delay_ms(150);
    if (bump_sensor <= 120) {
      // Left Bump Switch Range: 0 to 120
      BRAM_steer(ROTATE_RIGHT);
      _delay_ms(random_number());
    } else if (bump_sensor > 120 && bump_sensor <= 130) {
      // Right Bump Switch Range: 120 to 130
      BRAM_steer(ROTATE_LEFT);
      _delay_ms(random_number());
    } else {
      // Left + Right Bump Switch: > 130
      if (turn_status)
        BRAM_steer(ROTATE_LEFT);
      else
        BRAM_steer(ROTATE_RIGHT);
      _delay_ms(random_number());
    }
  }
}
void BRAM_LightFollow(unsigned char ldr_left, unsigned char ldr_right)
{
  int ldr_diff;
#if BRAM_DEBUG
  printf("Left LDR: %d; Right LDR: %d\n\r",ldr_left,ldr_right);
#endif
  // Get the different
  ldr_diff=ldr_left - ldr_right;
  if ((ldr_diff >= -THRESHOLD_VALUE) && (ldr_diff <= THRESHOLD_VALUE)) {
    if ((ldr_left > MAX_THRESHOLD) || (ldr_right > MAX_THRESHOLD)) {
      // Avoid Light
      BRAM_steer(FULL_STOP);
      _delay_ms(200);
      BRAM_steer(MOVE_BACKWARD);
      _delay_ms(200);
      BRAM_steer(ROTATE_LEFT);
      _delay_ms(200);
    } else {
      BRAM_steer(MOVE_FORWARD);       // Just go straight
    }
  } else {
    if (ldr_diff < 0)
      BRAM_steer(TURN_LEFT);
    else
      BRAM_steer(TURN_RIGHT);
  }
}
void main(void)
{
  unsigned char ldr_left;
  unsigned char ldr_right;
  unsigned char speed;
  unsigned char bump_sensor;
  unsigned char halt_status;
  OSCCON=0x70;         // Select 8 MHz internal clock
  TRISA = 0x03;        // Input for RA0 and RA1
  TRISC = 0x07;        // Set RC0,RC1 and RC2 as input others as Output
  ANSEL = 0x71;        // Set PORT AN0, AN4, AN5 and AN6 as analog input
  ANSELH = 0x00;       // Set PORT AN8 to AN11 as Digital I/O
  PORTC = 0x00;        // Turn Off all PORTC
  /* Init PWM for Single Output */
  CCP1CON=0b00001100;  // Single PWM mode; P1A, P1C active-high; P1B, P1D active-high
  CCPR1L=0;            // Start with zero Duty Cycle
  PSTRCON=0b00000100;  // Enable PIC Pulse Steering PWM on RC3 Port
  T2CON=0b00000101;    // Postscale: 1:1, Timer2=On, Prescale = 1:4
  PR2=0x65;            // Frequency: 4.90 kHz
  TMR2=0;              // Start with zero Counter 

  /* Init ADC */
  ADCON1=0b00110000;   // Select the FRC for 8 MHz
  halt_status=0;       // Initial: 0-Stop, 1-Run
  speed=0;             // Initial Speed
#if BRAM_DEBUG
  // Initial PIC16F690 UART
  uart_init();
  // Set the Attribute and Clear Screen
  ansi_me();
  ansi_cl();
  printf("Welcome to BRAM Debugging Mode\n\r\n\r");
#endif
  // Blink BRAM's Head Light Twice for Ready
  RA5=1; _delay_ms(100);
  RA5=0; _delay_ms(100);
  RA5=1; _delay_ms(100);
  RA5=0; _delay_ms(100);  

  for(;;) {
    if (RA1 == 0) {           // BRAM Status Switch
      _delay_ms(1);
      if (RA1 == 0) {         // Read again for Simple Debounce
        halt_status ^= 0x01;  // Halt Status
      }
    }
    /* Start Read All the ADC input here */
    // The PWM Motor Speed Control
    ADCON0=0b00000001;        // Select Left justify result. ADC port channel AN0
    GODONE=1;	              // Initiate conversion on the channel 0
    while(GODONE) continue;   // Wait for conversion done
    speed=ADRESH;
    // Bumped Sensor
    ADCON0=0b00011001;       // Select left justify result. ADC port channel AN6
    GODONE=1;	             // Initiate conversion on the channel 6
    while(GODONE) continue;  // Wait for ldr_left conversion done
    bump_sensor=ADRESH;      // Read 8 bits MSB, Ignore 2 bits LSB in ADRESL

    // The LDR Sensor
    ADCON0=0b00010001;       // Select left justify result. ADC port channel AN4
    GODONE=1;	             // Initiate conversion on the channel 4
    while(GODONE) continue;  // Wait for ldr_left conversion done
    ldr_left=ADRESH;         // Read 8 bits MSB, Ignore 2 bits LSB in ADRESL
    ADCON0=0b00010101;       // Select left justify result. ADC port channel AN5
    GODONE=1;	             // Initiate conversion on the channel 5
    while(GODONE) continue;  // Wait for ldr_right conversion done
    ldr_right=ADRESH;        // Read 8 bits MSB, Ignore 2 bits LSB in ADRESL           

    // BRAM Steering Speed
    BRAM_speed(speed * halt_status);
    RA5=0;                   // Turn Off BRAM Head Light
    // Whisker Sensor
    BRAM_AvoidMode(bump_sensor);    

    // Light Follower
    BRAM_LightFollow(ldr_left,ldr_right);
    _delay_ms(10);
  }
}
/* EOF: brampicphoto.c */

Downloading the Code

After compiling and simulating your code hook up your PICKit2 programmer to the PICJazz 16F690 board ICSP port turn the PICJazz 16F690 power. From the MPLAB IDE menu select Programmer -> Select Programmer -> Pickit2 it will automatically configure the connection and display it on the PICkit 2 tab output windows; Now you are ready to down load the code from MPLAB IDE menu select Programmer -> Program; this will down load the HEX code into the PICJazz 16F690 board:

Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1

Now you could enjoy BRAM with its basic obstacle avoidance and light following (photovore) behaviors:

The Final Thought

As shown by William Grey Walter with his tortoise robot, BRAM’s also show some kind of intelligent which is quite entertaining especially for my kids as they start to build their own maze and see how BRAM could solve that maze. On the second part of this tutorial we will explore more detail of the BRAM’s brain and how we utilize Microchip PIC 16F690 microcontroller UART peripheral for debugging BRAM.

Bookmarks and Share


bookmark bookmark bookmark bookmark bookmark bookmark bookmark bookmark bookmark bookmark




12 Responses to “Building BRAM your first Autonomous Mobile Robot using Microchip PIC Microcontroller – Part 1”

21.07.09#1

Comment by neyo_napster.

awesome work!!!
can u please provide the PCB layout of the PICJAZZ board.and how can we modify the circuit to drive a 12V dc geared motor?
mail: neyo_napster@yahoo.com

21.07.09#2

Comment by rwb.

Thanks, the L293D driver controller is designed to work up to max 36 volt, you could easily drive 12 volt geared motor by supplying the 12 volt to the Vs pin (Supply Voltage/Motor Supply pin) while keep the 4.5 volt on the Vss pin (Logic Supply Pin). For the PICJazz 16F690 PCB, currently we not publish it to the public; only the schematic which you could download from this blog.

21.07.09#3

Comment by neyo_napster.

Thanks a lot!!!

26.02.11#4

Comment by Eric88.

can you please provide me the assembler code that make the BRAM’s brain?? thanks

27.02.11#5

Comment by rwb.

No, I don’t have the assembler code for this project.

28.06.11#6

Comment by anotech.

sir, i hav to do a line following robot with these ICs,
L293D
PIC 16f877A
so i want the circuit diagram to make it, can u please help me.
i want the diagram with the connecting port (to programme)can you…………………….

28.06.11#7

Comment by anotech.

…link removed…

will this programmer help me to program PIC 16f877A ic???
so my line following robot moves knw?

28.06.11#8

Comment by rwb.

You could learned the principle of how the microcontroller based LFR work on this following article:

Build Your Own Microcontroller Based PID Control Line Follower Robot (LFR) – Second Part

About the Microchip PIC16F877A programmer, my recommendation is to use the Microchip PICKit 2 or PICKit 3 programmer.

12.04.12#9

Comment by Tec321.

I like it so much.
I was wondering if I Could ask you about the wheels and DC motor, what is the specific name of the DC motor and the wheels that were used in this project?

12.04.12#10

Comment by rwb.

You could experiment with any DC geared motor or you could use the Solarbotic GM2 DC geared motor.

13.04.12#11

Comment by Tec321.

One more question, you have used 8MHz crystal, am I right?

14.04.12#12

Comment by rwb.

I used the PIC16F690 Internal 8 MHz internal clock.