Prairie Dog Animation
revised 08-12-10

Objective:  Design and construct an animation with five independently controlled prairie dogs.  Each prairie dog will be moved in and out of his/her hole with a servo.  Each servo will be controlled by a 12F683 PIC and all five of those PICs will be controlled by a 16F684 acting as a master controller.
This redesign of the circuitry will give more flexibility in programming and will achieve more realistic animation.

Please note that this is not meant to be a detailed tutorial on building this animation but merely a reference that can be used to build your own animation.

 

Circuit design:

Most PIC and PICAXE chips can control model airplane servos.  These servos are ideal for animating any number of things on a model railroad layout.  Use of servos has been explored in great detail in another article, Animate Your Layout With Servos
The original prairie dog animation that was discussed in the earlier article made use of one PIC 16F88 to control as many as six servos.  While this worked the current draw was excessive when more than two or three were active at once.  This caused spikes that reset the microcontroller from time-to-time.  In this revised animation each servo has its own 8 pin controller that is based on the unit described in the other article.  The servo units are connected to a single master PIC, a 14 pin 16F684.  It communicates, via serial protocol @ 9600 baud, and tells each servo what to do and when.

Here are the five servo activation units, each on its own black wood frame.  each unit is connected to the master controller in the lower left.

This closeup shows the circuit that is attached to each servo unit. 

Schematic:

SOFTWARE

Servo RECEIVING Unit

'd. bodnar revised 3-8-09
' up on serial port #1, down on serial #2, up fast on #3, down fast on #4
'Note2: GPIO.3 can't be connected to IR sensor while using ICSP
@ DEVICE MCLR_OFF
ansel = 0 'all inputs digital
cmcon0 = 7
'Include "modedefs.bas"
define ADC_BITS 12
define ADC_CLOCK 3
define ADC_SAMPLEUS 50
ADCON0=0 'analog

Audio var gpio.0 'pin 7
Trigger var gpio.3 'pin 4
ServoPin var gpio.4 'pin 3
NotUsed var gpio.5 'pin 2
Temp var word
Temp2 var word
Range var word
CWMin var word
CCWMax var word
Move var byte
DownFlag var bit
UpFlag var bit
CCWMax = 300 '225 manual recommended max
CWMin = 10 '75 manual recommended min
RangeMax con 170
CCW var word 'where to start rotation
CW var word
Delay con 10

gpio = %00001110 '1, 2, 3 inputs other outputs
downflag= 0:upflag= 0
cw= 90
ccw=240
gosub down

NewStart:
serin trigger, 6, ["ABC"], Move
if move = 1 then
gosub up
endif
if move =2 then
gosub down
endif
if move = 3 then
gosub up_fast
endif
if move = 4 then
gosub down_fast
endif
goto newstart:




Test:
serout notused ,6, ["Top ",10,13]
gosub up:pause 2000:gosub down:pause 2000
gosub up_fast:pause 2000:gosub down_fast:pause 2000
goto test:
Start:
LOW ServoPin 'relax servo
IF Trigger = 0 THEN gosub DogDown
if trigger = 1 then gosub DogUp


goto Start ' wait till button pressed

DogDown:
'serout notused ,6, ["Down "]
if downflag=1 then return
gosub down
downflag=1
upflag=0
return

DogUp:
'serout notused ,6, ["Up "]
if upflag=1 then return
gosub up
upflag=1
downflag=0
return

gosub up
pause 1500
gosub down
goto start:

Down:
serout notused ,6, ["Down "]
HIGH Audio
FOR Temp = CCW TO CW Step -1
pulsout servopin, temp
PAUSE Delay
NEXT Temp

LOW Audio
return
pause 1500

Up:
serout notused ,6, ["Up "]
'move prairie dog Up
FOR Temp=CW TO CCW Step 1
pulsout ServoPin, Temp
PAUSE Delay
NEXT Temp
return
PAUSE 1500
GOTO Start:
'cw= 90
'ccw=240
Down_Fast:
serout notused ,6, ["Down Fast "]
'move prairie dog Down FAST
HIGH Audio
for temp = 1 to 40
pulsout servopin, cw
pause delay
next temp
LOW Audio
return
pause 1500

Up_Fast:
serout notused ,6, ["Up Fast "]
'move prairie dog Up FAST
FOR Temp=1 to 40
pulsout ServoPin, CCW
pause delay
NEXT Temp
return
pulsout servopin, CCW
PAUSE 1500
GOTO Start:


Master CONTROL Unit

' d bodnar - 3-8-09
' sent up on serial port #1, down on serial #2, up fast on #3, down fast on #4

DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 5 ' PIN 2 on 16f684
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 1 ' Set Debug mode: 0 = true, 1 = inverted
ansel=0 'allows you to use pins as digital rather than analog
'Note- this combination of output pins works properly!
Trigger var byte(6)
trigger(1)=11 'portc.3 ' pin 7
trigger(2)=10 'portc.2 ' pin 8
trigger(3)=12 'portc.4 'pin 6
trigger(4)=13 'portc.5 'pin 5
trigger(5)= 2 'porta.2 'pin 11
temp var byte
temp2 var byte
temp3 var byte
temp4 var byte
RNDmtemp var word
Move var byte
flag var bit [6] 'flag =0 if down / =1 if up

trisc = %00000000
trisa = %00000000
for temp=1 to 5:flag(temp)=0:next temp
debug 13,10,13,10,"(C) 2009 - d. bodnar - ver 4.1",10,13,"Prairie Dog Master Controller",13,10,"TrainElectronics.com",13,10
pause 5000 'wait for remote units to wake up

debug "all up", 10,13
gosub all_up
pause 2000
debug "all down fast", 10,13
gosub all_down_fast
pause 2000

Top:
gosub getrandom2digit
if temp2 >=1 and temp2 <= 5 then 'send dog up
if flag(temp2)=0 then
serout trigger(temp2), 6,[ "ABC",1]
pause 20
serout trigger(temp2), 6,[ "ABC",1]
debug 10,13,#temp2," up ",#flag(temp2),10,13
flag(temp2)=1
endif
endif

if temp2 >=6 and temp2 <= 10 then 'send dog down
if flag(temp2-5)=1 then
serout trigger(temp2-5), 6, [ "ABC",2]
pause 20
serout trigger(temp2-5), 6, [ "ABC",2]
debug 10,13, #(temp2-5)," down ",#flag(temp2-5),10,13
flag(temp2-5)=0
endif
endif

if temp2 = 11 then 'if at least 3 up send all down fast
if temp3 >=3 then
gosub all_down_fast
debug "All Down Fast", 10,13
endif
endif
if temp2>0 and temp2<=11 then
temp3=0:for temp4=1 to 5:temp3=temp3+flag(temp4):next
debug " ttl= ",#temp3
pause 1500
endif

goto top:

All_Down:
for temp=1 to 5:flag(temp)=0:
Move = 2
serout trigger(temp), 6,[ "ABC",move]
next temp
return

All_up:
for temp=1 to 5:flag(temp)=1:
Move = 1
serout trigger(temp), 6,[ "ABC",move]
next temp
return

All_Down_fast:
for temp=1 to 5:flag(temp)=0:
Move = 4
serout trigger(temp), 6, [ "ABC",move]
next temp
return

All_Up_Fast:
for temp=1 to 5:flag(temp)=1:
Move = 3
serout trigger(temp), 6, [ "ABC",move]
next temp
return

GetRandom2Digit: ' random #s from 0 - 99
for temp=1 to 10
random rndmtemp 'reset seed
temp2=rndmtemp dig 2
temp2=temp2*10
temp2=temp2+ rndmtemp dig 1
pause 10
next temp
temp2=temp2+0 'remove zeros
if temp2 <= 12 and temp2<>0 then
endif
return