Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Jake Read
ucbus-stepper
Commits
0bba9053
Commit
0bba9053
authored
Feb 15, 2021
by
Jake Read
Browse files
osape -> firmware mod, start tuner interface
parent
a0d55428
Changes
37
Hide whitespace changes
Inline
Side-by-side
.gitmodules
View file @
0bba9053
...
...
@@ -4,3 +4,6 @@
[submodule "controller/osapjs"]
path = controller/osapjs
url = ssh://git@gitlab.cba.mit.edu:846/jakeread/osapjs.git
[submodule "firmware/cl-step-controller/src/osape"]
path = firmware/cl-step-controller/src/osape
url = ssh://git@gitlab.cba.mit.edu:846/jakeread/osape.git
controller/client/clStepClient.js
0 → 100644
View file @
0bba9053
/*
clank-client.js
clank controller client side
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2020
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the open systems assembly protocol (OSAP) project.
Copyright is retained and must be preserved. The work is provided as is;
no warranty is provided, and users accept all liability.
*/
'
use strict
'
import
OSAP
from
'
../osapjs/core/osap.js
'
import
{
TS
,
PK
,
DK
,
AK
,
EP
}
from
'
../osapjs/core/ts.js
'
import
NetRunner
from
'
../osapjs/client/netrunner/osap-render.js
'
// the clank 'virtual machine'
import
ClStepVM
from
'
./clStepVM.js
'
import
{
AutoPlot
}
from
'
../osapjs/client/components/autoPlot.js
'
import
{
Button
}
from
'
../osapjs/client/interface/button.js
'
import
{
TextInput
}
from
'
../osapjs/client/interface/textInput.js
'
console
.
log
(
"
hello clank controller
"
)
// an instance of some osap capable thing (the virtual object)
// that will appear on the network, be virtually addressable
let
osap
=
new
OSAP
()
osap
.
name
=
"
cl-step tuner client
"
// draws network,
let
netrunner
=
new
NetRunner
(
osap
,
10
,
760
,
false
)
// -------------------------------------------------------- THE VM
// vm,
let
vm
=
new
ClStepVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
end
())
// -------------------------------------------------------- QUERY MAG
let
magDiagnosticsBtn
=
new
Button
(
10
,
10
,
94
,
14
,
'
mag?
'
)
magDiagnosticsBtn
.
onClick
(()
=>
{
vm
.
getMagDiagnostics
().
then
((
result
)
=>
{
console
.
log
(
result
)
magDiagnosticsBtn
.
good
(
"
ok
"
,
500
)
}).
catch
((
err
)
=>
{
console
.
error
(
err
)
magDiagnosticsBtn
.
bad
(
"
err
"
,
500
)
})
})
// -------------------------------------------------------- DO CALIB
let
runCalibBtn
=
new
Button
(
10
,
40
,
94
,
14
,
'
calibr8
'
)
runCalibBtn
.
onClick
(()
=>
{
vm
.
runCalib
().
then
(()
=>
{
runCalibBtn
.
good
(
"
ok
"
,
500
)
}).
catch
((
err
)
=>
{
console
.
error
(
err
)
runCalibBtn
.
bad
(
"
err
"
,
500
)
})
})
// -------------------------------------------------------- QUERY POSITION
let
posnLp
=
false
let
positionQueryBtn
=
new
Button
(
10
,
70
,
94
,
14
,
'
pos?
'
)
positionQueryBtn
.
onClick
(()
=>
{
if
(
posnLp
)
{
posnLp
=
false
}
else
{
let
loop
=
()
=>
{
if
(
!
posnLp
)
{
positionQueryBtn
.
bad
(
"
halted
"
,
500
)
}
else
{
vm
.
getPosition
().
then
((
pos
)
=>
{
$
(
positionQueryBtn
.
elem
).
text
(
pos
.
toFixed
(
3
))
setTimeout
(
loop
,
10
)
}).
catch
((
err
)
=>
{
console
.
error
(
err
)
posnLp
=
false
;
setTimeout
(
loop
,
10
)
})
}
}
posnLp
=
true
loop
()
}
})
// -------------------------------------------------------- LOOP SPEC
let
encPlot
=
new
AutoPlot
(
130
,
10
,
500
,
210
,
'
encoder
'
)
encPlot
.
setHoldCount
(
500
)
//tempPlot.setYDomain(0, 100)
encPlot
.
redraw
()
let
anglePlot
=
new
AutoPlot
(
130
,
230
,
500
,
210
,
'
angle reading
'
)
anglePlot
.
setHoldCount
(
500
)
//tempPlot.setYDomain(0, 100)
anglePlot
.
redraw
()
let
angleEstPlot
=
new
AutoPlot
(
130
,
450
,
500
,
210
,
'
angle estimate
'
)
angleEstPlot
.
setHoldCount
(
500
)
//tempPlot.setYDomain(0, 100)
angleEstPlot
.
redraw
()
let
angleDotPlot
=
new
AutoPlot
(
130
,
670
,
500
,
210
,
'
angle dot
'
)
angleDotPlot
.
setHoldCount
(
500
)
angleDotPlot
.
redraw
()
let
specLp
=
false
let
specPlotCount
=
0
let
loopQueryBtn
=
new
Button
(
10
,
100
,
94
,
14
,
'
spec?
'
)
loopQueryBtn
.
onClick
(()
=>
{
if
(
specLp
)
{
specLp
=
false
}
else
{
let
loop
=
()
=>
{
if
(
!
specLp
)
{
loopQueryBtn
.
bad
(
"
halted
"
,
500
)
}
else
{
vm
.
getSpec
().
then
((
spec
)
=>
{
specPlotCount
++
encPlot
.
pushPt
([
specPlotCount
,
spec
.
encoder
]);
encPlot
.
redraw
()
anglePlot
.
pushPt
([
specPlotCount
,
spec
.
angle
]);
anglePlot
.
redraw
()
angleEstPlot
.
pushPt
([
specPlotCount
,
spec
.
angleEstimate
]);
angleEstPlot
.
redraw
()
setTimeout
(
loop
,
10
)
}).
catch
((
err
)
=>
{
console
.
error
(
err
)
specLp
=
false
;
setTimeout
(
loop
,
10
)
})
}
}
specLp
=
true
loop
()
}
})
// -------------------------------------------------------- MOTION FEED
// -------------------------------------------------------- PID
let
PIDController
=
(
xPlace
,
yPlace
)
=>
{
let
pVal
=
new
TextInput
(
xPlace
,
yPlace
+
120
,
110
,
20
,
'
-0.1
'
)
let
iVal
=
new
TextInput
(
xPlace
,
yPlace
+
150
,
110
,
20
,
'
0.0
'
)
let
dVal
=
new
TextInput
(
xPlace
,
yPlace
+
180
,
110
,
20
,
'
0.1
'
)
let
pidSetBtn
=
new
Button
(
xPlace
,
yPlace
+
210
,
104
,
14
,
'
set PID
'
)
pidSetBtn
.
onClick
(()
=>
{
let
p
=
parseFloat
(
pVal
.
value
)
let
i
=
parseFloat
(
iVal
.
value
)
let
d
=
parseFloat
(
dVal
.
value
)
if
(
Number
.
isNaN
(
p
)
||
Number
.
isNaN
(
i
)
||
Number
.
isNaN
(
d
))
{
pidSetBtn
.
bad
(
"
bad parse
"
,
1000
)
return
}
tvm
.
setPIDTerms
([
p
,
i
,
d
]).
then
(()
=>
{
pidSetBtn
.
good
(
"
ok
"
,
500
)
}).
catch
((
err
)
=>
{
console
.
error
(
err
)
pidSetBtn
.
bad
(
"
err
"
,
1000
)
})
})
let
tempPlot
=
new
AutoPlot
(
xPlace
+
120
,
yPlace
,
420
,
230
)
tempPlot
.
setHoldCount
(
500
)
//tempPlot.setYDomain(0, 100)
tempPlot
.
redraw
()
let
effortPlot
=
new
AutoPlot
(
xPlace
+
120
,
yPlace
+
240
,
420
,
150
)
effortPlot
.
setHoldCount
(
500
)
//effortPlot.setYDomain(-10, 10)
effortPlot
.
redraw
()
let
tempLpBtn
=
new
Button
(
xPlace
,
yPlace
+
90
,
104
,
14
,
'
plot temp
'
)
let
tempLp
=
false
let
tempLpCount
=
0
tempLpBtn
.
onClick
(()
=>
{
if
(
tempLp
)
{
tempLp
=
false
tempLpBtn
.
good
(
"
stopped
"
,
500
)
}
else
{
let
poll
=
()
=>
{
if
(
!
tempLp
)
return
tvm
.
getExtruderTemp
().
then
((
temp
)
=>
{
//console.log(temp)
tempLpCount
++
tempPlot
.
pushPt
([
tempLpCount
,
temp
])
tempPlot
.
redraw
()
return
tvm
.
getExtruderTempOutput
()
}).
then
((
effort
)
=>
{
//console.log(effort)
effortPlot
.
pushPt
([
tempLpCount
,
effort
])
effortPlot
.
redraw
()
setTimeout
(
poll
,
200
)
}).
catch
((
err
)
=>
{
tempLp
=
false
console
.
error
(
err
)
tempLpBtn
.
bad
(
"
err
"
,
500
)
})
}
tempLp
=
true
poll
()
}
})
}
//PIDController(240, 10)
// -------------------------------------------------------- STARTUP LOCAL
let
wscVPort
=
osap
.
vPort
()
wscVPort
.
name
=
'
websocket client
'
wscVPort
.
maxSegLength
=
1024
let
LOGPHY
=
false
// to test these systems, the client (us) will kickstart a new process
// on the server, and try to establish connection to it.
console
.
log
(
"
making client-to-server request to start remote process,
"
)
console
.
log
(
"
and connecting to it w/ new websocket
"
)
// ok, let's ask to kick a process on the server,
// in response, we'll get it's IP and Port,
// then we can start a websocket client to connect there,
// automated remote-proc. w/ vPort & wss medium,
// for args, do '/processName.js?args=arg1,arg2'
jQuery
.
get
(
'
/startLocal/osapl-usb-bridge.js
'
,
(
res
)
=>
{
if
(
res
.
includes
(
'
OSAP-wss-addr:
'
))
{
let
addr
=
res
.
substring
(
res
.
indexOf
(
'
:
'
)
+
2
)
if
(
addr
.
includes
(
'
ws://
'
))
{
let
status
=
EP
.
PORTSTATUS
.
OPENING
wscVPort
.
status
=
()
=>
{
return
status
}
console
.
log
(
'
starting socket to remote at
'
,
addr
)
let
ws
=
new
WebSocket
(
addr
)
// opens,
ws
.
onopen
=
(
evt
)
=>
{
status
=
EP
.
PORTSTATUS
.
OPEN
// implement rx
ws
.
onmessage
=
(
msg
)
=>
{
msg
.
data
.
arrayBuffer
().
then
((
buffer
)
=>
{
let
uint
=
new
Uint8Array
(
buffer
)
if
(
LOGPHY
)
console
.
log
(
'
PHY WSC Recv
'
)
if
(
LOGPHY
)
TS
.
logPacket
(
uint
)
wscVPort
.
receive
(
uint
)
}).
catch
((
err
)
=>
{
console
.
error
(
err
)
})
}
// implement tx
wscVPort
.
send
=
(
buffer
)
=>
{
if
(
LOGPHY
)
console
.
log
(
'
PHY WSC Send
'
,
buffer
)
ws
.
send
(
buffer
)
}
}
ws
.
onerror
=
(
err
)
=>
{
status
=
EP
.
PORTSTATUS
.
CLOSED
console
.
log
(
'
sckt err
'
,
err
)
}
ws
.
onclose
=
(
evt
)
=>
{
status
=
EP
.
PORTSTATUS
.
CLOSED
console
.
log
(
'
sckt closed
'
,
evt
)
}
}
}
else
{
console
.
error
(
'
remote OSAP not established
'
,
res
)
}
})
controller/client/cl
ankVirtualMachine
.js
→
controller/client/cl
StepVM
.js
View file @
0bba9053
/*
cl
ankVirtualMachine
.js
c
cl
StepVM
.js
vm for
Clank-CZ
vm for
closed-loop stepper motors
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2021
...
...
@@ -13,31 +13,78 @@ no warranty is provided, and users accept all liability.
*/
import
{
TS
,
PK
,
DK
,
AK
,
EP
}
from
'
../osapjs/core/ts.js
'
import
TempVM
from
'
./tempVirtualMachine.js
'
import
MotorVM
from
'
./motorVirtualMachine.js
'
/* bus ID (osap maps +1)
X: 0
YL: 1
YR: 2, term
Z: 3
TCS: 4
E: 5
HE: 6
LC: 7
BED: 8
*/
export
default
function
ClStepVM
(
osap
,
route
)
{
// ------------------------------------------------------ 0: DIAGNOSTICS QUERY
let
diagnosticsQuery
=
osap
.
query
(
route
,
TS
.
endpoint
(
0
,
0
),
512
)
this
.
getMagDiagnostics
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
diagnosticsQuery
.
pull
().
then
((
data
)
=>
{
let
result
=
{
magHi
:
TS
.
read
(
'
boolean
'
,
data
,
0
,
true
),
magLo
:
TS
.
read
(
'
boolean
'
,
data
,
1
,
true
),
cordicOverflow
:
TS
.
read
(
'
boolean
'
,
data
,
2
,
true
),
compensationComplete
:
TS
.
read
(
'
boolean
'
,
data
,
3
,
true
),
angularGainCorrection
:
TS
.
read
(
'
uint8
'
,
data
,
4
,
true
),
cordicMagnitude
:
TS
.
read
(
'
uint16
'
,
data
,
5
,
true
)
}
resolve
(
result
)
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
// ------------------------------------------------------ 1: RUN CALIB
let
calibEP
=
osap
.
endpoint
()
calibEP
.
addRoute
(
route
,
TS
.
endpoint
(
0
,
1
),
512
)
calibEP
.
setTimeoutLength
(
10000
)
this
.
runCalib
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
calibEP
.
write
(
new
Uint8Array
(
0
)).
then
(()
=>
{
resolve
()
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
// ------------------------------------------------------ 3: POSITION QUERY
let
positionQuery
=
osap
.
query
(
route
,
TS
.
endpoint
(
0
,
3
),
512
)
this
.
getPosition
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
positionQuery
.
pull
().
then
((
data
)
=>
{
let
pos
=
TS
.
read
(
'
float32
'
,
data
,
0
,
true
)
resolve
(
pos
)
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
export
default
function
ClankVM
(
osap
,
route
)
{
// ------------------------------------------------------ 4: LOOP SPEC
// ------------------------------------------------------ MOTION
let
specQuery
=
osap
.
query
(
route
,
TS
.
endpoint
(
0
,
4
),
512
)
this
.
getSpec
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
specQuery
.
pull
().
then
((
data
)
=>
{
let
result
=
{
encoder
:
TS
.
read
(
'
uint16
'
,
data
,
0
,
true
),
angle
:
TS
.
read
(
'
float32
'
,
data
,
2
,
true
),
angleEstimate
:
TS
.
read
(
'
float32
'
,
data
,
6
,
true
)
}
resolve
(
result
)
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
/*
// ------------------------------------------------------ POS
// ok: we make an 'endpoint' that will transmit moves,
let moveEP = osap.endpoint()
// add the machine head's route to it,
moveEP.addRoute(TS.route().portf(0).portf(1).end(), TS.endpoint(0, 1), 512)
// and set a long timeout,
moveEP
.
setTimeoutLength
(
60000
)
// move like: { position: {X: num, Y: num, Z: num}, rate: num }
// moveEP.setTimeoutLength(60000)
this.addMoveToQueue = (move) => {
// write the gram,
let wptr = 0
...
...
@@ -123,19 +170,6 @@ export default function ClankVM(osap, route) {
})
}
// an endpoint to write 'wait time' on the remote,
let
waitTimeEP
=
osap
.
endpoint
()
waitTimeEP
.
addRoute
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
end
(),
TS
.
endpoint
(
0
,
4
),
512
)
this
.
setWaitTime
=
(
ms
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
let
datagram
=
new
Uint8Array
(
4
)
TS
.
write
(
'
uint32
'
,
ms
,
datagram
,
0
,
true
)
waitTimeEP
.
write
(
datagram
).
then
(()
=>
{
resolve
()
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
// endpoint to set per-axis accelerations,
let accelEP = osap.endpoint()
accelEP.addRoute(TS.route().portf(0).portf(1).end(), TS.endpoint(0, 5), 512)
...
...
@@ -179,252 +213,5 @@ export default function ClankVM(osap, route) {
}).catch((err) => { reject(err) })
})
}
// ------------------------------------------------------ MOTORS
// clank cz:
// AXIS SPU INVERT
// X: 320 false
// YL: 320 true
// YR: 320 false
// Z: 924.4r false
// E: 550 true
// per bondtech, for BMG on 16 microsteps, do 415: we are 32 microsteps
// https://www.bondtech.se/en/customer-service/faq/
// however, this is measured & calibrated: 830 was extruding 75mm for a 50mm request
/* bus ID (osap maps +1)
X: 0
YL: 1
YR: 2, term
Z: 3
TCS: 4
E: 5
HE: 6
LC: 7
BED: 8
*/
this
.
motors
=
{
X
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
1
).
end
()),
YL
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
2
).
end
()),
YR
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
3
).
end
()),
Z
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
4
).
end
()),
E
:
new
MotorVM
(
osap
,
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
6
).
end
()),
}
let
motorCurrents
=
[
0.5
,
0.5
,
0.5
,
0.5
,
0.5
]
this
.
setMotorCurrents
=
async
()
=>
{
try
{
await
this
.
motors
.
X
.
setCScale
(
motorCurrents
[
0
])
await
this
.
motors
.
YL
.
setCScale
(
motorCurrents
[
1
])
await
this
.
motors
.
YR
.
setCScale
(
motorCurrents
[
2
])
await
this
.
motors
.
Z
.
setCScale
(
motorCurrents
[
3
])
//await this.motors.E.setCScale(motorCurrents[4])
}
catch
(
err
)
{
console
.
error
(
'
bad motor current set
'
)
throw
err
}
}
// alias...
this
.
enableMotors
=
this
.
setMotorCurrents
this
.
disableMotors
=
async
()
=>
{
try
{
await
this
.
motors
.
X
.
setCScale
(
0
)
await
this
.
motors
.
YL
.
setCScale
(
0
)
await
this
.
motors
.
YR
.
setCScale
(
0
)
await
this
.
motors
.
Z
.
setCScale
(
0
)
await
this
.
motors
.
E
.
setCScale
(
0
)
}
catch
(
err
)
{
console
.
error
(
'
bad motor disable set
'
)
throw
err
}
}
this
.
initMotors
=
async
()
=>
{
// so, really, for these & the disable / enable / set current
// could do them all parallel: like this halts if i.e. YL fails,
// where it might just be that motor with an error... that'd be catching / continuing, accumulating
// errors, and reporting them in a group
try
{
await
this
.
motors
.
X
.
setAxisPick
(
0
)
await
this
.
motors
.
X
.
setAxisInversion
(
false
)
await
this
.
motors
.
X
.
setSPU
(
320
)
}
catch
(
err
)
{
console
.
error
(
'
bad x motor init
'
)
throw
err
}
try
{
await
this
.
motors
.
YL
.
setAxisPick
(
1
)
await
this
.
motors
.
YL
.
setAxisInversion
(
true
)
await
this
.
motors
.
YL
.
setSPU
(
320
)
}
catch
(
err
)
{
console
.
error
(
'
bad yl motor init
'
)
throw
err
}
try
{
await
this
.
motors
.
YR
.
setAxisPick
(
1
)
await
this
.
motors
.
YR
.
setAxisInversion
(
false
)
await
this
.
motors
.
YR
.
setSPU
(
320
)
}
catch
(
err
)
{
console
.
error
(
'
bad yr motor init
'
)
throw
err
}
try
{
await
this
.
motors
.
Z
.
setAxisPick
(
2
)
await
this
.
motors
.
Z
.
setAxisInversion
(
false
)
await
this
.
motors
.
Z
.
setSPU
(
924.444444
)
}
catch
(
err
)
{
console
.
error
(
'
bad z motor init
'
)
throw
err
}
/*
try {
await this.motors.E.setAxisPick(3)
await this.motors.E.setAxisInversion(true)
await this.motors.E.setSPU(550)
} catch (err) {
console.error('bad e motor init')
throw err
}
*/
await
this
.
setMotorCurrents
()
}
// ------------------------------------------------------ TOOLCHANGER
let
tcServoEP
=
osap
.
endpoint
()
tcServoEP
.
addRoute
(
TS
.
route
().
portf
(
0
).
portf
(
1
).
busf
(
1
,
5
).
end
(),
TS
.
endpoint
(
0
,
0
),
512
)
this
.
setTCServo
=
(
micros
)
=>
{
let
wptr
=
0
let
datagram
=
new
Uint8Array
(
4
)
// write micros
wptr
+=
TS
.
write
(
'
uint32
'
,
micros
,
datagram
,
wptr
,
true
)
// do the shipment
return
new
Promise
((
resolve
,
reject
)
=>
{
tcServoEP
.
write
(
datagram
).
then
(()
=>
{
console
.
warn
(
'
tc set
'
,
micros
)
resolve
()
}).
catch
((
err
)
=>
{
reject
(
err
)
})
})
}
this
.
openTC
=
()
=>
{
return
this
.
setTCServo
(
2000
)
}
this
.
closeTC
=
()
=>
{
return
this
.
setTCServo
(
875
)
}
// ------------------------------------------------------ TOOL CHANGING
// tool localization for put-down & pickup, tool statefulness,
// from back left 0,0
// put-down HE at (23.8, -177) -> (23.8, -222.6) -> release -> (-17.8, -208.6) clear -> (-17.8, -183)
// { position: {X: num, Y: num, Z: num}, rate: num }
let
delay
=
(
ms
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
setTimeout
(()
=>
{
resolve
()
},
ms
)
})
}
this
.
delta
=
async
(
move
,
rate
)
=>
{
try
{
if
(
!
rate
)
rate
=
6000
await
this
.
setWaitTime
(
1
)
await
delay
(
5
)
await
this
.
awaitMotionEnd
()
let
cp
=
await
this
.
getPos
()
console
.
log
(
'
current
'
,
cp
)
await
this
.
addMoveToQueue
({
position
:
{
X
:
cp
.
X
+
move
[
0
],
Y
:
cp
.
Y
+
move
[
1
],
Z
:
cp
.
Z
+
move
[
2
]
},
rate
:
rate
})
await
delay
(
5
)
await
this
.
awaitMotionEnd
()
await
this
.
setWaitTime
(
100
)
}
catch
(
err
)
{
console
.
error
(
'
arising during delta
'
)
throw
err
}
}
this
.
goto
=
async
(
pos
,
rate
)
=>
{
try
{
if
(
!
rate
)
rate
=
6000
// set remote queue-wait-time
await
this
.
setWaitTime
(
1
)
await
delay
(
5
)
// wait for the stop
await
this
.
awaitMotionEnd
()