trying to get a servo to move how i want

Pat13

Senior Member
I am using this code, developed by halstaff, for a 3 axis animatronic head. I intend to have the "Pan" servo move left and hold upon receiving an input on C.3. Right now I am just trying to establish movement range and speed. The problem is this: with halstaff's code, the movement of the servos is slowed somewhat, giving a "realistic" head movement. When I added my pan section to establish speed and position, the servo moves at full speed. I'm confused as I am using the same variables as defined in the "symbol" section
Here is halstaff's code, with servo positions modified for the peculiarities of my 3 axis design.
Code:
#Picaxe 08M2 'Gertie 3 axis Witch head


'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
'C.1 is nod servo
'C.2 is tilt servo
'C.4 is pan servo

symbol Nod = C.2
Symbol Pan = C.4
Symbol Tilt = C.1
symbol counter = b9
symbol pointer = b8
symbol delay = 39
symbol counter1 = b19
symbol pointer1 = b18
symbol delay1 = 45
symbol counter2 = b25
symbol pointer2 = b24
symbol delay2 = 55


start0:
pause 500
                
start1:'Nod Head
let b8=153 'set pointer offset so that head loop does not get stuck
let b6=150
let b7=150 'set default center values
servo Nod,pointer 'center servo
pause 7500
for counter = 150 to 75 step -1 
servopos Nod,counter
pause delay
next counter
pause 3000

for counter = 75 to 150 step 1
servopos Nod,counter 
pause delay
next counter
pause 3000

for counter = 190 to 150 step -1
servopos Nod,counter 
pause delay
next counter
pause 4000 

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

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


right: if pointer = 75 then move 
if pointer = 150 then mr 
for counter = 150 to 75 step -1  
servopos Nod,counter
pause delay
next counter
pointer = 75 
goto skipmr

mr: for counter = 150 to 75 step -1 
servopos Nod,counter
pause delay
next counter
pointer = 75 

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

middle: if pointer = 150 then move 'if head is already in the middle then go back to move
if pointer = 75 then ml 
for counter = 190 to 150 step -1
servopos Nod,counter 
pause delay
next counter
pointer = 150
goto skipml

ml: for counter = 75 to 150 step 1
servopos Nod,counter 
pause delay
next counter
pointer = 150

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

left: if pointer = 190 then move 
if pointer = 75 then lmr 
for counter = 150 to 190 step 1
servopos Nod,counter 
pause delay
next counter
pointer = 190
goto skiplmr

lmr: for counter = 75 to 190 step 1
servopos Nod,counter 
pause delay
next counter
pointer = 190

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


 

start2: 'Pan 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 Pan,pointer1 'center servo
pause 8000
for counter1 = 150 to 100 step -1 
servopos Pan,counter1
pause delay1 
next counter1
pause 3000

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

for counter1 = 200 to 150 step -1
servopos Pan,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 Pan,counter1
pause delay1
next counter1
pointer1 = 100 
goto skipmr1

mr1: for counter1 = 150 to 100 step -1 
servopos Pan,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 Pan,counter1 
pause delay1
next counter1
pointer1 = 150
goto skipml1

ml1: for counter1 = 100 to 150 step 1
servopos Pan,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 Pan,counter1 
pause delay1
next counter1
pointer1 = 200
goto skiplmr1

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

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




start3: 'Tilt head
let b24=153 'set pointer offset so that head loop does not get stuck
let b22=150
let b23=150 'set default center values
servo Tilt,pointer2 'center servo
pause 4500
for counter2 = 150 to 80 step -1 'move head from middle to right side
servopos Tilt,counter2
pause delay2
next counter2
pause 3000

for counter2 = 80 to 210 step 1
servopos Tilt,counter2 'move head from right to left
pause delay2
next counter2
pause 3000

for counter2 = 210 to 150 step -1
servopos Tilt,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<80 then left2 'check for random left
if b23>=80 and b23<=150 then middle2 'check for random middle
if b23>=150 then right2 'check for random right
goto move2 'keep moving the head back to move loop


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

mr2: for counter2 = 150 to 80 step -1 'move head from middle to right side
servopos Tilt,counter2
pause delay2
next counter2
pointer2 = 80 'set head pointer direction to right

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

middle2: if pointer2 = 150 then move2 'if head is already in the middle then go back to move
if pointer2 = 80 then ml2 'check to see if head is pointed left or right
for counter2 = 210 to 150 step -1
servopos Tilt,counter2 'move head from right to middle
pause delay2
next counter2
pointer2 = 150
goto skipml2

ml2: for counter2 = 80 to 150 step 1
servopos Tilt,counter2 'move servo from left to middle
pause delay2
next counter2
pointer2 = 150

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


left2: if pointer2 = 210 then move2 'if head is already left then return to move
if pointer2 = 80 then lmr2 'check if the head is in the middle or the right
for counter2 = 150 to 210 step 1
servopos Tilt,counter2 'move head from middle to left
pause delay2
next counter2
pointer2 = 210
goto skiplmr2

lmr2: for counter2 = 80 to 210 step 1
servopos Tilt,counter2 'move head from right to left
pause delay2
next counter2
pointer2 = 210

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

Pat13

Senior Member
Here is my code, with start2 being the changed portion
Code:
#Picaxe 08M2


'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
'C.1 is nod servo
'C.2 is tilt servo
'C.4 is pan servo

symbol Nod = C.1
Symbol Pan = C.4
Symbol Tilt = C.2
symbol counter = b9
symbol pointer = b8
symbol delay = 55
symbol counter1 = b19
symbol pointer1 = b18
symbol delay1 = 55
symbol counter2 = b25
symbol pointer2 = b24
symbol delay2 = 55


start0:
pause 500
                
start1:'Nod Head
let b8=153 'set pointer offset so that head loop does not get stuck
let b6=150
let b7=150 'set default center values
servo Nod,pointer 'center servo
pause 7500
for counter = 150 to 75 step -1 
servopos Nod,counter
pause delay
next counter
pause 3000

for counter = 75 to 150 step 1
servopos Nod,counter 
pause delay
next counter
pause 3000

for counter = 190 to 150 step -1
servopos Nod,counter 
pause delay
next counter
pause 4000 

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

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


right: if pointer = 75 then move 
if pointer = 150 then mr 
for counter = 150 to 75 step -1  
servopos Nod,counter
pause delay
next counter
pointer = 75 
goto skipmr

mr: for counter = 150 to 75 step -1 
servopos Nod,counter
pause delay
next counter
pointer = 75 

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

middle: if pointer = 150 then move 'if head is already in the middle then go back to move
if pointer = 75 then ml 
for counter = 190 to 150 step -1
servopos Nod,counter 
pause delay
next counter
pointer = 150
goto skipml

ml: for counter = 75 to 150 step 1
servopos Nod,counter 
pause delay
next counter
pointer = 150

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

left: if pointer = 190 then move 
if pointer = 75 then lmr 
for counter = 150 to 190 step 1
servopos Nod,counter 
pause delay
next counter
pointer = 190
goto skiplmr

lmr: for counter = 75 to 190 step 1
servopos Nod,counter 
pause delay
next counter
pointer = 190

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


 

start2: 'Pan head
pause 5000
servo Pan, 150
pause delay2
pause 2000
servopos Pan,75
pause delay2
pause 2000
servopos Pan, 225
pause delay2
pause 2000
servopos Pan, 150
pause delay2
pause 2000





start3: 'Tilt head
let b24=153 'set pointer offset so that head loop does not get stuck
let b22=150
let b23=150 'set default center values
servo Tilt,pointer2 'center servo
pause 4500
for counter2 = 150 to 80 step -1 'move head from middle to right side
servopos Tilt,counter2
pause delay2
next counter2
pause 3000

for counter2 = 80 to 210 step 1
servopos Tilt,counter2 'move head from right to left
pause delay2
next counter2
pause 3000

for counter2 = 210 to 150 step -1
servopos Tilt,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<80 then left2 'check for random left
if b23>=80 and b23<=150 then middle2 'check for random middle
if b23>=150 then right2 'check for random right
goto move2 'keep moving the head back to move loop


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

mr2: for counter2 = 150 to 80 step -1 'move head from middle to right side
servopos Tilt,counter2
pause delay2
next counter2
pointer2 = 80 'set head pointer direction to right

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

middle2: if pointer2 = 150 then move2 'if head is already in the middle then go back to move
if pointer2 = 80 then ml2 'check to see if head is pointed left or right
for counter2 = 210 to 150 step -1
servopos Tilt,counter2 'move head from right to middle
pause delay2
next counter2
pointer2 = 150
goto skipml2

ml2: for counter2 = 80 to 150 step 1
servopos Tilt,counter2 'move servo from left to middle
pause delay2
next counter2
pointer2 = 150

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


left2: if pointer2 = 210 then move2 'if head is already left then return to move
if pointer2 = 80 then lmr2 'check if the head is in the middle or the right
for counter2 = 150 to 210 step 1
servopos Tilt,counter2 'move head from middle to left
pause delay2
next counter2
pointer2 = 210
goto skiplmr2

lmr2: for counter2 = 80 to 210 step 1
servopos Tilt,counter2 'move head from right to left
pause delay2
next counter2
pointer2 = 210

skiplmr2: pause 4000 'delay to look natural
goto move2 'return to move loop
Any help appreciated
 

goom

Senior Member
A command such as "servo Pan, 150" will move the servo immediately to that position at full servo speed. If you want to move it slowly you need to use the same strategy as for the other axis, i.e. move a bit - pause - move a bit - pause etc. This is accomplished by the "for counter" loop which increments the servo position by 1 unit at a time with a pause between each increment.
 

Pat13

Senior Member
A command such as "servo Pan, 150" will move the servo immediately to that position at full servo speed. If you want to move it slowly you need to use the same strategy as for the other axis, i.e. move a bit - pause - move a bit - pause etc. This is accomplished by the "for counter" loop which increments the servo position by 1 unit at a time with a pause between each increment.
thanks goom, i had tried that but i think I had my pause times too long as it moved really slowly.
I'm having some issue with the servos and the picaxe. 08M2 is programmable but I have to unplug and re plug after programming to get servos to move. i am using seperate power supplies for picaxe and servos, with grounds connected and decoupling caps on picaxe. I think i may need cap on servo power as well.
 

Pat13

Senior Member
Ok, I have the speed of movement that I want. Now to get it to move when the input goes low. Here is the modified "start2", with an "if..then gosub". The program does not "gosub", when input goes low. I suspect that is because the code only looks for the input to go low once, and not constantly. However, I am not sure how to write this, perhaps a "do..loop". Note that start0 only has pause 500.
Code:
start2: 'Pan head
if Trigger = 0 then 
	gosub stare 
endif
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 Pan,pointer1 'center servo
pause 8000
for counter1 = 150 to 100 step -1 
servopos Pan,counter1
pause delay1 
next counter1
pause 3000

for counter1 = 100 to 220 step 1
servopos Pan,counter1 
pause delay1
next counter1
pause 3000

for counter1 = 220 to 150 step -1
servopos Pan,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 = 220 to 100 step -1 
servopos Pan,counter1
pause delay1
next counter1
pointer1 = 100 
goto skipmr1

mr1: for counter1 = 150 to 100 step -1 
servopos Pan,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 = 220 to 150 step -1
servopos Pan,counter1 
pause delay1
next counter1
pointer1 = 150
goto skipml1

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

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


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

lmr1: for counter1 = 100 to 220 step 1
servopos Pan,counter1 
pause delay1
next counter1
pointer1 = 220

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

stare:
servopos Pan, 150
for counter1 =b17 to 220 step 1
pause delay1
next counter1
if Trigger = 1 then return
endif
 

SAborn

Senior Member
Code:
stare:
servopos Pan, 150
for counter1 =b17 to 220 step 1
pause delay1
next counter1
if Trigger = 1 then return
endif
If this is the section of code you are having trouble with then it might be because "if Trigger = 1 then return" the program do the For/Next loop then drop through to the "IF" statement, if the "IF" is not true the program then it falls through and out the bottom as there is no instruction to tell it where else to go.

I also did not see any "gosub" in the code (perhaps i missed it) and without a gosub the return wont work with a goto.
 

westaust55

Moderator
I also did not see any "gosub" in the code (perhaps i missed it) and without a gosub the return wont work with a goto.
There is a gosub to be found:
Code:
start2: 'Pan head
	if Trigger = 0 then 
		gosub stare


@Pat13,

Notwithstanding the existence of a GOSUB, as SAborn indicates, your return structure is not complete and can easily flow down into other code which I suspect is not what you desire.

It would be helpfull if you formatted you code so the structure and flow is easier for others to follow.
attached is a partially formatted version with each looping structure indented and opnly labels starting in column 1 for ease of locating.



Code:
#Picaxe 08M2


'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
'C.1 is nod servo
'C.2 is tilt servo
'C.4 is pan servo

symbol Nod = C.1
Symbol Pan = C.4
Symbol Tilt = C.2
symbol counter = b9
symbol pointer = b8
symbol delay = 55
symbol counter1 = b19
symbol pointer1 = b18
symbol delay1 = 55
symbol counter2 = b25
symbol pointer2 = b24
symbol delay2 = 55


start0:
	DO
		pause 500
	LOOP
                
start1:'Nod Head
	let b8=153 'set pointer offset so that head loop does not get stuck
	let b6=150
	let b7=150 'set default center values
	servo Nod,pointer 'center servo
	pause 7500
	for counter = 150 to 75 step -1 
		servopos Nod,counter
		pause delay
	next counter
	pause 3000

	for counter = 75 to 150 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pause 3000

	for counter = 190 to 150 step -1
		servopos Nod,counter 
		pause delay
	next counter
	pause 4000 

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

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


right: 
	if pointer = 75 then move 
	if pointer = 150 then mr 
	for counter = 150 to 75 step -1  
		servopos Nod,counter
		pause delay
	next counter
	pointer = 75 
	goto skipmr

mr: 
	for counter = 150 to 75 step -1 
		servopos Nod,counter
		pause delay
	next counter
	pointer = 75 

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

middle: 
	if pointer = 150 then move 'if head is already in the middle then go back to move
	if pointer = 75 then ml 
	for counter = 190 to 150 step -1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 150
	goto skipml

ml: 
	for counter = 75 to 150 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 150

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

left: 
	if pointer = 190 then move 
	if pointer = 75 then lmr 
	for counter = 150 to 190 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 190
	goto skiplmr

lmr: 
	for counter = 75 to 190 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 190

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



start2: 'Pan head
	if Trigger = 0 then 
		gosub stare 
	endif
	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 Pan,pointer1 'center servo
	pause 8000
	for counter1 = 150 to 100 step -1 
		servopos Pan,counter1
		pause delay1 
	next counter1
	pause 3000

	for counter1 = 100 to 220 step 1
		servopos Pan,counter1 
		pause delay1
	next counter1
	pause 3000

	for counter1 = 220 to 150 step -1
		servopos Pan,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 = 220 to 100 step -1 
servopos Pan,counter1
pause delay1
next counter1
pointer1 = 100 
goto skipmr1

mr1: for counter1 = 150 to 100 step -1 
servopos Pan,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 = 220 to 150 step -1
servopos Pan,counter1 
pause delay1
next counter1
pointer1 = 150
goto skipml1

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

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


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

lmr1: for counter1 = 100 to 220 step 1
servopos Pan,counter1 
pause delay1
next counter1
pointer1 = 220

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

stare:
	servopos Pan, 150
	for counter1 =b17 to 220 step 1
		pause delay1
	next counter1
	if Trigger = 1 then return
	endif
===================================



start3: 'Tilt head
	let b24=153 'set pointer offset so that head loop does not get stuck
	let b22=150
	let b23=150 'set default center values
	servo Tilt,pointer2 'center servo
	pause 4500
	for counter2 = 150 to 80 step -1 'move head from middle to right side
		servopos Tilt,counter2
		pause delay2
	next counter2
	pause 3000

	for counter2 = 80 to 210 step 1
		servopos Tilt,counter2 'move head from right to left
		pause delay2
	next counter2
	pause 3000

	for counter2 = 210 to 150 step -1
		servopos Tilt,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<80 then left2 'check for random left
	if b23>=80 and b23<=150 then middle2 'check for random middle
	if b23>=150 then right2 'check for random right
	goto move2 'keep moving the head back to move loop


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

mr2: for counter2 = 150 to 80 step -1 'move head from middle to right side
servopos Tilt,counter2
pause delay2
next counter2
pointer2 = 80 'set head pointer direction to right

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

middle2: if pointer2 = 150 then move2 'if head is already in the middle then go back to move
if pointer2 = 80 then ml2 'check to see if head is pointed left or right
for counter2 = 210 to 150 step -1
servopos Tilt,counter2 'move head from right to middle
pause delay2
next counter2
pointer2 = 150
goto skipml2

ml2: for counter2 = 80 to 150 step 1
servopos Tilt,counter2 'move servo from left to middle
pause delay2
next counter2
pointer2 = 150

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


left2: if pointer2 = 210 then move2 'if head is already left then return to move
if pointer2 = 80 then lmr2 'check if the head is in the middle or the right
for counter2 = 150 to 210 step 1
servopos Tilt,counter2 'move head from middle to left
pause delay2
next counter2
pointer2 = 210
goto skiplmr2

lmr2: for counter2 = 80 to 210 step 1
servopos Tilt,counter2 'move head from right to left
pause delay2
next counter2
pointer2 = 210

skiplmr2: pause 4000 'delay to look natural
goto move2 'return to move loop
Why do you only have a PAUSE 500 in the Start0: task? :confused:
At least put it in a loop to make it clear you do not think the code will drop down into the Start1: task.

08M2 is programmable but I have to unplug and re plug after programming to get servos to move.
Is that unplug the 08M2 or the power or other?
Maybe post you schematic so folks can review and offer help.
 

hippy

Ex-Staff (retired)
The 'start2:' code in post #2, is not in a loop, it falls into 'Start3:'. As this is a PICAXE M2 that means you end up with two of the multi-tasking tasks running the same code, one a little behind the other. That will give all manner of problems and glitches.

I find the label numbering extremely confusing when trying to follow the code ...

Start1: ... goto move ... goto right
Start2: ... goto move1 ... goto right1
Start3: ... goto move2 ... goto right2

'goto right1' takes you to a label within task 1, no within task 2, no wait ... This would be much clearer and more logical IMO ...

Start1: ... goto move1 ... goto right1
Start2: ... goto move2 ... goto right2
Start3: ... goto move3 ... goto right3
 

Pat13

Senior Member
Thanks for the replies. I have adjusted the codes with indents. As for why start0 does not have a loop, I am not sure. This code was developed by a friend of mine and works really well for our purposes (which is random-looking head movement). I assume it is there to give that portion of multitask something to do.
What I am trying to do is get the head to turn and hold that position when pinC.3 receives a low input, then when the input goes high, to return to where it was in the program. I have been reading the if..then section of manual 2. It would seem I need to add "else" in there (?). I am also wondering if there may be some other issues that arise from the sub routine. Since there is no for ..next loop, I foresee that when the sub is called up, the servo will move immediately to the middle position (150) and when it returns to the main program the servo will move immediately to its former position. I am wanting the movement into and out of the subroutine to be consistent with the way the servo moves in the other parts of the program.
here is the code with indents
Code:
#Picaxe 08M2 'Gertie 3 axis Witch head


'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
'C.1 is nod servo
'C.2 is tilt servo
'C.4 is pan servo

symbol Nod = C.2
Symbol Pan = C.4
Symbol Tilt = C.1
symbol counter = b9
symbol pointer = b8
symbol delay = 39
symbol counter1 = b19
symbol pointer1 = b18
symbol delay1 = 45
symbol counter2 = b25
symbol pointer2 = b24
symbol delay2 = 55
symbol Trigger = pinC.3

start0:
	main:
	pause 500
	goto main
                
start1:'Nod Head
	let b8=153 'set pointer offset so that head loop does not get stuck
	let b6=150
	let b7=150 'set default center values
		servo Nod,pointer 'center servo
		pause 7500
	for counter = 150 to 75 step -1 
		servopos Nod,counter
		pause delay
	next counter
	pause 3000

	for counter = 75 to 150 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pause 3000

	for counter = 180 to 150 step -1
		servopos Nod,counter 
		pause delay
	next counter
	pause 4000 

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

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


right: 
	if pointer = 75 then move 
	if pointer = 150 then mr 
	for counter = 150 to 75 step -1  
		servopos Nod,counter
		pause delay
	next counter
	pointer = 75 
	goto skipmr

mr: 
	for counter = 150 to 75 step -1 
		servopos Nod,counter
		pause delay
	next counter
	pointer = 75 

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

middle: 
	if pointer = 150 then move 'if head is already in the middle then go back to move
	if pointer = 75 then ml 
	for counter = 180 to 150 step -1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 150
	goto skipml

ml: 
	for counter = 75 to 150 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 150

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

left: 
	if pointer = 180 then move 
	if pointer = 75 then lmr 
	for counter = 150 to 180 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 180
	goto skiplmr

lmr: 
	for counter = 75 to 180 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 180

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


 

start2: 'Pan head
	if Trigger = 0 then 
		gosub stare 
	endif
	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 Pan,pointer1 'center servo
	pause 8000
	for counter1 = 150 to 100 step -1 
		servopos Pan,counter1
		pause delay1 
	next counter1
	pause 3000

	for counter1 = 100 to 220 step 1
		servopos Pan,counter1 
		pause delay1
	next counter1
	pause 3000

	for counter1 = 220 to 150 step -1
		servopos Pan,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 = 220 to 100 step -1 
		servopos Pan,counter1
		pause delay1
	next counter1
	pointer1 = 100 
	goto skipmr1

mr1: 
	for counter1 = 150 to 100 step -1 
		servopos Pan,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 = 220 to 150 step -1
		servopos Pan,counter1 
		pause delay1
	next counter1
	pointer1 = 150
	goto skipml1

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

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


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

lmr1: 
	for counter1 = 100 to 220 step 1
		servopos Pan,counter1 
		pause delay1
	next counter1
	pointer1 = 220

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

stare:
	servopos Pan, 150
	for counter1 =b17 to 220 step 1
	pause delay1
	next counter1
	if Trigger = 1 then return
	else gotot stare
	endif


start3: 'Tilt head
	let b24=153 'set pointer offset so that head loop does not get stuck
	let b22=150
	let b23=150 'set default center values
	servo Tilt,pointer2 'center servo
	pause 4500
	for counter2 = 150 to 80 step -1 'move head from middle to right side
		servopos Tilt,counter2
		pause delay2
	next counter2
	pause 3000

	for counter2 = 80 to 210 step 1
		servopos Tilt,counter2 'move head from right to left
		pause delay2
	next counter2
	pause 3000

	for counter2 = 210 to 150 step -1
		servopos Tilt,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<80 then left2 'check for random left
	if b23>=80 and b23<=150 then middle2 'check for random middle
	if b23>=150 then right2 'check for random right
	goto move2 'keep moving the head back to move loop

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

mr2: 
	for counter2 = 150 to 80 step -1 'move head from middle to right side
		servopos Tilt,counter2
		pause delay2
	next counter2
	pointer2 = 80 'set head pointer direction to right

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

middle2: 
	if pointer2 = 150 then move2 'if head is already in the middle then go back to move
	if pointer2 = 80 then ml2 'check to see if head is pointed left or right
	for counter2 = 210 to 150 step -1
		servopos Tilt,counter2 'move head from right to middle
		pause delay2
	next counter2
	pointer2 = 150
	goto skipml2

ml2: 
	for counter2 = 80 to 150 step 1
		servopos Tilt,counter2 'move servo from left to middle
		pause delay2
	next counter2
	pointer2 = 150

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


left2: 
	if pointer2 = 210 then move2 'if head is already left then return to move
	if pointer2 = 80 then lmr2 'check if the head is in the middle or the right
	for counter2 = 150 to 210 step 1
		servopos Tilt,counter2 'move head from middle to left
		pause delay2
	next counter2
	pointer2 = 210
	goto skiplmr2

lmr2: 
	for counter2 = 80 to 210 step 1
		servopos Tilt,counter2 'move head from right to left
		pause delay2
	next counter2
	pointer2 = 210

skiplmr2: 
	pause 4000 'delay to look natural
	goto move2 'return to move loop
 
Last edited:

SAborn

Senior Member
You need to use the syntax check as there is syntax errors in your code, like double use of the label "move1" and other errors.

I dont think your use of "else" will work as you want here.
Code:
stare:
	servopos Pan, 150
	for counter1 =b17 to 220 step 1
	pause delay1
	next counter1
	if Trigger = 1 then return
	else goto stare
	endif
Because its sends it back to "stare" which will start another loop of running the servo from the position in "b17" (it will give the head whiplash)
A better option might be to just add another label and jut use a goto that label, something like this.

Code:
stare:
	servopos Pan, 150
	for counter1 =b17 to 220 step 1
	pause delay1
	next counter1

Label_here:

	if Trigger = 1 then return
	endif
       goto Label_here
 

Pat13

Senior Member
You need to use the syntax check as there is syntax errors in your code, like double use of the label "move1" and other errors.

I dont think your use of "else" will work as you want here.
Sorry, my bad. I had been playing around with the indents and renaming some of the labels and had been using syntax check, but didn't before I posted. DOH!

Because it sends it back to "stare" which will start another loop of running the servo from the position in "b17" (it will give the head whiplash)
A better option might be to just add another label and jut use a goto that label, something like this.
I thought that "else" would turn it into a loop, but wasn't sure how to write that, thanks will give that a try. I'm also thinking that as I have "stare" written now, it is going to give the head whiplash going into and coming out of the subroutine. I think I have to do something like this
Code:
stare:
	if pointer1 < 150 then stare1
	if pointer1 > 150 then stare2
	if pointer1 = 220 then stare3
stare1:
	servopos Pan, pointer1
	for counter1 =pointer1 to 220 step 1
	pause delay1
	next counter1
stare2:
	servopos Pan, pointer1
	for counter1 = pointer1 to 220 step 1
	pause delay1
	next counter1
stare3:
	servopos Pan, pointer1
	pause 2000
	
Back:
	if Trigger = 1 then return
	endif
	goto Back
I think that will help with the whiplash when the subroutine is called, not sure what will happen on return.
 

lbenson

Senior Member
It might help you if you run your code through the simulator to see how it works.

In the first three lines, what happens if pointer1 is equal to 150? 220 is > 150, so you'll never get to that third "if" statement.

You have a problem with falling through routines (I think it's not intended). When stare1 is finished, it will drop through to stare2, and stare2 drops through to stare3.

In "Back:", where does "return" return to?

You may want to be using gosubs after your "if pointer1" statements, and then "returns" for each subroutine.
 

Pat13

Senior Member
It might help you if you run your code through the simulator to see how it works.

In the first three lines, what happens if pointer1 is equal to 150? 220 is > 150, so you'll never get to that third "if" statement.

You have a problem with falling through routines (I think it's not intended). When stare1 is finished, it will drop through to stare2, and stare2 drops through to stare3.

In "Back:", where does "return" return to?

You may want to be using gosubs after your "if pointer1" statements, and then "returns" for each subroutine.
Thanks Ibenson. Tried running both codes (3 axis no sub and 3 axis with sub) in simulator but they would get hung up on for..next loops. Not sure how the simulator handles multi tasking.
As far as falling through routines, it is definitely not intended. My Picaxe experience has been solely through my hobby, which is building Halloween props. My schooling in code has been through reading the manuals, studying posted code, experimentation with code and this forum. I'm learning! Just slowly.
I was assuming that "return" would take it back to the point of interruption (pinC.3 low) of the main body of code.
I see what you are saying about gosubs. I changed to this
Code:
stare:
	if pointer1 < 150 then gosub stare1
	if pointer1 > 150 then gosub stare2
	if pointer1 = 150 then gosub stare3
	if pointer1 = 220 then gosub stare4
stare1:
	servopos Pan, pointer1
	for counter1 =pointer1 to 220 step 1
	pause delay1
	next counter1
	return
stare2:
	servopos Pan, pointer1
	for counter1 = pointer1 to 220 step 1
	pause delay1
	next counter1
	return
stare3:
	servopos Pan, pointer1
	for counter1 = pointer1 to 220 step 1
	pause delay1
	next counter1
	return
stare4:
	servopos Pan, pointer1
	pause 2000
	return
	
Back:
	if Trigger = 1 then 
		goto move1
	endif
	goto Back
 

lbenson

Senior Member
Better as far as organization goes, but we really need to see all of the code again.

I don't see that there is any difference in the latest posted code between stare1, stare2, and stare3. If that is intended, you could just do this:
Code:
stare:
	if pointer1 = 220 then 
                gosub stare4
              else 
                gosub stare1
              endif
              return

stare1:
	servopos Pan, pointer1
	for counter1 = pointer1 to 220 step 1
	pause delay1
	next counter1
	return
stare4:
	servopos Pan, pointer1
	pause 2000
	return
Note the "return" at the end of stare (because I assume you have called "stare" as a subroutine). This keeps it from dropping through into
"stare1".

What does "Back:" do? How do you ever get there?

The point about putting the "if pointer1 = 220" statement first (when using "goto"s (explicit or implied)) is that if it is after the "if pointer1 > 150", then it will never be reached, since 220 is greater than 150. This is not the case with gosub--your code will work assuming that you want to do stare2 first, and then stare4.

It might be helpful if you did a rough flowchart of what you wanted to occur based on what events. What are the events which can occur, and what respose do you want your head to make? Events can be switch detections or timer-caused. It seems to me that your process is essentially event-driven, so you need to define events and actions.

Note that in any but the shortest programs, the use of "goto" can produce "spaghetti code", where it is hard for anyone to follow the flow of the program--even, after a few weeks or months, the author. There is controversy, and there are exceptions (like interrupts), but since Edsger Dijkstra's 1968 letter "Go To Statement Considered Harmful", it has been generally considered better form (resulting in easier-to-understand code) to follow "structured" principles--using loops and subroutines to make the program flow easier to follow.
 
Last edited:

hippy

Ex-Staff (retired)
Code:
	servopos Pan, pointer1
	for counter1 = pointer1 to 220 step 1
	pause delay1
	next counter1
	return
In code such as that the servo is moved and then a number of PAUSE are invoked, so the entire FOR-NEXT could be replaced with a single PAUSE.

I would guess that you really want to adjust SERVOPOS within the FOR-NEXT.
 

lbenson

Senior Member
Code:
	servopos Pan, pointer1
	for counter1 = pointer1 to 220 step 1
	pause delay1
	next counter1
	return
In code such as that the servo is moved and then a number of PAUSE are invoked, so the entire FOR-NEXT could be replaced with a single PAUSE.

I would guess that you really want to adjust SERVOPOS within the FOR-NEXT.
As in:
Code:
	for counter1 = pointer1 to 220 step 1
	servopos Pan, counter1
	pause delay1
	next counter1
	return
If ... you actually want to move to 220.

If you want to move from point A to point B (having made sure that they are within the bounds you desire):
Code:
  if A < B then
    stepsize = 1
  else
    stepsize = 0xff ' effectively minus 1
  endif
  for counter1 = A to B step stepsize
    servopos Pan, counter1
    pause delay1
  next counter1
  servopos Pan, B
  return
(Per hippy's post below, 0xff won't work as -1, neither does 0xffff, so his version is the one to use.)
 
Last edited:

hippy

Ex-Staff (retired)
stepsize = 0xff ' effectively minus 1
for counter1 = A to B step stepsize
I'm not sure that will work with PICAXE maths which are 16-bit internal. Best way is to try it, and, to cater for when A=B, I would probably use something like ..

Code:
Select Case A
  Case < B
    For counter1 = A To B Step 1
      :
    Next
  Case > B
    For counter1 = B To A Step -1
      :
    Next
End Select
That can be put into a subroutine. As long as 'B' retains the value of where the servo is, 'A' can be set to where you want it to go, and the routine can be called for any case when you want it to go from where it is to a new position. Or alternatively ...

Code:
MoveToA:
  Do While A <> B
    If A > B Then
      B = B + 1
    Else
      B = B - 1
    End If
    ServoPos <?>, B
    Pause <?>
  Loop
  Return
 

Pat13

Senior Member
Thanks Ibenson and hippy, I appreciate the help, especially taking the time to explain the "why". I will pay closer attention to loops and subroutines from here on.
I don't see that there is any difference in the latest posted code between stare1, stare2, and stare3. If that is intended, you could just do this:
I understand. I don't need to define every pointer1, just that it is or isn't 220.
Note the "return" at the end of stare (because I assume you have called "stare" as a subroutine). This keeps it from dropping through into
"stare1".
What does "Back:" do? How do you ever get there?
I must be misunderstanding how return works. I don't want the program to return until pinC.3 detects logic high. So I thought I had to define that, hence "Back". It was suggested in an earlier post

It might be helpful if you did a rough flowchart of what you wanted to occur based on what events.
I have a very clear idea of what I want to happen. This is for an animatronic display, with several characters narrating and chanting. At the risk of being boring, the display features three witches with randomly moving heads and arms. When the Trick or Treaters push a swiitch the narrative begins, which also initiates "Stare", the witches heads turning (servopos, Pan,220) to look at the ToTs. An 18M2 monitors the switch and selects mp3s from four tenda boards (witch 1, witch2, cauldron bubble, thunderclap) using the "busy" pins on the tenda. Each witch has a minmum of three 08M2s, one dedicated to three axis movement (Pan/Tilt/Nod). It's pinC.3 is also connected to the tenda busy pin, (along with the 18M2). When a witch speaks, she turns (Pan) to look at the ToTs, when she isn't speaking, Pan returns to random servopos. I want the servopos to move smoothly, no whiplash. The picaxes have their own power supply, the servos, tendas and 12VDC gear motors run off a computer power supply. All ground are connected and decoupling caps on everything. I ran this last Halloween, but was using Pololu micromaestrosnstead of 08M2s. Haunters who build these types of displays usually use a program called vsa and run it off a computer. I wanted to use all picaxe.


Code:
	servopos Pan, pointer1
	for counter1 = pointer1 to 220 step 1
	pause delay1
	next counter1
	return
In code such as that the servo is moved and then a number of PAUSE are invoked, so the entire FOR-NEXT could be replaced with a single PAUSE.

I would guess that you really want to adjust SERVOPOS within the FOR-NEXT.
Yes, the main thing is to get it to move to the proper position on command and return to random servopos while elimnating whiplash.

I'm not sure that will work with PICAXE maths which are 16-bit internal. Best way is to try it, and, to cater for when A=B, I would probably use something like ..

Code:
Select Case A
  Case < B
    For counter1 = A To B Step 1
      :
    Next
  Case > B
    For counter1 = B To A Step -1
      :
    Next
End Select
That can be put into a subroutine. As long as 'B' retains the value of where the servo is, 'A' can be set to where you want it to go, and the routine can be called for any case when you want it to go from where it is to a new position. Or alternatively ...

Code:
MoveToA:
  Do While A <> B
    If A > B Then
      B = B + 1
    Else
      B = B - 1
    End If
    ServoPos <?>, B
    Pause <?>
  Loop
  Return
Hippy, that code is way above my payscale, LOL! It will make for some great study! Thank you!
 

lbenson

Senior Member
With a servo, you want to move from where you are to where you want to be. Generally, depending on servo, these positions are signified by a range of values between 75 and 225.

Hippy's code assumes that you know where you are, and that value (between 75 and 225), is stored in the variable "B". "A" contains the value you want to move to, which can either be greater than "B" or less.

As you know, the quickest way to move is "servopos pin,A"--but that moves as fast as the servo can go, and you want to move more slowly. The way to do that is to break up the large jump into a number of small jumps, separated by a small delay. The easiest jump to calculate is one single step.

The number of single steps you need to make is "A - B" (if "A" is greater than "B"), or "B - A" (if "A" is less than "B"). Hippy's code gets from "B" to "A" by incrementing or decrementing "B" until it reaches "A", and issuing the single-step servopos command and pause with each increment or decrement. This makes for a smooth glide from "B" to "A" (unless the delay is too large, in which case the step-wise motion will be apparant).
 
Last edited:

hippy

Ex-Staff (retired)
Yes, it probably helps to put more meaningful names in the code ...

Code:
  whereWeAre = 150
  Servo <?>, whereWeAre
  Do
    whereWeWantToBe =  75 : Gosub MoveToWhereWeWantToBe
    whereWeWantToBe = 225 : Gosub MoveToWhereWeWantToBe
  Loop

MoveToWhereWeWantToBe:
  Do While whereWeWantToBe <> whereWeAre 
    If whereWeWantToBe > whereWeAre Then
      whereWeAre = whereWeAre + 1
    Else
      whereWeAre = whereWeAre - 1
    End If
    ServoPos <?>, whereWeAre 
    Pause <?>
  Loop
  ' When we get here : whereWeAre will be whereWeWantToBe
  Return
 

Pat13

Senior Member
I have had a chance to work on this. I substituted Ibenson's code from post# 14 for my subroutine from post #13. Servo is still not going to subroutine when the Tenda goes low. Wondering if the problem may be hardware. Right now, "Busy" pin of Tenda is connected directly to pinC.3. Do I need a 10K pullup resistor to +5V? When tenda is high it showing 2.3V.
 

lbenson

Senior Member
If you're asking about hardware, we would need to see a schematic. Most viewers won't know what a "Tenda board" is (I don't)--can you provide a reference? Is the "busy" pin active high or low? What causes it to transition low to high or high to low?

If you change the code for test purposes to just execute the subroutine (once) regardless of the state of the tenda busy pin, does it do what you want?

Full program at present also needed.
 

westaust55

Moderator
Ah witches and Tenda boards....
That sounds familiar...

http://www.picaxeforum.co.uk/showthread.php?21877-I-m-not-sure-if-this-will-work
http://www.picaxeforum.co.uk/showthread.php?22083-CHI030A-Issues
http://www.picaxeforum.co.uk/showthread.php?21797-08M2-problems-in-calling-up-files-on-Tenda-module

Actually started by you (Pat13). Is this a new version/enhancement or still working on the original design.

Here is a Tenda Audio module spec/data doc:
http://www.warf.com/download/5028_3652_TDS055 v1.2.pdf
But this version has RS232 interface so we need a link to the modules you have.
Is the busy line open collector and needs a pull-up resistor?

Edit:
Found this Datasheet:
http://www.thaieasyelec.net/archives/Manual/TDB380 datasheet V2[1].0 .pdf
Is this the one?
 
Last edited:

Pat13

Senior Member
Ah witches and Tenda boards....
That sounds familiar...

Actually started by you (Pat13). Is this a new version/enhancement or still working on the original design.
LOL, yes, westaust55, these girls seem to enjoy making my life miserable! It is an enhancement of the original design. I noticed from last year that half of the kids would walk by the witches, (they were triggered by a PIR) as there was only audio to indicate that something was happening. For this year I want the heads to turn to look at the kids and as well, thru a pnp transistor circuit, (to be added later) to have spot lights on each witch when they speak their chants.

http://www.echelleinconnue.net/outils/mobio/composants/TDB380_datasheet_V2_(Tenda_Electronics).pdf
This is the unit I am working with. The busy pin is low active.

Here is the circuit for the Witches:
View attachment Witch circuit.pdf

This is the complete code for the servo movement, which includes the subroutine for panning the head when Tenda goes low active (Start2). The idea is that the heads will hold the fully panned position until the Tenda goes high.
Code:
#Picaxe 08M2 'Gertie 3 axis Witch head


'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
'C.1 is nod servo
'C.2 is tilt servo
'C.4 is pan servo

symbol Nod = C.1
Symbol Pan = C.4
Symbol Tilt = C.2
symbol counter = b9
symbol pointer = b8
symbol delay = 39
symbol counter1 = b19
symbol pointer1 = b18
symbol delay1 = 45
symbol counter2 = b25
symbol pointer2 = b24
symbol delay2 = 55
symbol Trigger = pinC.3

start0:
	main:
	pause 500
	goto main
                
start1:'Nod Head
	let b8=153 'set pointer offset so that head loop does not get stuck
	let b6=150
	let b7=150 'set default center values
		servo Nod,pointer 'center servo
		pause 7500
	for counter = 150 to 75 step -1 
		servopos Nod,counter
		pause delay
	next counter
	pause 3000

	for counter = 75 to 150 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pause 3000

	for counter = 180 to 150 step -1
		servopos Nod,counter 
		pause delay
	next counter
	pause 4000 

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

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


right: 
	if pointer = 75 then move 
	if pointer = 150 then mr 
	for counter = 150 to 75 step -1  
		servopos Nod,counter
		pause delay
	next counter
	pointer = 75 
	goto skipmr

mr: 
	for counter = 150 to 75 step -1 
		servopos Nod,counter
		pause delay
	next counter
	pointer = 75 

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

middle: 
	if pointer = 150 then move 'if head is already in the middle then go back to move
	if pointer = 75 then ml 
	for counter = 180 to 150 step -1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 150
	goto skipml

ml: 
	for counter = 75 to 150 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 150

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

left: 
	if pointer = 180 then move 
	if pointer = 75 then lmr 
	for counter = 150 to 180 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 180
	goto skiplmr

lmr: 
	for counter = 75 to 180 step 1
		servopos Nod,counter 
		pause delay
	next counter
	pointer = 180

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


 

start2: 'Pan head
	if Trigger = 0 then gosub stare 
	
	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 Pan,pointer1 'center servo
	pause 8000
	for counter1 = 150 to 100 step -1 
		servopos Pan,counter1
		pause delay1 
	next counter1
	pause 3000

	for counter1 = 100 to 220 step 1
		servopos Pan,counter1 
		pause delay1
	next counter1
	pause 3000

	for counter1 = 220 to 150 step -1
		servopos Pan,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 = 220 to 100 step -1 
		servopos Pan,counter1
		pause delay1
	next counter1
	pointer1 = 100 
	goto skipmr1

mr1: 
	for counter1 = 150 to 100 step -1 
		servopos Pan,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 = 220 to 150 step -1
		servopos Pan,counter1 
		pause delay1
	next counter1
	pointer1 = 150
	goto skipml1

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

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


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

lmr1: 
	for counter1 = 100 to 220 step 1
		servopos Pan,counter1 
		pause delay1
	next counter1
	pointer1 = 220

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

stare:
	if pointer1 = 220 then 
                gosub stare2
              else 
                gosub stare1
              endif
              return

stare1:
	servopos Pan, pointer1
	for counter1 = pointer1 to 220 step 1
	pause delay1
	next counter1
	return
stare2:
	servopos Pan, pointer1
	pause 2000
	return


start3: 'Tilt head
	let b24=153 'set pointer offset so that head loop does not get stuck
	let b22=150
	let b23=150 'set default center values
	servo Tilt,pointer2 'center servo
	pause 4500
	for counter2 = 150 to 80 step -1 'move head from middle to right side
		servopos Tilt,counter2
		pause delay2
	next counter2
	pause 3000

	for counter2 = 80 to 210 step 1
		servopos Tilt,counter2 'move head from right to left
		pause delay2
	next counter2
	pause 3000

	for counter2 = 210 to 150 step -1
		servopos Tilt,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<80 then left2 'check for random left
	if b23>=80 and b23<=150 then middle2 'check for random middle
	if b23>=150 then right2 'check for random right
	goto move2 'keep moving the head back to move loop

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

mr2: 
	for counter2 = 150 to 80 step -1 'move head from middle to right side
		servopos Tilt,counter2
		pause delay2
	next counter2
	pointer2 = 80 'set head pointer direction to right

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

middle2: 
	if pointer2 = 150 then move2 'if head is already in the middle then go back to move
	if pointer2 = 80 then ml2 'check to see if head is pointed left or right
	for counter2 = 210 to 150 step -1
		servopos Tilt,counter2 'move head from right to middle
		pause delay2
	next counter2
	pointer2 = 150
	goto skipml2

ml2: 
	for counter2 = 80 to 150 step 1
		servopos Tilt,counter2 'move servo from left to middle
		pause delay2
	next counter2
	pointer2 = 150

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


left2: 
	if pointer2 = 210 then move2 'if head is already left then return to move
	if pointer2 = 80 then lmr2 'check if the head is in the middle or the right
	for counter2 = 150 to 210 step 1
		servopos Tilt,counter2 'move head from middle to left
		pause delay2
	next counter2
	pointer2 = 210
	goto skiplmr2

lmr2: 
	for counter2 = 80 to 210 step 1
		servopos Tilt,counter2 'move head from right to left
		pause delay2
	next counter2
	pointer2 = 210

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

Pat13

Senior Member
Here is the code for the Witch chants, which actually controls the Tenda modules.
Code:
'#18M2 Witch scene

symbol Aggie = B.2 'MDFly 1 RX
symbol Gertie = B.0 'MDFly 2 RX
symbol Aggie_BZ = pinB.3 'MDFly 1 Busy
symbol Gertie_BZ =pinB.1 'MDFly 2 busy

symbol Cauldron = B.5 'MDFLY 3 RX
symbol Cauldron_BZ = pinB.4 'MDFly 3 RX

symbol Thunder = B.7'MDFly 4 RX
symbol Thunder_BZ = pinB.6 'MDFly 4 Busy
symbol Brunny_Fly = C.1

symbol Baud =T4800 'tenda baud Rate
symbol Trigger =pinC.2 'trigger, probably PIR
symbol debounce = b5
symbol Retriggertime = w5


Start0:
	
	Retriggertime = 120
		
	Init:	
		high Aggie 'prepare MDFly 1
		pause 400
		high Gertie 'prepare MDFly 2
		pause 400
		high Cauldron 'prepare MDFly 3
		pause 400
		high Thunder 'prepare MDFly 4
		pause 400			
		serout Aggie,Baud,($EF) 'stop MDFly 1
		serout Gertie, Baud, ($EF)'stop MDFly 2
		serout Cauldron, Baud, ($EF) 'stop MDFly 3
		serout Thunder, Baud, ($EF) 'stop MDFly 4
		pause 6000			'wait 6 seconds
		serout Aggie, Baud, ($E8) 'set MDFly 1 volume
		serout Gertie, Baud, ($E8) 'set MDFly 2 volume
		serout Cauldron, Baud, ($E8) 'set MDFly 3 volume
		serout Thunder, Baud, ($E8) 'set MDFly 4 volume
		serout Cauldron, Baud, ($01)
		pause 60000	 'wait 1 minute 

	Waiting:
		
		Do
		serout Cauldron, Baud, ($01)
		let w0 = time
		random w0
		If Trigger = 1 then 
			goto Happy_Halloween
		pause 100
		Endif
		loop while Trigger = 0
			


	Happy_Halloween:
			pause 100
			serout Cauldron, Baud, ($02)
			pause 2000
			do while Cauldron_BZ = 0
			loop
			
			serout Cauldron, Baud, ($01)
			serout Aggie,Baud,($F2,01)
			pause 375
			serout Gertie,Baud, ($F2,01)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F2,02)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F2,03)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F2,04)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F2,05)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Thunder, Baud, ($01)
			pause 2000
			do while Thunder_BZ = 0
			loop
			
			serout Aggie, Baud, ($F2,06)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F2,06)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F2,08)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			high Thunder
			pause 300
			high Brunny_Fly
			serout Thunder, Baud, ($01)
			serout Aggie, Baud, ($F2,10)
			serout Gertie, Baud, ($F2, 08)
			pause 16500
			low Brunny_Fly
			goto Spellcast
			
		Spellcast:
		
			let w0 = time
			random w0
			let b2=w0//8+1
			if b2=1 then 
				goto Its_Halloween
			elseif w1=2 then 
				goto Tonight
			elseif w1=3 then 
				goto Early_Early
			elseif w1=4 then 
				goto MacBeth
			elseif w1=5 then
				goto Kindle
			elseif w1=6 then
				goto Cat
			elseif w1=7 then
				goto Riders
			endif
		
	
		Its_Halloween:
			high Aggie
			pause 300
			high Gertie 
			pause 300
			
			serout Aggie, Baud, ($F3,01)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F3,02)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F3,03)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F3,04)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F3,05)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F3,06)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F3,07)
			pause 2000
			do while Aggie_BZ = 0
			loop			
			
			serout Gertie, Baud, ($F3,08)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			high Thunder
			pause 300
			high Brunny_Fly
			serout Thunder, Baud, ($01)
			serout Aggie, Baud, ($F2,10)
			serout Gertie, Baud, ($F2, 08)
			pause 16500
			low Brunny_Fly
			goto Retriggerdelay
			
		Tonight:
			high Aggie 
			pause 300
			high Gertie
			pause 300
			
			serout Aggie, Baud, ($F4,01)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F4,02)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F4,03)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F4,04)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F4,05)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F4,06)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			high Thunder 
			pause 300
			high Brunny_Fly
			serout Thunder, Baud, ($01)
			serout Aggie, Baud, ($F2,10)
			serout Gertie, Baud, ($F2, 08)
			pause 16500
			low Brunny_Fly
			goto Retriggerdelay
	Early_Early:
			high Aggie
			pause 300
			high Gertie
			pause 300
			
			serout Aggie, Baud, ($F5,01)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F5,02)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F5,03)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F5,04)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F5,05)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F5,06)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F5,07)
			pause 2000
			do while Aggie_BZ = 0
			loop			
			
			serout Gertie, Baud, ($F5,08)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			high Thunder
			pause 300
			high Brunny_Fly
			serout Thunder, Baud, ($01)
			serout Aggie, Baud, ($F2,10)
			serout Gertie, Baud, ($F2, 08)
			pause 16500
			low Brunny_Fly
			goto Retriggerdelay
	MacBeth:
			high Aggie
			pause 300
			high Gertie
			pause 300
			
			serout Aggie, Baud, ($F6,01)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F6,02)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F6,03)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F6,04)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F6,05)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F6,06)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F6,07)
			serout Gertie, Baud, ($F6,07)
			pause 2000
			do while Aggie_BZ = 0
			loop			
			
			serout Aggie, Baud, ($F6,08)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F6,09)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F6,10)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F6,11)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F6,12)
			serout Gertie, Baud, ($F6,12)
			pause 2000
			do while Aggie_BZ = 0
			loop			
			
			serout Gertie, Baud, ($F6,13)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F6,14)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F6,15)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F6,16)
			pause 2000
			do while Aggie_BZ = 0
			loop			
			
			serout Gertie, Baud, ($F6,17)
			pause 2000
			do while Gertie_BZ = 0
			loop
	
			serout Aggie, Baud, ($F6,18)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Aggie, Baud, ($F6,19)
			serout Gertie, Baud, ($F6,19)
			pause 2000
			do while Aggie_BZ = 0
			loop
			
			serout Gertie, Baud, ($F6,20)
			pause 2000
			do while Gertie_BZ = 0
			loop
			
			high Thunder
			pause 300						
			high Brunny_Fly
			serout Thunder, Baud, ($01)
			serout Aggie, Baud, ($F2,10)
			serout Gertie, Baud, ($F2, 08)
			pause 16500
			low Brunny_Fly
			goto Retriggerdelay
		
		Retriggerdelay:                                            
                    Do
                    Pause 1000
                    Retriggertime = Retriggertime -1 
                    Loop Until Retriggertime=0
                    return
I had to remove a couple of the chants (Kindle, Cats and Riders) as it was too many characters to post here.
 

lbenson

Senior Member
Pat,

It may take a while to work through this.

To start with, you should define all of your variables as symbols at the beginning of your program. (With a small program, this may not matter, but with one the size of yours, it will help you keep track of your variables.) For instance, you use w3 and b7 in your random code, but you can't tell this by looking at the start of the program. This is especially important when you need to define a new variable.

Beginning with the executable code, you have no means to get out of this starting loop:
Code:
	main:
	pause 500
	goto main
Note also that it is customary to begin labels at the first column position, so "main:" would not be indented.

"start0:" followed by "main:" is redundant--two labels for the same code--this can create confusion, so I would drop "start0" (and if you refer to it later in the code, replace it with "main").

Consider these three statements:
Code:
symbol pointer = b8
	let b8=153 
 		servo Nod,pointer 'center servo
One defines symbols so that you have given a meaningful name to a variable. Once you have done that, you should use the symbol name and not the "b#" variable, so for the sake of clarity you should use "let pointer = 153" (and the "let" part of the command is optional, so you can just say "pointer = 153").

With respect to indentation, it is customary only to indent within a "block" of code--after a label, within "if", "for", and "do" commands and the like, so "servo Nod,pointer 'center servo" and "pause 7500" should be indented at the same level as the statement above them (which is not the beginning of a new block).

----------
Code:
	for counter = 180 to 150 step -1
		servopos Nod,counter 
		pause delay
	next counter
I don't think this code does what you want it to. The previous "for" loop has left the servo at 150, not 180, so you will jump to 180 and then step down to 150.

---------------

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

Not sure what you want to do here, but you can get a better pseudo-random number sequence if you "seed" the random variable instead of beginning with w3 equal to 0 (the beginning default). This has been explored several times on the forum, but I don't remember the results. I tend to seed with 48611, which happens to be the 5000th prime number, and a fairly large number which will fit in a word.

So seed your random number by putting "w3 = 48611" before "main:".

-----------

Your code doesn't do this, but I'm going to guess that you want the movement randomly divided between left, middle and right. That's three values, so you can get this by getting the remainder of dividing your random value by 3 (giving values of 0, 1, and 2).

You need a temporary value to hold the remainder of that division. I think b2 is available, so I'll use it.
Code:
	random w3
	b2 = w3 // 3 ' get the remainder of dividing w3 by 3
	branch b2,(left,middle,right)
This will go (branch) to left one-third of the time, middle another third, and right the remainder.

Now "right", for instance, goes to various places based on the value of "pointer". "pointer" (b8) was set above at 153 and has not up to this point been changed. Execution will fall through the first two "if" statements and the head will then be moved 75 steps down.

This is as far as I got, but I think this is enough to indicate that you are not keeping good track of where your position is. It might be better if you used "pointer" as a variable +always+ showing what your servo position is, and using a method like hippy's to move to a new position in steps, always using "pointer" to indicate where you are.

So I'd recommend that you try again with your code. Define all the variables, track where you are, and use the simulator to walk through instance after instance to make sure that you are always calculating the values that you expect, moving in the code where you intend to, and moving the head as you wish.
 
Last edited:

Pat13

Senior Member
Pat,

It may take a while to work through this.
Ibenson, if I had a nickel for every time someone said that to me...:)

Again, I can't say enough how much I appreciate you taking time out to walk me thru this. I am gong re work the code, using yours and hippy's suggestions. A couple of ?s. I understand the idea of always knowing where the servo position is. In fact, if I am understanding this correctly, almost all of this code could be basically condensed down to something like hippy's code with random selection of left, middle and right, and maybe even some random pause time. I'm just not sure how to define 'pointer' as always knowing what the servo position is?
Also I am not understanding <?>, precisely, what is the value of '?'.
 

hippy

Ex-Staff (retired)
Wondering if the problem may be hardware. Right now, "Busy" pin of Tenda is connected directly to pinC.3. Do I need a 10K pullup resistor to +5V? When tenda is high it showing 2.3V.
I haven't read the rest of the thread but that sounds like an error in hardware - a low and high fighting each other - either a short on the board or C.3 set as output and opposite polarity to what the Tenda board is putting out. Disconnect the Tenda from C.3 and measure its busy signal voltage.
 

lbenson

Senior Member
In hippy's example, "servo <?>, position", "<?>" just means whichever pin you are using.

One other thing on symbol names--instead of using position, position2, and position3, you might use nodPosition, tiltPosition, panPosition.

Out of curiosity, for your witch, what is the difference between nod and tilt?
 

lbenson

Senior Member
>almost all of this code could be basically condensed down to something like hippy's code with random selection of left, middle and right, and maybe even some random pause time

Right.

Here is an example--random selection of servo (pan, tilt, nod), random selection of movement (minimum, middle, maximum), random selection of delay (among 3 timings), tracking of panPosition, tiltPosition, nodPosition.

Code:
' 08RandomServo.bas randomly moves three servos
#picaxe 08M2

Symbol tiltServo = C.1
symbol nodServo = C.2
Symbol panServo = C.4
symbol Trigger = pinC.3

symbol flags = b0 ' reserved for bit flags [if you need them]
symbol randomPick = b1 ' remainder of division of randomValue for range
symbol tiltPosition = b2 ' keeps track of servo position of tilt servo
symbol nodPosition = b3
symbol panPosition = b4
symbol servoPin = b5 ' assigned tilt, nod, or pan (0,1,or 2)

symbol randomValue = w3 ' includes b6 & b7
symbol position = b8
symbol counter = b9
symbol toPosition = b10 ' where we want to move to
symbol fromPosition = b11 ' where we are moving from
symbol delay = b12 ' delay to use

symbol delay1 = 39
symbol delay2 = 45
symbol delay3 = 55

symbol minimumValue = 75
symbol middleValue = 150
symbol maximumValue = 220


randomValue = 48611 ' seed with large prime number which fits in a word
' initialize servos (center) and position values
servo tiltServo, middleValue
servo nodServo, middleValue
servo panServo, middleValue
tiltPosition = middleValue
nodPosition = middleValue
panPosition = middleValue

main:
  do
    ' randomly pick a servo to move
    random randomValue
    randomPick = randomValue // 3 ' gives value 0, 1, or 2
    lookup randomPick, (tiltServo, nodServo, panServo), servoPin 
    lookup randomPick, (tiltPosition, nodPosition, panPosition), fromPosition 

    ' randomly pick a position to move to (min, mid, max)
    random randomValue
    randomPick = randomValue // 3 ' gives value 0, 1, or 2
    lookup randomPick, (minimumValue, middleValue, maximumValue), toPosition

    ' randomly pick a delay to use (delay1,2, or 3)
    random randomValue
    randomPick = randomValue // 3 ' gives value 0, 1, or 2
    lookup randomPick, (delay1, delay2, delay3), delay

    gosub moveServo

    ' save new position for servo
    select servoPin
      case tiltServo: tiltPosition = toPosition
      case nodServo: nodPosition = toPosition
      case panServo: panPosition = toPosition
    end select
    pause 2000

  loop

moveServo:
  Do While toPosition <> fromPosition 
    If toPosition > fromPosition Then
      fromPosition = fromPosition + 1
    Else
      fromPosition = fromPosition - 1
    End If
    ServoPos servoPin, fromPosition
    Pause delay
  Loop
  return
Tested in the simulator. It doesn't test for movement to the position where the servo already is. In that case, it will drop out of the moveServo routine with no delays.

>Left-upright-right from vertical for tilt - Vertical to front for nod - seems logical

So it does.
 

Pat13

Senior Member
Brilliant ibenson, thanks for this. I've been working on this, trying to come up with a version. I'm going to spend some time studying your code. I'm sure I will have questions.
 
Top