Bot Board II

Hello,

I am trying to use the Lynxmotion AL5D Robotic Arm with predefined motions when pressed buttons on the Lynxmotion PS2 wireless controller. The wireless receiver is hooked up to the Bot Board II. The Bot Board II then goes to the SSC-32 Servo Controller which is then connected to the arm.

I was wondering if it were possible to eliminate the SSC-32 from the equation? I haven’t found any examples of controlling the servos with just the Bot Board II but was wondering if is possible.

Thank you!

Here is an example…

lynxmotion.com/images/html/build148.htm

Before using the SSC-32 a command such as this worked perfectly:
serout p15,i38400,"#0 P2300 #2 P1500 #3 P2000 #4 P2000 #5 P3000",13]

What am I missing in order to control the servos with only the Bot Board II?

I have added this declaration:

;[PIN NUMBERS]
BasePin con P0 ;Base Connection
ShoulderPin con P1 ;Shoulder Connection
ElbowPin con P2 ;Elbow Connection
WristPin con P3 ;Wrist Connection
WristRotatePin con P5 ;Wrist Rotation Connection (Optional)

Thanks!

I don’t even know where to start…

Try studying the code in this tutorial. It’s for a BRAT not an arm, but it doesn’t really matter. You will need to remove some BRAT specific things. But study this part of the code.

lynxmotion.com/images/html/build155.htm

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]

The values are in degrees I believe, and the last value is the time in mS for each part of the sequence. Study the entire code and ask questions.

Ok I have adopted the example code and I am able to completely able to control the arm using the PS2 controller.

I am trying to create defined arm motions by the press of the triangle button.

I have this code in the PS2Input gosub routine:
{
IF (DualShock(2).bit4 = 0) and LastButton(1).bit4 THEN ;Triangle Button

	 gosub movement   0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 500.0] 
     gosub movement -80.0,  0.0,  0.0, 0.0,  0.0,  0.0, 500.0] 
  	
   ENDIF 

}
Instead of rotating the base 80 degrees the arm simply jolts for less than a second. Am I forgetting anything? Do I need to specify the amount of time it should take to make the movement?

Thank you Jim you have been great help!

My guess is that once the movement is done, the code will then go to the default code, where it will probably have some variable defined like BaseAngle or the like and it will tell the arm to go to that location. IE there is probably code that takes the input from the ps2 controller joysticks and updates the different angles to the new desired location.

Kurt

I have tried to make the arm do predefined movements two different ways, each with their own difficulties. With both methods I am having trouble controlling the speed of the movements.

Method 1
With this code the shoulder and elbow do not move.
IF (DualShock(2).bit4 = 0) and LastButton(1).bit4 THEN ;Triangle Button
'starting postition
BaseAngle1=-200
ShoulderAngle1=300
ElbowAngle1=400
GlobalGripperAngle1=-550
TargetGripper1=0
Gripper1=0
TargetWristAngle1=0
WristRotateAngle1=0
ENDIF

I have found that the values are not in degrees. The range of motion for the servos are:
Base -900,900]
Shoulder -780,900]
Elbow -780,900]
Gripper [720,680]
Wrist Rotate -760,830]
Divide by 10 to get degrees.

Method 2
When I use code such as this, after the 3000 pause the arm continues to make undefined movements.
IF (DualShock(2).bit7 = 0) and LastButton(1).bit7 THEN ;Square Button test
gosub movement [0, 0, 0, 0, 0, 0, 0]
pause 3000
ENDIF

In both methods the arm does unpredictable movements when using a long pause such as 3000. Using shorter pauses such as 10 or 100 just skip the first step and go’s to the last step.

I believe that the angle is in 1/10th of a degree. So base of ±900 is ±90 degrees…

But more to the issue. I am not sure which program you are using. If you are using something like a striped down version of rover V1.2.bas, then The issues are, that once your code is done, you go back into the main loop, you will see something like:

[code]main:

#IF EnableFSR=1
;Read analog input
adin GripperFSRPin, GripperPressure
#ELSE
GripperPressure=1000
#ENDIF

;Read remote input
GOSUB Ps2Input

; rover stuff removed…

;[ARM CALCULATIONS]

;Inverse Kinematic calculations
GOSUB ArmIK [WristPosX, WristPosY, GlobalGripperAngle1]
ShoulderAngle1 = -IKShoulderAngle1+900
ElbowAngle1 = IKElbowAngle1+900
WristAngle1 = -IKWristAngle1

GOSUB CheckLimits

GOSUB WaitForPrevMove ;Wait for servos to finish the previous move

IF ArmOn THEN
IF ArmOn AND Prev_ArmOn=0 THEN
Sound P9,[60\4000,80\4500,100\5000]
gosub InitArm

  GlobalGripperAngle1=0
ENDIF

GOSUB Movement-BaseAngle1, -ShoulderAngle1, -ElbowAngle1, -WristAngle1, -Gripper1, -WristRotateAngle1, 50][/code]

What you notice here is that as soon as the code goes back to Main: it checks for new PS2 input or in your case, it completes the call to PS2Input and then calls:

GOSUB ArmIK [WristPosX, WristPosY, GlobalGripperAngle1] 

Which uses those 3 variables to calculate the new angles for the different servos and then a little more stuff and then calls off to Movement with it’s own calculated values.

Some options that may work for you:
a) Set some mode variable when you press your button, that says, don’t do anything else in main loop. Question would be how to clear it again… Sort-of how the on/off works… Could be press same button again on PS2 to clear. Could add code that if any of the 4 joystick values are out of the dead-band, to clear the flag…
b) Have your code set those 3 values…

Kurt

Doh!!! Extreme sorrow…

I forgot to include the link. lynxmotion.com/images/html/build155.htm

Kurt and Autobot…

Because Autobot expressed interest in having the arm do a series of movements from a PS2 button press I pointed him to the BRAT tutorial. However I neglected to include the link… :blush:

Now my post might make a little more sense?

I edited the post…

I have been using the http://www.lynxmotion.com/images/html/build148.htm tutorial. I have arranged the jumpers and pins the same as the tutorial. Only the battery input closest to the PWR LED works. I have tested the connections for the other PWR source to verify that it works. The code has a subroutine causing the alarm to go off when low battery ie. it is always going off. Is the jumper layout in the tutorial correct?

Two examples were provided. The first allows you to move the arm in real time from the PS2 controller. The second example is for a BRAT, and it sends a series of movements whenever a certain button is pressed.

From your previous posts it sounded to me like you needed the second tutorial not the first.

We are not telling you how to write a program, we are telling you what to change in the programs in the tutorials.

It’s really not clear to me at all what you have done and what the code looks like.

Please follow the nomenclature we have established. There are two places to connect power. VS is for servo power and VL is for logic, or the microcontroller power. VS is 6vdc, and VL can be 7-9vdc. Applying power to the VL will light up the power LED, but applying power the the VS will not.

The code has nothing to do with battery voltage. Where did you read that? The beeping is bwecause the PS2 is not connected or connected wrong.

Here is a link to the manual for the BotBoard… hint hint >.<

lynxmotion.com/s-4-electroni … .aspx#micr

Thanks for all your help. I have the arm going to all of the predefined positions that I wanted it to using the move and movement functions from the PS2 Biped BRAT Tutorial. :slight_smile:

Are there any general rules to follow with the speed given to a movement and pauses after the command? One of my commands defaults to speed 0 and that is way to quick.

The quick movement only occurs when I press the button for the first time. The following button presses the action is performed at the assigned speed which is much slower.

Here is the code. The issue I have is with command 4. The first time L2 is pressed the motor performs the command really fast. The following times it behaves as intended.

[code];System variables
base con p4 'base
shoulder con p5 'shoulder
elbow con p6 'elbow
wrist con p7 'wristpostion
spoon con p8 'spoon rotate
table con p10 'table position

NUMSERVOS con 6
aServoOffsets var sword(NUMSERVOS)
ServoTable bytetable base, shoulder, elbow, wrist, spoon, table

;[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

;Interrupt init
ENABLEHSERVO

command var byte
bat var word

IdleBot var word
WalkSpeed var float
WalkAngle var float

TravLength var byte
TravLength = 6
LastStep var byte
LastStep = 0
AnkleAdj var byte
AnkleAdj = 0

BotActive var bit
BotActive = FALSE

;[Ps2 Controller]
DualShock var Byte(7)
LastButton var Byte(2)
DS2Mode var Byte
PS2Index var byte
BodyYShift var sbyte
PS2IN var float

;PS2 controller
high PS2CLK
LastButton(0) = 255
LastButton(1) = 255

;Matt Added
LastCommand var byte
TableLoc var float

;==============================================================================
; Complete initialization
;==============================================================================
aServoOffsets = rep 0\NUMSERVOS ; Use the rep so if size changes we should properly init

; try to retrieve the offsets from EEPROM:

; see how well my pointers work
gosub ReadServoOffsets

;Init positions

;Note, movement subroutine arguments are base,shoulder,elbow,wrist,spoon,table,speed
TableLoc = -79.9
gosub movement -80.0, 0.0, -35.0,40.0,-80, TableLoc, 1000.0]

;low 1
;low 2
pause 1000

;---------------------------------------;
;--------Command Quick Reference--------;
;---------------------------------------;
;- Command 0 = Home Position -;
;- Command 4 = Spin Table -;
;- Command 5 = reast to Feed -;
;- Command 5 2nd time = Feed -;
;- Command 9 = Rest Position -;
;---------------------------------------;

main

gosub PS2INPUT

if(IdleBot = 1000)then
command = 9
gosub move
elseif(IdleBot = 50)
AnkleAdj = 0
else
IdleBot = IdleBot + 1
pause 15
endif

adin 16, bat

'if (bat < 270) then ;the battery is getting low
'sound 9,[50\5000,25\4400,50\5000]
'else
'pause 50
'endif

goto main

move:
if(command = 1) then

  elseif(command = 4)	; L2 was pressed				
  	if(LastCommand <> 4) then ' IF the last command was not 4 THEN move to the "ready position"
  		gosub movement -42.0, 10.0, -35.0,40.0,0.0, TableLoc, 700.0]
  		pause 200
  		gosub movement -42.0, 0.0, -35.0,40.0,0.0, TableLoc, 700.0]
     endif
			;--------------------------------------;
			;----Table Position Wuick Reference----;
			;--------------------------------------;
			;- Position 1 = -71.9		          -;
			;- Position 2 = -25.3                 -;
			;- Position 3 =  21.3             	  -;
			;- Position 4 =  67.9        	      -;
			;--------------------------------------;
	;evaluates the current location of the table and moves to the next location
	if(LastCommand = 4) then
		if(TableLoc = -71.9) then 
  			TableLoc = -25.3
     		gosub movement -42.0,  0.0, -35.0,40.0,-80, TableLoc, 2000.0]
     		elseif(TableLoc = -25.3)
     		TableLoc = 21.3
     		gosub movement -42.0,  0.0, -35.0,40.0,-80, TableLoc, 2000.0]
     		elseif(TableLoc = 21.3)
     		TableLoc = 67.9
     		gosub movement -42.0,  0.0, -35.0,40.0,-80, TableLoc, 2000.0]
     		elseif(TableLoc = 67.9)
     		TableLoc = -71.9
     		gosub movement -42.0,  0.0, -35.0,40.0,-80, TableLoc, 2000.0] 	
     	endif	
     endif

     
  elseif(command = 5)					'R2 was pressed	
  ;IF in the "ready" position initiate feed sequence 	
  	if(LastCommand <> 9) then		
  	;Feed Sequence									
     	gosub movement -42.0,  0.0, -35.0, 40.0, -80.0, TableLoc, 700.0] 
     	Pause 10
     	gosub movement -42.0, -11.0,-45.0, 55.0,-80.0, TableLoc, 800.0]
     	Pause 500
     	gosub movement -42.0, -11.0,-40.0, 55.0, 89.0, TableLoc, 800.0]
     	pause 500
     	gosub movement  10.0, 0.0, 15.0,-10.0, 89.0, TableLoc, 1000.0]
     	
    else	
    ;IF in the "home" position move to the "ready" position
  		gosub movement -80.0,  0.0, -35.0,40.0,-80, TableLoc, 700.0] 
     	pause 700
     	gosub movement -61.0,  0.0, -10.0, 0.0,-80.0, TableLoc, 700.0] 
     	pause 400
     	gosub movement -42.0,  0.0, -35.0,40.0,-80.0, TableLoc, 700.0]
     	pause 700
     	gosub movement -42.0,  0.0, -35.0, 40.0,-80.0, TableLoc, 700.0]
     	
     endif
   
 
   elseif(command = 0)							; Home Position 
     gosub movement -80.0,  0.0, -35.0,40.0,-80, TableLoc, 800.0]
     gosub movement -80.0,  0.0, -35.0,40.0,-80, -71.9, 2000.0]
     
     
  elseif(command = 9)							; Rest Position 
     gosub movement -80.0,  0.0, -35.0,40.0,-80, TableLoc, 800.0]
      gosub movement -80.0,  0.0, -35.0,40.0,-80, -71.9, 2000.0]
     
  endif

IdleBot = 0
return

;--------------------------------------------------------------------
;[PS2Input] reads the input data from the PS2 controller and processes the
;data to the parameters.
Ps2Input:

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

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
	
return

ENDIF

IF (DualShock(1).bit3 = 0) and LastButton(0).bit3 THEN ;Start Button test
IF(BotActive) THEN
'Turn off send to home position
Sound P9,[100\4400,80\3800,60\3200]
command = 9
gosub move
lastcommand = 9
BotActive = False
ELSE
'Turn on
Sound P9,[60\3200,80\3800,100\4400]
TableLoc = -71.9 'set table location to location 1
command = 0
gosub move
LastCommand = 9
BotActive = True
ENDIF
ENDIF

IF BotActive THEN

IF (DualShock(2).bit1 = 0) AND (LastButton(1).bit3 = 1) THEN ;R2 Button
	command = 5
	gosub move
	LastCommand = 5
ENDIF

IF (DualShock(2).bit0 = 0) AND (LastButton(1).bit0 = 1) THEN ;L2 Button
	command = 4
	gosub move
	LastCommand = 4
ENDIF

IF (ABS(Dualshock(6)-128) > TravelDeadZone) AND (BotActive = TRUE) 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)) AND (BotActive = TRUE)
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

LastButton(0) = DualShock(1)
LastButton(1) = DualShock(2)
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,righthippos,leftkneepos,rightkneepos,leftanklepos,rightanklepos,speed]
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; aServoOffsets(
rkspeed=0.0;
raspeed=0.0;
endif
hservo [base\TOINT (-lefthippos
stepsperdegree) + aServoOffsets(3)\TOINT lhspeed, |
shoulder\TOINT (righthipposstepsperdegree) + aServoOffsets(0)\TOINT rhspeed, |
elbow\TOINT (-leftkneepos
stepsperdegree) + aServoOffsets(4)\TOINT lkspeed, |
wrist\TOINT (rightkneeposstepsperdegree) + aServoOffsets(1)\TOINT rkspeed, |
spoon\TOINT (-leftanklepos
stepsperdegree) + aServoOffsets(5)\TOINT laspeed, |
table\TOINT (rightanklepos*stepsperdegree) + aServoOffsets(2)\TOINT raspeed]
hservowait [base,shoulder,elbow,wrist,spoon]

;idle var byte
;finished var byte
;junk var word
;sensorloop
; finished = true
; gethservo lefthip,junk,idle
; if(NOT idle)then
; finished=false
; endif
; gethservo righthip,junk,idle
; if(NOT idle)then
; finished=false
; endif
; gethservo leftknee,junk,idle
; if(NOT idle)then
; finished=false
; endif
; gethservo rightknee,junk,idle
; if(NOT idle)then
; finished=false
; endif
; gethservo leftankle,junk,idle
; if(NOT idle)then
; finished=false
; endif
; gethservo rightankle,junk,idle
; if(NOT idle)then
; finished=false
; endif
;add sensor handling code here

; if(NOT finished)then sensorloop

last_lefthippos = lefthippos
last_leftkneepos = leftkneepos
last_leftanklepos = leftanklepos
last_righthippos = righthippos
last_rightkneepos = rightkneepos
last_rightanklepos = rightanklepos

return

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.0
two
endif
if(three<0.0)then
three=-1.0three
endif
if(four<0.0)then
four=-1.0
four
endif
if(five<0.0)then
five=-1.0five
endif
if(six<0.0)then
six=-1.0
six
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

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

;==============================================================================
; Subroutine: ReadServoOffsets
; Will read in the zero points that wer last saved for the different servos
; that are part of this robot.
;
;==============================================================================
pT var pointer ; try using a pointer variable
cSOffsets var byte ; number of
bCSIn var byte
bCSCalc var byte ; calculated checksum
b var byte ;
i var byte

ReadServoOffsets:
readdm 0, [cSOffsets, bCSIn]
;serout s_out, i9600, “RSO: cnt:”, dec cSOffsets, " CS in:", hex bcsIn];

if (cSOffsets > 0) and (cSOffsets <= NUMSERVOS) then 		; offset data is bad so go to error location

	; OK now lets read in the array of data
	readdm 2, [str aServoOffsets\csOffsets*2]
	
	;... calculate checksum...
	bCSCalc = 0

	for i = 0 to NUMSERVOS-1
		bCSCalc = AServoOffsets(i).lowbyte + AServoOffsets(i).highbyte

; serout s_out, i9600, " “, sdec aServoOffsets(i),”:", hex aServoOffsets(i)]
next

; serout s_out, i9600, " CS Calc:", hex bCSCalc]

	if bCSCalc <> bCSIn then 
		aServoOffsets = rep 0\NUMSERVOS
	endif
endif

; serout s_out, i9600, [13]
return[/code]

Looks like your speed value is off. When you press the button for the first time, it looks here:

if(LastCommand <> 4) then ' IF the last command was not 4 THEN move to the "ready position" gosub movement -42.0, 10.0, -35.0,40.0,0.0, TableLoc, 700.0] pause 200 gosub movement -42.0, 0.0, -35.0,40.0,0.0, TableLoc, 700.0] endif700. When you press the button again, it looks here:

if(LastCommand = 4) then if(TableLoc = -71.9) then TableLoc = -25.3 gosub movement -42.0, 0.0, -35.0,40.0,-80, TableLoc, 2000.0] elseif(TableLoc = -25.3) TableLoc = 21.3 gosub movement -42.0, 0.0, -35.0,40.0,-80, TableLoc, 2000.0] elseif(TableLoc = 21.3) TableLoc = 67.9 gosub movement -42.0, 0.0, -35.0,40.0,-80, TableLoc, 2000.0] elseif(TableLoc = 67.9) TableLoc = -71.9 gosub movement -42.0, 0.0, -35.0,40.0,-80, TableLoc, 2000.0] endif endifAll have a value of 2000.

I have changed all of the values to 2000. I am still having the same problem. I noticed that when I remove the pause 200 The arm’s first movement is really quick as well.

Note: with HSERVO (and SSC-32 as well), The first movement will always be fast. Why? Because there is no way for the system to know where the servos are, so when the BB2 (or SSC-32) issues the first pulse to a servo, the servo will jump as quick as it can to that position. It is only after those servos receive pulses can the processor incrementally move it to the next location.

The best way to minimize the effect of this, is to have the servos start up in some known location and have your first servo outputs go to that position. For example for an Arm it is nice to have the Arm start up in some default parked location…

Hope that makes sense.

Kurt