So for the fun of it I did order one of those cameras from Amazon.com (actually through to a different company) and it was only $79.
While I know my brat will never make it be be a mech as it only has HS-475HB servos in it, I thought it would be fun to at least get myself part way there, as I do have a servo on it for a sensor, so I thought I would take up Fish’s challange to make the brat code such that it can do more than one thing at a time. IE while it is stepping, can it turn it’s head and maybe do something on a button press…
So I started hacking on the PS2 Brat code that is part of the new PS2 brat project. I think I have it at least partially working. Right now I am running the code on a test board, which has 3 servos plugged in for one leg and one servo for Head or turret. Next step is to move it to my Brat. This may take a little time as my Brat is currently setup for a TV remote (IRPD) and has an Atom Pro on an ABB, which has not modified for PS2 control. I may swap in my test board or solder in a pull-up resistor. This may take me a little time, so I thought I might post the current work in progress…
The code was changed to have all of the calls to Move moved into the main loop, it also changed the PS2Input function to be called in two different ways. One for the main loop that processes everything, and a second way that is called in the Movement function after an HServo has been issued, while waiting for the HSERVO to complete. I added in this a call back function that you can add code to to test switches or the like. In here I put a call back to the PS2Input. In the PS2Input function I added code to check the state of the right joystick on the PS2 to control the extra servo. Also I have it checking the state of R1 and L1 and have it doing two different actions depending on if it is a button down or a button up transistion. Currently this is just making two different sounds, but could be changed to activate the gun or the like.
Warning: This is a work in progress. Has not been run on a real brat yet, and It may or may not work - so use at your own risk!
[code];Program written for Bot Board II, Basic Atom Pro 28, Basic Micro Studio v1.0.0.4
;Written by Nathan Scherdin, modified by Jim and James Frye
; Mucked up by Kurt
;System variables
righthip con p10
rightknee con p8
rightankle con p7
lefthip con p6
leftknee con p5
leftankle con p4
Turret con p0
;[PS2 Controller]
PS2DAT con P12 ;PS2 Controller DAT (Brown)
PS2CMD con P13 ;PS2 controller CMD (Orange)
PS2SEL con P14 ;PS2 Controller SEL (Blue)
PS2CLK con P15 ;PS2 Controller CLK (White)
PadMode con $79
TRUE con 1
FALSE con 0
BUTTON_DOWN con 0
BUTTON_UP con 1
TravelDeadZone con 4 ;The deadzone for the analog input from the remote
;calibrate steps per degree.
stepsperdegree fcon 166.6
;You must calibrate the servos to “zero”. Each robot will be different!
;When homed in and servos are at 0 degrees the robot should be standing
;straight with the AtomPro chip pointing backward. If you know the number
;of degrees the servo is off, you can calculate the value. 166.6 steps
;per degree. The values for our test robot were found by running the
;program bratosf.bas written by James Frye.
righthip_start con 420
rightknee_start con 600
rightankle_start con -480
lefthip_start con 540
leftknee_start con 0
leftankle_start con 60
;Interrupt init
ENABLEHSERVO
command var byte
fAbortCommand var byte
bat var word
IdleBot var word
WalkSpeed var float
WalkAngle var float
TurretAngle var slong
TurretAngle = 0
TravLength var byte
TravLength = 6
LastStep var byte
LastStep = 0
AnkleAdj var byte
AnkleAdj = 0
BotActive var bit
BotActive = FALSE
idle var byte
junk var word
;[Ps2 Controller]
DualShock var Byte(7)
LastButton var Byte(2)
DS2Mode var Byte
PS2Index var byte
BodyYShift var sbyte
PS2IN var float
;--------------------------------------------------------------------
;[Init]
;PS2 controller
high PS2CLK
LastButton(0) = 255
LastButton(1) = 255
;Init positions
;Note, movement subroutine arguments are Rightankle,Rightknee,Righthip,Leftankle,Leftknee,Lefthip,speed
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
;low 1
;low 2
pause 1000
;---------------------------------------;
;--------Command Quick Reference--------;
;---------------------------------------;
;- Command 0 = Home Position -;
;- Command 1 = Walk Forward -;
;- Command 2 = Walk Backward -;
;- Command 4 = Kick (Left) -;
;- Command 5 = Kick (Right) -;
;- Command 6 = Headbutt -;
;- Command 7 = Get up from Front -;
;- Command 8 = Get up from Back -;
;- Command 9 = Rest Position -;
;- Command 11= Turn Left -;
;- Command 12= Turn Right -;
;- Command 13= Slight Turn Left -;
;- Command 14= Slight Turn Right -;
;---------------------------------------;
sound 9,[50\4000,40\3500,40\3200,50\3900]
;--------------------------------------------------------------------
;[Main Loop]
main:
gosub PS2INPUT[1]
; PS2Input will return a Command number, that we will then call move on.
; We do this here instead of in Ps2Input as Ps2Input will be called from within the
; move function, and this will remove some recursion and hopefully keep more consistent states
; first check to see if we need to do idle processing...
if command <> 0xff then
if(IdleBot = 1000)then
command = 9
elseif(IdleBot = 50)
AnkleAdj = 0
else
IdleBot = IdleBot + 1
endif
endif
;
if command <> 0xff then
gosub move
else
#ifdef USING_BATTERY
adin 16, bat
if (bat < 270) then ;the battery is getting low
sound 9,[50\5000,25\4400,50\5000]
else
pause 50
endif
#else
pause 50
#endif
endif
goto main
;--------------------------------------------------------------------
;[Move]
move:
fAbortCommand = FALSE ; Reset the abort command
if(command = 1) then ; Walk
if LastStep = 0 then
gosub movement WalkAngle, WalkSpeed, WalkSpeed, -WalkAngle,-WalkSpeed,-WalkSpeed,500.0]
gosub movement -WalkAngle, WalkSpeed, WalkSpeed, WalkAngle,-WalkSpeed,-WalkSpeed,500.0]
LastStep = 1
elseif LastStep = 1
gosub movement -WalkAngle,-WalkSpeed,-WalkSpeed, WalkAngle, WalkSpeed, WalkSpeed,500.0]
gosub movement WalkAngle,-WalkSpeed,-WalkSpeed, -WalkAngle, WalkSpeed, WalkSpeed,500.0]
LastStep = 0
endif
AnkleAdj = AnkleAdj + 1
if (AnkleAdj > 6) then
AnkleAdj = 6
endif
elseif(command = 4) ; Kick Left
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
gosub movement -14.0, 0.0, 0.0, 42.0, 0.0, 0.0, 500.0]
gosub movement -23.0, 0.0, 0.0, 0.0,-32.0, 41.0, 500.0]
gosub movement -23.0, 0.0, 0.0, 0.0, 24.0,-20.0, 250.0]
gosub movement -18.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
elseif(command = 5) ; Kick Right
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
gosub movement 42.0, 0.0, 0.0,-14.0, 0.0, 0.0, 500.0]
gosub movement 0.0,-32.0, 41.0,-23.0, 0.0, 0.0, 500.0]
gosub movement 0.0, 24.0,-20.0,-23.0, 0.0, 0.0, 250.0]
gosub movement 0.0, 0.0, 0.0,-18.0, 0.0, 0.0, 500.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
elseif(command = 7) ; Get up from front
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
gosub movement 0.0, 90.0, 45.0, 0.0, 90.0, 45.0, 500.0]
gosub movement 40.0, 90.0,-37.0, 0.0, 90.0, 45.0, 500.0]
gosub movement 0.0, 90.0,-65.0, 0.0, 90.0,-65.0, 500.0]
if not fAbortCommand then
pause 300
endif
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,1000.0]
elseif(command = 8) ; Get up from back
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,1000.0]
gosub movement 0.0,-90.0, 5.0, 0.0,-90.0, 5.0,1000.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,1000.0]
; pause 1000
; gosub movement 0.0, 22.0,-80.0, 0.0, 22.0,-80.0,1000.0]
; gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,1000.0]
elseif(command = 0) ; Home Position
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
; sound 9,[50\4400]
; pause 50
; sound 9,[50\4400]
; pause 50
; sound 9,[50\4400]
elseif(command = 6) ; Headbutt
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
gosub movement 0.0,-50.0,-90.0, 0.0,-50.0,-90.0, 500.0]
gosub movement 0.0, 32.0,-58.0, 0.0, 32.0,-58.0, 400.0]
if not fAbortCommand then
pause 200
endif
gosub movement 0.0,-11.0, 7.0, 0.0,-11.0, 7.0, 500.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
; sound 9,[50\4400]
; pause 50
; sound 9,[50\3960]
; pause 50
; sound 9,[50\3960]
elseif(command = 11) ; Turn left
gosub movement 20.0, 0.0, 0.0,-14.0, 0.0, 0.0,500.0]
gosub movement 20.0,-35.0,-35.0,-14.0, 35.0, 35.0,500.0]
gosub movement 0.0,-35.0,-35.0, 0.0, 35.0, 35.0,500.0]
gosub movement 0.0, 35.0, 35.0, 0.0,-35.0,-35.0,500.0]
gosub movement 20.0, 35.0, 35.0,-14.0,-35.0,-35.0,500.0]
gosub movement 20.0, 0.0, 0.0,-14.0,-35.0,-35.0,500.0]
gosub movement -14.0, 0.0, 0.0, 20.0,-35.0,-35.0,500.0]
gosub movement -14.0, 0.0, 0.0, 20.0, 0.0, 0.0,500.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,500.0]
elseif(command = 12) ; Turn right
gosub movement -14.0, 0.0, 0.0, 20.0, 0.0, 0.0,500.0]
gosub movement -14.0, 35.0, 35.0, 20.0,-35.0,-35.0,500.0]
gosub movement 0.0, 35.0, 35.0, 0.0,-35.0,-35.0,500.0]
gosub movement 0.0,-35.0,-35.0, 0.0, 35.0, 35.0,500.0]
gosub movement -14.0,-35.0,-35.0, 20.0, 35.0, 35.0,500.0]
gosub movement -14.0,-35.0,-35.0, 20.0, 0.0, 0.0,500.0]
gosub movement 20.0,-35.0,-35.0,-14.0, 0.0, 0.0,500.0]
gosub movement 20.0, 0.0, 0.0,-14.0, 0.0, 0.0,500.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,500.0]
elseif(command = 13) ;coarse correct left
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,500.0]
gosub movement 25.0, 0.0, 0.0,-18.0, 0.0, 0.0,500.0]
if not fAbortCommand then
pause 100
endif
gosub movement 2.0,-20.0,-20.0,-18.0, 20.0, 20.0,500.0]
gosub movement 0.0,-20.0,-20.0, 0.0, 20.0, 20.0,500.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,500.0]
elseif(command = 14) ;coarse correct right
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,500.0]
gosub movement -18.0, 0.0, 0.0, 25.0, 0.0, 0.0,500.0]
if not fAbortCommand then
pause 100
endif
gosub movement -18.0, 20.0, 20.0, 2.0,-20.0,-20.0,500.0]
gosub movement 0.0, 20.0, 20.0, 0.0,-20.0,-20.0,500.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,500.0]
elseif(command = 9) ; Rest Position
gosub movement 0.0, 35.0, 40.0, 0.0, 35.0, 40.0,500.0]
endif
IdleBot = 0
return
;--------------------------------------------------------------------
;[PS2Input] reads the input data from the PS2 controller and processes the
;data to the parameters.
fMainInput var byte ; will be non-zero for main loop, 0 for secondary movement calls…
Ps2Input[fMainInput]:
low PS2SEL
shiftout PS2CMD,PS2CLK,FASTLSBPRE,$1\8]
shiftin PS2DAT,PS2CLK,FASTLSBPOST,[DS2Mode\8]
high PS2SEL
pause 1
low PS2SEL
shiftout PS2CMD,PS2CLK,FASTLSBPRE,$1\8,$42\8]
shiftin PS2DAT,PS2CLK,FASTLSBPOST,[DualShock(0)\8, DualShock(1)\8, DualShock(2)\8, DualShock(3)\8, |
DualShock(4)\8, DualShock(5)\8, DualShock(6)\8]
high PS2SEL
pause 1
;serout s_out,i14400,[dec DS2Mode, 13]
;DS2Mode = DS2Mode & 0x7F
if DS2Mode <> PadMode THEN
low PS2SEL
shiftout PS2CMD,PS2CLK,FASTLSBPRE,$1\8,$43\8,$0\8,$1\8,$0\8] ;CONFIG_MODE_ENTER
high PS2SEL
pause 1
low PS2SEL
shiftout PS2CMD,PS2CLK,FASTLSBPRE,$01\8,$44\8,$00\8,$01\8,$03\8,$00\8,$00\8,$00\8,$00\8] ;SET_MODE_AND_LOCK
high PS2SEL
pause 1
low PS2SEL
shiftout PS2CMD,PS2CLK,FASTLSBPRE,$01\8,$4F\8,$00\8,$FF\8,$FF\8,$03\8,$00\8,$00\8,$00\8] ;SET_DS2_NATIVE_MODE
high PS2SEL
pause 1
low PS2SEL
shiftout PS2CMD,PS2CLK,FASTLSBPRE,$01\8,$43\8,$00\8,$00\8,$5A\8,$5A\8,$5A\8,$5A\8,$5A\8] ;CONFIG_MODE_EXIT_DS2_NATIVE
high PS2SEL
pause 1
low PS2SEL
shiftout PS2CMD,PS2CLK,FASTLSBPRE,$01\8,$43\8,$00\8,$00\8,$00\8,$00\8,$00\8,$00\8,$00\8] ;CONFIG_MODE_EXIT
high PS2SEL
pause 100
; sound P9,[100\3000, 100\3500, 100\4000]
return
ENDIF
; Init to say command is 0xff - For now only when we are main input
if FMainInput then
command = 0xff
endif
IF (DualShock(1).bit3 = 0) and LastButton(0).bit3 THEN ;Start Button test
if FMainInput then
IF(BotActive) THEN
'Turn off
Sound P9,[100\4400,80\3800,60\3200]
command = 9
;gosub move
BotActive = False
ELSE
'Turn on
Sound P9,[60\3200,80\3800,100\4400]
command = 0
;gosub move
BotActive = True
ENDIF
else
; If the start button is pressed while a movemet is active we will try to abort out of the current
; movement. We won't update the LastButton state below, so we should then go through here again
; from the main loop to then go to the Turn off state.
fAbortCommand = TRUE ; this should abort us out of the movement
endif
ENDIF
IF BotActive THEN
; Some commands we will only process if we are called from the main loop.
IF fMainInput then ; must of the commands will only be processed by the main input
IF (DualShock(1).bit0 = 0) and LastButton(0).bit0 THEN ;Select Button test
if (TravLength = 8) then
TravLength = 8
Sound P9,[80\3800,60\3200]
else
TravLength = 6
Sound P9,[80\3200,60\3800]
endif
ENDIF
IF (DualShock(1).bit4 = 0) and LastButton(0).bit4 THEN ;Up Button test
command = 7
;gosub move
ENDIF
IF (DualShock(1).bit6 = 0) and LastButton(0).bit6 THEN ;Down Button test
command = 8
;gosub move
ENDIF
IF (DualShock(2).bit4 = 0) and LastButton(1).bit4 THEN ;Triangle Button test
command = 6
;gosub move
ENDIF
; IF (DualShock(2).bit5 = 0) and LastButton(1).bit5 THEN ;Circle Button test
; ENDIF
IF (DualShock(2).bit6 = 0) and LastButton(1).bit6 THEN ;Cross Button test
command = 0
;gosub move
ENDIF
; IF (DualShock(2).bit7 = 0) and LastButton(1).bit7 THEN ;Square Button test
; ENDIF
IF (DualShock(2).bit3 = 0) AND (LastButton(1).bit3 = 1) THEN;R1 Button test
command = 5
;gosub move
ENDIF
IF (DualShock(2).bit2 = 0) AND (LastButton(1).bit2 = 1) THEN;L1 Button test
command = 4
;gosub move
ENDIF
; IF (DualShock(2).bit0 = 0) THEN;AND (LastButton(1).bit0 = 1) THEN ;L2 Button test
; ENDIF
; IF (DualShock(2).bit3 = 0) THEN;AND (LastButton(1).bit3 = 1) THEN ;R2 Button test
; ENDIF
IF (ABS(Dualshock(6)-128) > TravelDeadZone) THEN
PS2IN = TOFLOAT (Dualshock(6) - 128)
if PS2IN > 0.0 then
WalkSpeed = (PS2IN/(TOFLOAT TravLength))
WalkAngle = (((PS2IN/10.0) + 4.0) - (TOFLOAT AnkleAdj))
else;if (Dualshock(6)-128) < 0
WalkSpeed = (PS2IN/(TOFLOAT TravLength))
WalkAngle = -(((PS2IN/10.0) - 4.0) + (TOFLOAT AnkleAdj))
endif
command = 1
;gosub move
ELSEIF (ABS(Dualshock(5)-128) > (TravelDeadZone*4))
PS2IN = TOFLOAT (Dualshock(5) - 128)
if (PS2IN > (TOFLOAT TravelDeadZone)) AND (PS2IN < 70.0) then
command = 14
elseif (PS2IN >= 70.0)
command = 12
elseif (PS2IN < (TOFLOAT -TravelDeadZone)) AND (PS2IN > -70.0)
command = 13
else
command = 11
endif
;gosub move
ENDIF
ENDIF
;
; some commands can be processed in the secondary loop...
;
; For R1 and L1 we want to fire guns? Do two transistion. One when button down
; second when the button comes back up.
IF DualShock(2).bit3 <> LastButton(1).bit3 THEN ; R1 test to see if button changed
IF (DualShock(2).bit3 = 0) THEN
; Button Down
Sound P9,[50\4400]
; hservo [RGUNP\7000\0]
else
; Button up - for now two different quick sounds
; hservo [RGUNP-7000\0]
Sound P9,[50\3200]
endif
ENDIF
; IF (DualShock(2).bit2 = 0) THEN ;L1 Button test
; hservo [LGUNP\7000\0]
; ENDIF
IF (ABS(DualShock(3)-128) > TravelDeadZone) THEN
; We also only process this if the turret servo is idle
gethservo Turret,junk,idle
if(idle)then
TurretAngle = TurretAngle + ((Dualshock(3) - 128)*2)
IF TurretAngle > 12000 THEN
TurretAngle = 12000
ELSEIF TurretAngle < -12000
TurretAngle = -12000
ENDIF
;serout s_out,i14400,[sdec TurretAngle, 13]
hservo [Turret\TurretAngle\0]
endif
ENDIF
ENDIF
; bugbug - some buttons that are process may have to process here...
IF fMainInput then ; must of the commands will only be processed by the main input
LastButton(0) = DualShock(1)
LastButton(1) = DualShock(2)
else
; define which bits we will process here
; 76543210
LBMASK0 con %00001000
LBMASK1 con %00001000
LastButton(0) = (LastButton(0) & !LBMASK0) | (DualShock(1) & LBMASK0)
LastButton(1) = (LastButton(1) & !LBMASK1) | (DualShock(2) & LBMASK1)
endif
return
;--------------------------------------------------------------------
;[MovementCB] = This callback will be called by movement in a loop in between when HServo is called and
; while it waits for the Hservo to complete. The function has the ability to abort the wait and potentially
; other calls to movement by setting the variable fAbortCommand. Note Movement will not clear this flag, as
; this will allow whole sequences to be aborted easily.
MovementCB:
gosub PS2INPUT[0] ; call Ps2input but tell it we are not the main loop
return
;--------------------------------------------------------------------
;
;Should never need to edit anything below this line. Add user subroutines above this and below main.
lefthippos var float
leftkneepos var float
leftanklepos var float
righthippos var float
rightkneepos var float
rightanklepos var float
last_lefthippos var float
last_leftkneepos var float
last_leftanklepos var float
last_righthippos var float
last_rightkneepos var float
last_rightanklepos var float
lhspeed var float
lkspeed var float
laspeed var float
rhspeed var float
rkspeed var float
raspeed var float
speed var float
longestmove var float
;movement [lefthippos,leftkneepos,leftanklepos,righthippos,rightkneepos,rightanklepos,speed]
movement [rightanklepos,rightkneepos,righthippos,leftanklepos,leftkneepos,lefthippos,speed]
; several step movements may be interrupted, so check flag and return.
if fAbortCommand then
return
endif
if(speed<>0.0)then
gosub getlongest[lefthippos-last_lefthippos, |
leftkneepos-last_leftkneepos, |
leftanklepos-last_leftanklepos, |
righthippos-last_righthippos, |
rightkneepos-last_rightkneepos, |
rightanklepos-last_rightanklepos],longestmove
speed = ((longestmovestepsperdegree)/(speed/20.0))
gosub getspeed[lefthippos,last_lefthippos,longestmove,speed],lhspeed
gosub getspeed[leftkneepos,last_leftkneepos,longestmove,speed],lkspeed
gosub getspeed[leftanklepos,last_leftanklepos,longestmove,speed],laspeed
gosub getspeed[righthippos,last_righthippos,longestmove,speed],rhspeed
gosub getspeed[rightkneepos,last_rightkneepos,longestmove,speed],rkspeed
gosub getspeed[rightanklepos,last_rightanklepos,longestmove,speed],raspeed
else
lhspeed=0.0;
lkspeed=0.0;
laspeed=0.0;
rhspeed=0.0;
rkspeed=0.0;
raspeed=0.0;
endif
hservo [lefthip\TOINT (-lefthipposstepsperdegree) + lefthip_start\TOINT lhspeed, |
righthip\TOINT (righthipposstepsperdegree) + righthip_start\TOINT rhspeed, |
leftknee\TOINT (-leftkneeposstepsperdegree) + leftknee_start\TOINT lkspeed, |
rightknee\TOINT (rightkneeposstepsperdegree) + rightknee_start\TOINT rkspeed, |
leftankle\TOINT (-leftankleposstepsperdegree) + leftankle_start\TOINT laspeed, |
rightankle\TOINT (rightanklepos*stepsperdegree) + rightankle_start\TOINT raspeed]
; This version adds a call back function to allow other things to be processed while this movement completes.
Movement_CheckAgain:
do
gethservo lefthip,junk,idle
if(NOT idle)then Movement_DoCallback
gethservo righthip,junk,idle
if(NOT idle)then Movement_DoCallback
gethservo leftknee,junk,idle
if(NOT idle)then Movement_DoCallback
gethservo rightknee,junk,idle
if(NOT idle)then Movement_DoCallback
gethservo leftankle,junk,idle
if(NOT idle)then Movement_DoCallback
gethservo rightankle,junk,idle
if(idle)then Movement_DoReturn
Movement_DoCallBack:
gosub MovementCB
while not fAbortCommand
Movement_DoReturn:
; hservowait [lefthip,righthip,leftknee,rightknee,leftankle,rightankle]
; bugbug: if we abort we may need to do something different here???
last_lefthippos = lefthippos
last_leftkneepos = leftkneepos
last_leftanklepos = leftanklepos
last_righthippos = righthippos
last_rightkneepos = rightkneepos
last_rightanklepos = rightanklepos
return
;--------------------------------------------------------------------
;[getlongest]
one var float
two var float
three var float
four var float
five var float
six var float
getlongest[one,two,three,four,five,six]
if(one<0.0)then
one=-1.0one
endif
if(two<0.0)then
two=-1.0two
endif
if(three<0.0)then
three=-1.0three
endif
if(four<0.0)then
four=-1.0four
endif
if(five<0.0)then
five=-1.0five
endif
if(six<0.0)then
six=-1.0six
endif
if(one<two)then
one=two
endif
if(one<three)then
one=three
endif
if(one<four)then
one=four
endif
if(one<five)then
one=five
endif
if(one<six)then
one=six
endif
return one
;--------------------------------------------------------------------
;[getspeed]
newpos var float
oldpos var float
longest var float
maxval var float
getspeed[newpos,oldpos,longest,maxval]
if(newpos>oldpos)then
return ((newpos-oldpos)/longest)*maxval
endif
return ((oldpos-newpos)/longest)*maxval
[/code]