# Stand Alone 3 Axis Skull Controller



## halstaff

My biggest goal for this year is to get all of my 3 axis skulls up and running and to put together a controller system that allowed them to be stand alone props. I didn't want to be connected to a computer and didn't want to have to program them in VSA. Since none of my skulls movements need to be synced to music, a random movement works fine.
I took hpropman's random movement code and adapted it to work for a 3 axis skull. Using the new Picaxe 18M2, I was able to get it to control not only the head movements but also the audio board which is triggered by a PIR.
Now when attaching it to a new skull, I just need to adjust the servo limits to match the skulls setup. Of course, I can always quickly and easily adjust the program to speed up the movements or change the times between movements.
The total cost of the components for all 3 boards including the Tenda stereo board and SD card and the PIR was less than $60. I just used power supplies that I picked up at garage sales so those would need to be factored in to the cost as well.
It's nice to have one major project for 2012 already completed!


----------



## pshort

Sounds neat! Certainly a good direction to be thinking!


----------



## Dead Things

Bravo Steve, nice movement. When I attempted one with this design, the nod did not work well, head kept falling forward/backward (too much play in the caster). You've overcome that. Can you post the code?


----------



## halstaff

When I first built this 2 years ago, I used an 08M Picaxe chip and just wrote out a long list of movements that alternated between the different servos. It was rough and the nod servo especially would drop with a lot of force.
By using "step" and slowing the movement down to 1, I'm able to not only get the look I want but it smooths everything out and solved the problem with the nod servo.
Here's my code although I still need to go and do some commenting -

'b18 byte variable 0-255 in 10uS increments.
'b15 Pause variable 0-65535 in 1mS increments.
'Hitec servo's like signals between 0.740 and 2.740 mS and period of 1 to 20 mS
'B.1 is tilt servo
'B.2 is to audio player
'B.3 is from audio driver
'B.4 is turn servo
'B.5 is is nod servo
'B.6 is jaw servo
'B.7 is PIR

symbol PIR_IN=pinB.7
symbol PIR_COUNT=b10
symbol counter = b9
symbol pointer = b8
symbol delay = 35
symbol counter1 = b19
symbol pointer1 = b18
symbol delay1 = 39
symbol counter2 = b25
symbol pointer2 = b24
symbol delay2 = 45

start0:

Servo B.6,255 'Initialises Pin4 as a servo output and sets servo to the start position
pause 500
Pause 60000

Init: 'Just a starting point label

serout B.3,4800, ($EF); 'STOP MP3 module 
pause 1000
serout B.3,4800, ($E1); 'Set MP3 volume
pause 1000

Testit: 
Do : Loop Until PIR_IN=1

Do
PIR_COUNT = PIR_COUNT + 1 * PIR_IN
Loop Until PIR_COUNT = 10
PIR_COUNT = 0

goto Routine

Routine:

serout B.3,4800,($01) 'Start playing first mp3
pause 500

Begin:

w6=30000 'Counter for number of loops needed, every 1000 = about 15 seconds +/-

b2=8 'Set pause delay
b3=210 'Set Servo Min position and also offset - mouth open 100
b4=255 'Set Servo Max position - mouth closed
Servopos B.6,b4 'Initialises Pin4 as a servo output and sets servo to the start position

OP:

ADCA: 'Reads input voltage in 256 steps Pin 1 (leg 6)

Readadc B.2,b0 'Read input voltage into b0
b1=255-b0+b3 'Add offset for servo's CCW output 
If b1<b3 then gosub servomax 'Test for less than servo min position and if less, set at servo min
If b1>b4 then gosub servomin 'Test for more than servo min position and if more, set at servo max

MoveA: 'Move servoA
servopos B.6,b1 'Pulse pin 4 (leg 3) width=b1 - Using servopos can help prevent jitter

pause b2 'Wait Delay b2

w6=w6-1 'Decrement the counter
if w6>0 then goto OP 'Test for counter being larger than 0 if yes, go round the loop again

goto Hold

goto OP

servomin:
b1=b3 
return

servomax:
b1=b4
return

Hold:
servopos B.6,255
pause 500
low B.6

for time = 1 to 60 '60 is the number of seconds of retrigger delay
pause 1000 'Pause for 1 sec 
next time

goto Testit

start1:'Nod Head
let b8=63 'set pointer offset so that head loop does not get stuck
let b6=60
let b7=60 'set default center values
servo B.5,pointer 'center servo
pause 7500
for counter = 60 to 35 step -1 
servopos B.5,counter
pause delay
next counter
pause 3000

for counter = 35 to 105 step 1
servopos B.5,counter 
pause delay
next counter
pause 3000

for counter = 105 to 60 step -1
servopos B.5,counter 
pause delay
next counter
pause 4000

move: random w3 'place a random number in wo (also B0 & B1)

if b7<35 then left 'check for random down
if b7>=35 and b7<=60 then middle 'check for random middle
if b7>=60 then right 
goto move 'keep moving the head back to move loop

right: if pointer = 35 then move 
if pointer = 60 then mr 
for counter = 105 to 35 step -1 
servopos B.5,counter
pause delay
next counter
pointer = 35 
goto skipmr

mr: for counter = 60 to 35 step -1 
servopos B.5,counter
pause delay
next counter
pointer = 35

skipmr: pause 7000 'delay to look natural
goto move 'return to move loop

middle: if pointer = 60 then move 'if head is already in the middle then go back to move
if pointer = 35 then ml 
for counter = 105 to 60 step -1
servopos B.5,counter 
pause delay
next counter
pointer = 60
goto skipml

ml: for counter = 35 to 60 step 1
servopos B.5,counter 
pause delay
next counter
pointer = 60

skipml: pause 9000 'delay to look natural
goto move 'return to move loop

left: if pointer = 105 then move 
if pointer = 35 then lmr 
for counter = 60 to 105 step 1
servopos B.5,counter 
pause delay
next counter
pointer = 105
goto skiplmr

lmr: for counter = 35 to 105 step 1
servopos B.5,counter 
pause delay
next counter
pointer = 105

skiplmr: pause 7000 'delay to look natural
goto move 'return to move loop

start2: 'Tilt head
let b18=153 'set pointer offset so that head loop does not get stuck
let b16=150
let b17=150 'set default center values
servo B.1,pointer1 'center servo
pause 8000
for counter1 = 150 to 100 step -1 
servopos B.1,counter1
pause delay1 
next counter1
pause 3000

for counter1 = 100 to 200 step 1
servopos B.1,counter1 
pause delay1
next counter1
pause 3000

for counter1 = 200 to 150 step -1
servopos B.1,counter1 
pause delay1
next counter1 
pause 2000

move1: random w8 'place a random number in wo (also B0 & B1)

if b17<100 then left1 'check for random left
if b17>=100 and b17<=150 then middle1 'check for random middle
if b17>=150 then right1 
goto move1 'keep moving the head back to move loop

right1: if pointer1 = 100 then move1 
if pointer1 = 150 then mr1 
for counter1 = 200 to 100 step -1 
servopos B.1,counter1
pause delay1
next counter1
pointer1 = 100 
goto skipmr1

mr1: for counter1 = 150 to 100 step -1 
servopos B.1,counter1
pause delay1
next counter1
pointer1 = 100

skipmr1: pause 7000 'delay to look natural
goto move1 'return to move loop

middle1: if pointer1 = 150 then move1 'if head is already in the middle then go back to move
if pointer1 = 100 then ml1 'check to see if head is pointed left or right
for counter1 = 200 to 150 step -1
servopos B.1,counter1 
pause delay1
next counter1
pointer1 = 150
goto skipml1

ml1: for counter1 = 100 to 150 step 1
servopos B.1,counter1 
pause delay1
next counter1
pointer1 = 150

skipml1: pause 9000 'delay to look natural
goto move1 'return to move loop

left1: if pointer1 = 200 then move1 
if pointer1 = 100 then lmr1 
for counter1 = 150 to 200 step 1
servopos B.1,counter1 
pause delay1
next counter1
pointer1 = 200
goto skiplmr1

lmr1: for counter1 = 100 to 200 step 1
servopos B.1,counter1 
pause delay1
next counter1
pointer1 = 200

skiplmr1: pause 7000 'delay to look natural
goto move1 'return to move loop

start3: 'Turn head side to side
let b24=173 'set pointer offset so that head loop does not get stuck
let b22=170
let b23=170 'set default center values
servo B.4,pointer2 'center servo
pause 9500
for counter2 = 170 to 120 step -1 'move head from middle to right side
servopos B.4,counter2
pause delay2
next counter2
pause 3000

for counter2 = 120 to 220 step 1
servopos B.4,counter2 'move head from right to left
pause delay2
next counter2
pause 3000

for counter2 = 120 to 170 step -1
servopos B.4,counter2 'move head from right to middle
pause delay2
next counter2
pause 4000

move2: random w11 'place a random number in wo (also B0 & B1)

if b23<120 then left2 'check for random left
if b23>=120 and b23<=170 then middle2 'check for random middle
if b23>=170 then right2 'check for random right
goto move2 'keep moving the head back to move loop

right2: if pointer2 = 120 then move2 'if head is already Right goto back to move
if pointer2 = 170 then mr2 'check to see if head in pointed middle or the left
for counter2 = 220 to 120 step -1 'move head from left side to the right side
servopos B.4,counter2
pause delay2
next counter2
pointer2 = 120 'set head pointer direction to right
goto skipmr2

mr2: for counter2 = 170 to 120 step -1 'move head from middle to right side
servopos B.4,counter2
pause delay2
next counter2
pointer2 = 120 'set head pointer direction to right

skipmr2: pause 7000 'delay to look natural
goto move2 'return to move loop

middle2: if pointer2 = 170 then move2 'if head is already in the middle then go back to move
if pointer2 = 120 then ml2 'check to see if head is pointed left or right
for counter2 = 220 to 170 step -1
servopos B.4,counter2 'move head from right to middle
pause delay2
next counter2
pointer2 = 170
goto skipml2

ml2: for counter2 = 120 to 170 step 1
servopos B.4,counter2 'move servo from left to middle
pause delay2
next counter2
pointer2 = 170

skipml2: pause 9000 'delay to look natural
goto move2 'return to move loop

left2: if pointer2 = 220 then move2 'if head is already left then return to move
if pointer2 = 120 then lmr2 'check if the head is in the middle or the right
for counter2 = 170 to 220 step 1
servopos B.4,counter2 'move head from middle to left
pause delay2
next counter2
pointer2 = 220
goto skiplmr2

lmr2: for counter2 = 120 to 220 step 1
servopos B.4,counter2 'move head from right to left
pause delay2
next counter2
pointer2 = 220

skiplmr2: pause 7000 'delay to look natural
goto move2 'return to move loop


----------



## Atom058

Nice job, Halstaff. I did something similar to this a while back. I too, wanted to have something that did not need to be attached to a computer. I did mine using PICs - 3 running simultaneously, 1 for each axis - so that I could have simultaneous movement in all directions. I did not have the eye movement... Here is a link to what I did:

My First 3-Axis Skull pictures by jwheat058 - Photobucket

Great minds think alike?

The video does not do justice to the voice... Sorry - looks much better in real time...


----------



## halstaff

Jeff, I considered using your boards which I really like but decided that for my needs, random movement was just fine. There are many of us that are tired of having these tied to computers and are working on variations of our builds. Within the next month, I think we'll have at least 4 options to choose from, each build different and offering a variety of choices.
My son told be that great minds think for themselves but often seek solutions to the same problems. I think we qualify!


----------



## Brad Green

I did something similar a few years back with a Prop1 board and a ST sound driver. I was aiming for a simple pug-n-play that I could set up anywhere. I managed to get everything, including and MP3 player into a Bucky skull, but it wasn't easy!



Uploaded with ImageShack.us


----------



## sluggo

Atom058 said:


> I did mine using PICs - 3 running simultaneously, 1 for each axis - so that I could have simultaneous movement in all directions.


You can have simultaneous movement in multiple directions using just one processor. I have used a PIC16F628 to control 3 servos. You just need to structure your program appropriately. An 18-pin PIC could easily control 8 servos, with few extra pins for sound, triggers, etc.


----------



## sluggo

Brad Green said:


> I managed to get everything, including and MP3 player into a Bucky skull, but it wasn't easy!


I can see why. Yikes!


----------



## MaxSinister

Awesome work Steve. I've been following your Picaxe stuff on the boards and can honestly say that I've gotten into Picaxe because of you. Thanks for the great stuff.


----------



## halstaff

I've had questions about the audio/driver board so I wanted to post the link to the thread detailing that build - http://www.hauntforum.com/showthread.php?t=26880
You can see how the board improved as some of the great minds here made suggestions that I incorporated in new designs.


----------



## pshort

Somewhat along these lines, I'm working on a design that combines audio and servo control on one standalone board. It will have up to 3 minutes of 16-bit mono audio and 8-channels of servo output. The current board size is 1.6" x 2.4", although the 2.4" might go up a little bit. It's an SMT board, a little bit too complex for any sort of DIY kit.


----------

