Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Jake Read
displacementexercise
Commits
ceeff7a9
Commit
ceeff7a9
authored
Jul 10, 2020
by
Jake Read
Browse files
controller calibrated, UI halfway
parent
0c223c5e
Changes
6
Show whitespace changes
Inline
Side-by-side
controller/js/client/dex-client.js
View file @
ceeff7a9
...
...
@@ -14,9 +14,9 @@ no warranty is provided, and users accept all liability.
'
use strict
'
import
GRIDSQUID
from
'
./drawing/gridsquid.js
'
import
{
TS
}
from
'
../core/ts.js
'
import
LeastSquares
from
'
./utes/lsq.js
'
import
DEXUI
from
'
./dex-ui.js
'
import
*
as
dat
from
'
./libs/dat.gui.module.js
'
...
...
@@ -68,6 +68,10 @@ document.addEventListener('keydown', (evt) => {
}
})
// -------------------------------------------------------- Button Smashing
let
UI
=
new
DEXUI
()
// -------------------------------------------------------- DEX Virtual Machine
let
TIMEOUT_MS
=
5000
...
...
@@ -79,6 +83,14 @@ let DEXKEY_MOTORENABLE = 16
let
dex
=
{}
let
lsq
=
new
LeastSquares
()
// donate some x, y readings to calibrate the least squares
// here this was observed integer outputs from the amp, and load applied during those readings
lsq
.
setObservations
(
[[
25
,
14854
,
29649
,
44453
,
74061
,
103695
],
[
0
,
-
0.100
,
-
0.200
,
-
0.300
,
-
0.500
,
-
0.700
]])
// loadcells need to be calibrated,
dex
.
readLoadcell
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
wscPort
.
send
){
...
...
@@ -93,7 +105,7 @@ dex.readLoadcell = () => {
reject
(
'
oddball key after loadcell request
'
)
}
else
{
let
counts
=
TS
.
read
(
'
int32
'
,
data
,
1
,
true
)
resolve
(
counts
)
resolve
(
lsq
.
predict
(
counts
)
)
}
}
setTimeout
(()
=>
{
...
...
@@ -142,9 +154,9 @@ dex.setMotorEnable = (val) => {
reject
(
'
oddball key after motor enable request
'
)
}
else
{
if
(
data
[
1
]
>
0
){
resolve
(
'
enabled
'
)
resolve
(
true
)
}
else
{
resolve
(
'
disabled
'
)
resolve
(
false
)
}
}
}
// end recv
...
...
@@ -155,15 +167,28 @@ dex.setMotorEnable = (val) => {
})
}
dex
.
step
=
(
count
)
=>
{
// mm -> steps,
// microsteps are 16
// pinion is 20T, driven is 124
// lead screw is 1204: 4mm / revolution,
dex
.
spmm
=
(
200
*
16
/
(
20
/
124
))
/
4
dex
.
maxspeed
=
0.5
//mm/s it's slow !
console
.
log
(
'
SPMM
'
,
dex
.
spmm
)
dex
.
step
=
(
mm
)
=>
{
// assert maximum move increment here,
if
(
mm
>
20
)
mm
=
20
if
(
mm
<
-
20
)
mm
=
-
20
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
wscPort
.
send
){
reject
(
'
port to dex is closed
'
)
return
}
// calculate for spmm,
let
steps
=
Math
.
floor
(
-
dex
.
spmm
*
mm
)
console
.
log
(
'
STEPS
'
,
steps
)
let
req
=
new
Uint8Array
(
5
)
req
[
0
]
=
DEXKEY_STEPS
TS
.
write
(
'
int32
'
,
count
,
req
,
1
,
true
)
TS
.
write
(
'
int32
'
,
steps
,
req
,
1
,
true
)
wscPort
.
send
(
req
)
let
rejected
=
false
dex
.
recv
=
(
data
)
=>
{
...
...
@@ -172,13 +197,15 @@ dex.step = (count) => {
reject
(
'
oddball key after step request
'
)
}
else
{
let
increment
=
TS
.
read
(
'
int32
'
,
data
,
1
,
true
)
resolve
(
increment
)
resolve
(
-
increment
/
dex
.
spmm
)
}
}
// end recv
let
moveTime
=
(
Math
.
abs
(
mm
/
dex
.
maxspeed
)
+
5
)
*
1000
console
.
log
(
'
TIME
'
,
moveTime
)
setTimeout
(()
=>
{
rejected
=
true
reject
(
'
timeout
'
)
},
TIMEOUT_MS
)
},
moveTime
)
})
}
...
...
@@ -227,13 +254,16 @@ jQuery.get('/startLocal/dex-usb-bridge.js', (res) => {
console
.
error
(
err
)
})
}
UI
.
start
(
dex
)
}
ws
.
onerror
=
(
err
)
=>
{
console
.
error
(
'
sckt err
'
,
err
)
UI
.
connectionError
(
'
socket closed
'
)
}
ws
.
onclose
=
(
evt
)
=>
{
console
.
error
(
'
sckt closed
'
,
evt
)
wscPort
.
send
=
null
UI
.
connectionError
(
'
socket closed
'
)
}
}
}
else
{
...
...
controller/js/client/dex-ui.js
0 → 100644
View file @
ceeff7a9
/*
dex-ui.js
dex interface 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.
*/
export
default
function
DEXUI
(){
// the machine object,
let
dex
=
null
this
.
start
=
(
machine
)
=>
{
console
.
warn
(
'
alive
'
)
dex
=
machine
clear
()
}
// when lower levels bail, refreshing is the move
this
.
connectionError
=
(
msg
)
=>
{
console
.
error
(
'
HALT
'
)
}
// elements
let
dom
=
$
(
'
#wrapper
'
).
get
(
0
)
// UI util
let
setPosition
=
(
div
,
x
,
y
)
=>
{
$
(
dom
).
append
(
div
)
$
(
div
).
css
(
'
left
'
,
`
${
x
}
px`
).
css
(
'
top
'
,
`
${
y
}
px`
)
}
// hold flag
let
waitUi
=
$
(
'
<div>
'
).
addClass
(
'
flag
'
).
get
(
0
)
setPosition
(
waitUi
,
180
,
50
)
let
waitStatus
=
false
let
waiting
=
()
=>
{
waitStatus
=
true
$
(
waitUi
).
css
(
'
background-color
'
,
'
#f7bbb7
'
)
}
let
clear
=
()
=>
{
waitStatus
=
false
$
(
waitUi
).
css
(
'
background-color
'
,
'
#b7f7c3
'
)
}
let
isWaiting
=
()
=>
{
return
waitStatus
}
clear
()
// incremental stacks
let
ypos
=
50
let
yinc
=
30
// position / zero
let
position
=
0
let
posDisplay
=
$
(
'
<div>
'
).
addClass
(
'
button
'
).
get
(
0
)
setPosition
(
posDisplay
,
50
,
ypos
)
posDisplay
.
update
=
(
num
)
=>
{
position
=
num
$
(
posDisplay
).
text
(
`
${
num
.
toFixed
(
5
)}
mm`
)
}
posDisplay
.
update
(
position
)
$
(
posDisplay
).
click
((
evt
)
=>
{
position
=
0
posDisplay
.
update
(
position
)
})
let
enableButton
=
$
(
'
<div>
'
).
addClass
(
'
button
'
).
get
(
0
)
setPosition
(
enableButton
,
50
,
ypos
+=
yinc
)
let
motorEnabled
=
false
enableButton
.
update
=
(
state
)
=>
{
if
(
state
){
motorEnabled
=
true
$
(
enableButton
).
text
(
'
disable motor
'
)
$
(
enableButton
).
css
(
'
background-color
'
,
'
#b7f7c3
'
)
}
else
{
motorEnabled
=
false
$
(
enableButton
).
text
(
'
enable motor
'
)
$
(
enableButton
).
css
(
'
background-color
'
,
'
#f7bbb7
'
)
}
}
enableButton
.
update
(
motorEnabled
)
$
(
enableButton
).
click
((
evt
)
=>
{
if
(
isWaiting
())
return
waiting
()
let
req
=
!
motorEnabled
dex
.
setMotorEnable
(
req
).
then
((
state
)
=>
{
clear
()
enableButton
.
update
(
state
)
}).
catch
((
err
)
=>
{
clear
()
console
.
error
(
err
)
})
})
// increment-by
let
incBy
=
$
(
'
<input type="text" value="5">
'
).
addClass
(
'
inputwrap
'
).
get
(
0
)
setPosition
(
incBy
,
50
,
ypos
+=
yinc
)
//console.log(incBy.value)
// up-button
let
incUp
=
$
(
'
<div>
'
).
addClass
(
'
button
'
).
get
(
0
)
setPosition
(
incUp
,
50
,
ypos
+=
yinc
)
$
(
incUp
).
text
(
'
jog up
'
)
$
(
incUp
).
click
((
evt
)
=>
{
if
(
isWaiting
())
return
waiting
()
dex
.
step
(
parseFloat
(
incBy
.
value
)).
then
((
increment
)
=>
{
clear
()
posDisplay
.
update
(
position
+=
increment
)
}).
catch
((
err
)
=>
{
clear
()
console
.
error
(
err
)
})
})
// down-button
let
incDown
=
$
(
'
<div>
'
).
addClass
(
'
button
'
).
get
(
0
)
setPosition
(
incDown
,
50
,
ypos
+=
yinc
)
$
(
incDown
).
text
(
'
jog down
'
)
$
(
incDown
).
click
((
evt
)
=>
{
if
(
isWaiting
())
return
waiting
()
dex
.
step
(
parseFloat
(
incBy
.
value
)
*
-
1
).
then
((
increment
)
=>
{
clear
()
posDisplay
.
update
(
position
+=
increment
)
}).
catch
((
err
)
=>
{
clear
()
console
.
error
(
err
)
})
})
// reading / zero
let
load
=
0
let
loadDisplay
=
$
(
'
<div>
'
).
addClass
(
'
button
'
).
get
(
0
)
setPosition
(
loadDisplay
,
50
,
ypos
+=
yinc
+
10
)
loadDisplay
.
update
=
(
num
)
=>
{
load
=
num
$
(
loadDisplay
).
text
(
`
${
num
.
toFixed
(
3
)}
N`
)
}
loadDisplay
.
update
(
load
)
$
(
loadDisplay
).
click
((
evt
)
=>
{
if
(
isWaiting
())
return
waiting
()
dex
.
tareLoadcell
().
then
(()
=>
{
clear
()
loadDisplay
.
update
(
0
)
}).
catch
((
err
)
=>
{
clear
()
console
.
error
(
err
)
})
})
// read request
let
readReq
=
$
(
'
<div>
'
).
addClass
(
'
button
'
).
get
(
0
)
setPosition
(
readReq
,
50
,
ypos
+=
yinc
)
$
(
readReq
).
text
(
'
read loadcell
'
)
$
(
readReq
).
click
((
evt
)
=>
{
if
(
isWaiting
())
return
waiting
()
dex
.
readLoadcell
().
then
((
load
)
=>
{
clear
()
loadDisplay
.
update
(
load
)
}).
catch
((
err
)
=>
{
clear
()
console
.
error
(
err
)
})
})
// testing
// test-by
let
testStep
=
$
(
'
<input type="text" value="0.01">
'
).
addClass
(
'
inputwrap
'
).
get
(
0
)
setPosition
(
incBy
,
50
,
ypos
+=
yinc
+
10
)
// start / stop testing
let
testButton
=
$
(
'
<div>
'
).
addClass
(
'
button
'
).
get
(
0
)
setPosition
(
testButton
,
50
,
ypos
+=
yinc
)
let
testing
=
false
testButton
.
update
=
(
state
)
=>
{
if
(
state
){
testing
=
true
$
(
testButton
).
text
(
'
disable motor
'
)
$
(
testButton
).
css
(
'
background-color
'
,
'
#b7f7c3
'
)
}
else
{
testing
=
false
$
(
testButton
).
text
(
'
enable motor
'
)
$
(
testButton
).
css
(
'
background-color
'
,
'
#f7bbb7
'
)
}
}
testButton
.
update
(
testing
)
$
(
testButton
).
click
((
evt
)
=>
{
if
(
testing
){
// start testing
}
else
{
// stop testing
}
})
}
controller/js/client/style.css
View file @
ceeff7a9
...
...
@@ -40,6 +40,37 @@ body {
position
:
absolute
;
}
.flag
{
position
:
absolute
;
width
:
20px
;
height
:
20px
;
}
.button
{
position
:
absolute
;
width
:
100px
;
height
:
20px
;
padding
:
5px
;
background-color
:
#dbdbdb
;
color
:
#000
;
font-size
:
15px
;
text-align
:
center
;
}
.button
:hover
{
background-color
:
#e6e6e6
;
cursor
:
pointer
;
}
.inputwrap
{
position
:
absolute
;
width
:
100px
;
height
:
20px
;
padding
:
5px
;
border
:
none
;
background-color
:
#dbdbdb
;
}
/* svg bs */
.svgcont
{
...
...
controller/js/client/utes/lsq.js
0 → 100644
View file @
ceeff7a9
/*
lsq.js
input previous system measurements as state (lists)
make predictions for y based on input at x, with lsq. from old data
*/
import
smallmath
from
'
./smallmath.js
'
export
default
function
LeastSquares
()
{
// internal state
let
observations
=
[]
let
m
=
1
let
b
=
0
// setup
this
.
setObservations
=
(
xy
)
=>
{
observations
=
JSON
.
parse
(
JSON
.
stringify
(
xy
))
if
(
observations
[
0
].
length
>
2
){
let
lsqr
=
smallmath
.
lsq
(
observations
[
0
],
observations
[
1
])
m
=
lsqr
.
m
b
=
lsqr
.
b
}
}
// to generate human-readable interp of model
this
.
printFunction
=
()
=>
{
if
(
b
>=
0
)
{
return
`
${
m
.
toExponential
(
2
)}
x +
${
b
.
toExponential
(
2
)}
`
}
else
{
return
`
${
m
.
toExponential
(
2
)}
x
${
b
.
toExponential
(
2
)}
`
}
}
this
.
predict
=
(
x
)
=>
{
return
m
*
x
+
b
}
}
controller/js/client/utes/smallmath.js
0 → 100644
View file @
ceeff7a9
// least squares from https://medium.com/@sahirnambiar/linear-least-squares-a-javascript-implementation-and-a-definitional-question-e3fba55a6d4b
// mod to return object of m, b, values.x, values.y,
var
smallmath
=
{
lsq
:
function
(
values_x
,
values_y
)
{
var
x_sum
=
0
;
var
y_sum
=
0
;
var
xy_sum
=
0
;
var
xx_sum
=
0
;
var
count
=
0
;
/*
* The above is just for quick access, makes the program faster
*/
var
x
=
0
;
var
y
=
0
;
var
values_length
=
values_x
.
length
;
if
(
values_length
!=
values_y
.
length
)
{
throw
new
Error
(
'
The parameters values_x and values_y need to have same size!
'
);
}
/*
* Above and below cover edge cases
*/
if
(
values_length
===
0
)
{
return
[
[],
[]
];
}
/*
* Calculate the sum for each of the parts necessary.
*/
for
(
let
i
=
0
;
i
<
values_length
;
i
++
)
{
x
=
values_x
[
i
];
y
=
values_y
[
i
];
x_sum
+=
x
;
y_sum
+=
y
;
xx_sum
+=
x
*
x
;
xy_sum
+=
x
*
y
;
count
++
;
}
/*
* Calculate m and b for the line equation:
* y = x * m + b
*/
var
m
=
(
count
*
xy_sum
-
x_sum
*
y_sum
)
/
(
count
*
xx_sum
-
x_sum
*
x_sum
);
var
b
=
(
y_sum
/
count
)
-
(
m
*
x_sum
)
/
count
;
/*
* We then return the x and y data points according to our fit
*/
var
result_values_x
=
[];
var
result_values_y
=
[];
for
(
let
i
=
0
;
i
<
values_length
;
i
++
)
{
x
=
values_x
[
i
];
y
=
x
*
m
+
b
;
result_values_x
.
push
(
x
);
result_values_y
.
push
(
y
);
}
return
{
m
:
m
,
b
:
b
,
values
:
{
x
:
result_values_x
,
y
:
result_values_y
}
}
}
}
export
default
smallmath
controller/js/local/dex-usb-bridge.js
View file @
ceeff7a9
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment