Let's Make Robots!

Wall Following RC car using 16F887

Here are two videos of my hobby level radio control car following the wall around a room.  This car uses channel 3 of the radio control system to toggle between RC control and autonomous control.



The idea is to hook middle school kids (USA grades 7th and 8th.  ages 11 - 14) into Science, Technology, Engineering and Math.  This offers the speed and excitement of RC car
 racing, the trial and error of RC race car design plus the clear thinking and discipline of computer programming.

 THE COMPETITION:  A car race.

 Build an oval race track on a polished wooden gymnasium floor defined on the inside by
 cardboard boxes large enough to echo back a SRF05 sonar proximity detector's signal.

 The race is to lap the track, say, six times;  three by radio control;  three by autonomous control.  Either time trials or multiple cars at the same time.  If the race has multiple cars on the track at one time, some more work must be done on the car to avoid collision.

  I will design and build a PIC kit that attaches to almost any RC car that has Electronic Speed Control (ESC) driving the wheels and a servo driven steering mechanism.  It will use the car's 7+ volt battery, knocked down to 5 volts by the ESC.  There must be a third channel on the RC system to tell the car who is boss.

 I need to borrow, steal, or design a microcontroller programming language that forces the students to think about the signals from the front and side facing sonars and create the corresponding commands to the wheels and the steering.  Presently the 16F887 compiler runs on a WINDOWS PC and communicates to the car via special hardware connected to the USB port.  (Available from MicroChip Inc.)

----------The post below seems to be way ahead of me----------

Author: bendjamin
| Title: I made some similar robots a

I made some similar robots a while ago.  I'll try and post a video of them.  They are designed to race around a track, in other words they are doing wall avoiding so when you make a track with walls on the inside and outside they will go around and around.  I made the robots myself, they are differential steering with a body made from laser cut polycarbonate.  I used the sharp IR rangefinders for navigation and have four on each robot, two forward facing and two side facing. They also have four bumber switches, one pair in front and the other at the rear.

| Link: http://letsmakerobots.com/node/696#comment-43464

What do you all think?



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Sounds like a very cool project, and for a noble cause too.

Considering the age of your prospective students, I wonder if PICBASIC might be a solid choice for a convenient language? It's easy to read and write, still offers a good amount of control and complexity, and there are many BASIC language compilers available for PICs. Unfortunately I can't suggest which compiler to go for, since I stick to Assembly and C myself, but I know there are other projects here on LMR that have used different forms of BASIC to program PIC micros with great success.

Been thinking that a good middle school STEM hook would be simple racing on an oval indoor (gymnasium basketball court) track delineated by large cardboard boxes (big enough to be detected by the SRF05 sonar proximity detectors) on the inside. I imagine a ten lap race. For six laps the kids control the cars with their radio transmitters. For four laps the cars are autonomous.

I think I can design a PBP template that would make coding the PIC reasonably simple. The template would contain the code state machine. The students' job would be to choose the steering/wheels commands associated with each state.

I have a question for you all.

If I were to add a black tape line around the track, what electronic gimmick might I put on an RC car to make it into a line follower? Is there a commercially available light source and photo cell combo similar to the pre-canned SRF05 sonar device?

On the subject of compiler-of-choice, I am using PICBASIC PRO.  It is expensive.  C comes for free from MIcroChip as part of a  PICkit 2 purchase. I don't think I should worry about cost right at the moment.


There are several free PICBASIC IDEs around too, GCBASIC, MicroCode, Proton, etc.

There are some nice IR reflectance units such as the QRD1114 that only require 2 extra resistors, but if you want a completed unit similar to the SRF05 you could go for something like this or this from SparkFun. The first sensor board is a nice simple digital output board (low signal = high reflectance), while the second sensor requires you to set the signal line to output a high signal to charge the onboard capacitor, and then you set the line back to an input and measure the time it takes for the signal to go low again (shorter time = higher reflectance). The first sensor is naturally easier to use, while the second allows for an analog value to be determined for the reflectance, so you can actually calibrate the sensitivity.

Sorry Old Man! But hooking kids on drugs is safer than this................

I keep saying that my RC car is meant to be a race car while being autonomous. Struggling to find its way around a room is not the demo that I want. I think an oval track in the gym bounded on the inside by many cardboard boxes at least a couple feet high. The kids with the RC transmitters must sit still in the lower seats of the roll out stands. The cars would be out of their sight when on the far side of the track.

My serious problem is that as a race car driver my 16F887 is not doing very well. It does not query the SRF05s quickly enough. The trigger pulses get to the sonars about one per second.

I am at a loss to figure what is consuming all the PIC compute time.

QUESTION? What would be the easiest, most efficient way for me to get on board with Assembly Language 16F887 coding? Machine language is not new to me. I used it professionally till somewhere in the 1980's.  What is a clear and complete document on this ASM?


Edit/Delete Message

I have not yet had to fall back on ASM code.

I did discover:

1. My PIC was resetting because of regressive subroutine calls. Changing a couple GOSUB's to GOTO's solved that.

2. My car was not being driven smoothly because of occasional zero responses from the SRF05's (or at least one of the SF05's). Implementing a - check again if the sensor says zero - routine after polling the sonar sensors smoothed things out.

I did notice that adding an IF THEN statement to the PBP code increased the size of the HEX code considerably. I still feel I need to understand the two compile processes.

Not going well at all.

When I up the speed the car does not respond quickly enough.  At a corner Instead of seeing (hearing) ahead and turning, it crashes into the on coming wall, backs up, and tries again. Part of my problem is not  understanding the machine language code behind the PICBASIC PRO commands.  Another part is the PIC getting into little loops or resetting and thereby ignoring the real time signals.  Lastly I need to expand the distances to which the code reacts.  If the velocity is greater, it must start turning or braking sooner.

On the bench, the machine seems to behave as expected, but on the race track.  NOPE.


Hi Ken, good to hear you have been making progress. Would you be able to post your PICASIC code for us to have a poke at?

I have been distracted.  Folks in another forum suggested that I up the effective oscillator to 8Mhz.  This made three things not work.

1.  HPWM command is throughly confused.  For good reason.  The Electronic Speed control wants pulses less than 2ms at a rate of 50 per second.  HPWM does not really do that.  I think I must go to interrupt driven code to be true to the spec.

2. PULSIN and recognizing the PWM input from Channel 3 which tells the car to toggle between PIC control and radio control.  The threshold needed adjusting (doubling for the twice as fast oscillator).

3. Interpreting the information in the echo response pulse from the SRF05's needed adjusting as well as timing the 10usec trigger pulse.

Once I clean up the mess this change made, I'll post what I have.

Thank you for asking.


Is it OKAY to post code in this manner?

Sorry I can't make the commands stand out like they do on

the MicroCode Studio page.

-------------start snip--------------16F887 PICBASIC PRO code--

symbol trigright = PORTB.0 ' Define output pin for Trigger pulse
symbol trigfront = PORTB.1 ' Define output pin for Trigger pulse

symbol echoright = PORTC.6 ' Define input pin for Echo pulse
symbol echofront = PORTC.5 ' Define input pin for Echo pulse

SYMBOL channel3 = PORTC.4  ' Define input pin for Channel 3 PWM
TRISC = %11110000
'OSCCON = %01100001 ' 4mhz clock - default
'define OSC 4 'not needed but does no harm

b0 var word
rangeright var word
rangeright = 100
rangefront var word
oldrangeright var word
differencerangeright var word
frontfreetostopreverse var word
reversecount VAR WORD
reversecount = 0
switchtoPIC VAR WORD
switchtoPIC = 1
radiocontrol var word
radiocontrol = 0

symbol frontdanger = 500 ' is about 34 inches. We
'realize we are getting too close. Back up. (note that breaking
'takes a lot, so this should be much higher than the real distance)

symbol frontfreetostopreversesetup = 502'  must be
'higher than "frontdanger" - higher value means more
'backing out after close encounters

symbol frontfree = 600' is about 40 inches.
'I set higher to turn earlier when something is in front
'fritsl says it get less skid-turning,
'but more likeliness to miss sharp right turns.  My racing
'model has no sharp right turns.

symbol desiredtrack = 360 ' about 24 inches.
symbol outertrack = 600 'about 40 inches

HPWM 1,100,50     ' Straignt discovered by experiment.
                    ' slow to center at 100

gosub blinkloop01  'This delay is to let me get ahead of the car.
'portd = %00000000
low portc.0        ' Set up initially as PIC control

'--Beginning run--
' Steering already straight.  Make wheels 1/2forward.

hpwm 2,113,50   'WheelsHalfForward
oldrangeright = rangeright

gosub puls
gosub RCcontrolsense
  if switchtoPIC > 150 then
  'radiocontrol = 1
  gosub MakeRadioControl 
  'radiocontrol = 0
  gosub MakePICControl

goto skidandreverse

frontfreetostopreverse = frontfreetostopreversesetup

'Here we are going forward.
if rangefront < frontfree then 'turn left as there is
'something ahead in front
HPWM 1,70,50 'SteerFullLeft
goto aftermain 'this is second priority above all loop till this is secured

if rangeright > outertrack then 'turn right as we are too far away
Hpwm 1,110,50    'SteerQuarterRight
'gosub  SteerQuarterRight

if rangeright < desiredtrack and oldrangeright < rangeright then
hpwm 1,100,50   'SteerStraight
' drive straight forward as we are on the wrong
'side of desired track, but we are moving the right direction
if rangeright > desiredtrack and oldrangeright > rangeright then
hpwm 1,100,50   'SteerStraight
' drive straight forward as we are on the wrong
'side of desired track, but we are moving the right direction

if rangeright > desiredtrack and oldrangeright < rangeright then
Hpwm 1,110,50   'SteerHalfRight
'gosub SteerHalfRight  'turn right as we are in the outer lane and getting away

if rangeright < desiredtrack and oldrangeright > rangeright then
'if rangeright < desiredtrack then
HPWM 1,85,50 'SteerHalfLeft
'gosub SteerHalfLeft  'turn left as we are in the inner lane and getting closer

goto aftermain


'Skidright:   'Nothing calls this subroutine
'gosub blinkloop7
'b0 = 0
'while rangefront > frontfreetostopreverse and rangeright > outertrack and b0 < 20
'gosub puls
'b0 = b0 +1

'low forrev  'set in forward gear
'hpwm 2,112,50 'WheelsHalfForward
'gosub WheelsHalfForward
'pause 300 why did I put in this pause?


'hpwm 2,100,50 'WheelsStop 
HPWM 1,140,50      'SteerFullRight 
HPWM 2,92,50  'WheelsHalfBack
Pause 100

frontfreetostopreverse = frontfreetostopreversesetup

frontfreetostopreverse = frontfreetostopreverse - 25
'Making sure we are not backing and reversing and going
'nowhere, as we have a wall behind us.

if frontfreetostopreverse < 50 then
goto stuckerror

gosub puls

if rangefront < frontfreetostopreversesetup then
' We have not reversed far enough

   if rangeright < desiredtrack and oldrangeright < rangeright and rangefront > frontdanger then
   hpwm 1,110,50  'SteerQuarterRight
   ' Going backwards.  On the correct side.
   'Moving away the wall.  Turn right to get parallel with the wall.
   'gosub puls
   'goto go_reverse

   if rangeright > desiredtrack and oldrangeright > rangeright and rangefront > frontdanger then
   hpwm 1,100,50 'SteerStraight
  ''Going backwards.  On far side of desired track. Moving
   ''towards the wall. Go straight.

   if rangeright > desiredtrack and oldrangeright < rangeright and rangefront > frontdanger then
   hpwm 1,110,50  'SteerQuarterRight    
   'Going backwards.  On far side of desired track.  Moving
   'away from the wall. Steer to get back on desired track.

   if rangeright < desiredtrack and oldrangeright > rangeright then
   'Going backwards. On correct side of desired track. Moving
   'toward the wall.  Steer left to get parallel to wall.
   hpwm 1,80,50 'SteerQuarterLeft

   goto keepreversing

   'hpwm 2,100,50 'WheelsStop
   'Pause 500
 endif '  This refers back five "IF's" ago. It means
' it is time to stop reversing and try going forward.
Hpwm 1,70,50  'SteerFullLeft
hpwm 2,112,50 'start going forward again.
goto aftermain 'was RETURN 'from gosub to reverseoutoftrouble.  There is
' no gosub there.


if rangefront < frontdanger then ' too close
goto reverseoutoftrouble
goto aftermain ' this is first priority above all - loop till this is secured
goto goingforward


puls: ' produce 10uS trigger pulse (must be minimum of 10uS)
low trigright
HIGH trigright
LOW trigright
'measures the range in 10uS steps
'zero could be legal here
pulsin echoright,1,rangeright ' measures the range in 10uS steps

pulsf:  ' produce 10uS trigger pulse (must be minimum of 10uS)
low trigfront
hIGH trigfront
LOW trigfront
pulsin echofront,1,rangefront ' measures the range in 10uS steps
if rangefront = 0 then goto pulsf

define pulsin_max 10000
PULSIN channel3,1,switchtoPIC

HPWM 1,100,50 'SteerStraight
hpwm 2,100,50 'WheelsStop

high portd.6
pause 5000   'Indicates trouble.
'RCControl or PICControl pulse sensing.  Prefer RCControl if stuck.
PULSIN channel3,1,switchtoPIC
if switchtoPIC > 150 then
radiocontrol = 1
gosub MakeRadioControl 
radiocontrol = 0
GOSub MakePICControl
'PORTD = %00000000
goto aftermain
'goto dadaa

high portc.0

low portc.0

FOR CNT = 1 TO 5

'PORTD = %00000000