Select Git revision
BasePlane.js
-
amandaghassaei authoredamandaghassaei authored
clStepClient.js 8.33 KiB
/*
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 effortPlot = new AutoPlot(130, 10, 500, 210, 'effort')
effortPlot.setHoldCount(500)
//tempPlot.setYDomain(0, 100)
effortPlot.redraw()
let anglePlot = new AutoPlot(130, 230, 500, 210, 'angle reading')
anglePlot.setHoldCount(500)
//tempPlot.setYDomain(0, 100)
anglePlot.redraw()
let posEstPlot = new AutoPlot(130, 450, 500, 210, 'pos estimate')
posEstPlot.setHoldCount(500)
//tempPlot.setYDomain(0, 100)
posEstPlot.redraw()
let posDotPlot = new AutoPlot(130, 670, 500, 210, 'position dot')
posDotPlot.setHoldCount(500)
posDotPlot.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++
effortPlot.pushPt([specPlotCount, spec.effort]); effortPlot.redraw()
anglePlot.pushPt([specPlotCount, spec.angle]); anglePlot.redraw()
posEstPlot.pushPt([specPlotCount, spec.posEstimate]); posEstPlot.redraw()
posDotPlot.pushPt([specPlotCount, spec.posDot]); posDotPlot.redraw()
setTimeout(loop, 10)
}).catch((err) => {
console.error(err)
specLp = false;
setTimeout(loop, 10)
})
}
}
specLp = true
loop()
}
})
// -------------------------------------------------------- RUN / MODE SWICH
let runBtn = new Button(10, 130, 94, 14, 'run')
runBtn.onClick(() => {
vm.setMode("pid").then(() => {
runBtn.good("ok", 500)
}).catch((err) => {
console.error(err)
runBtn.bad("err", 500)
})
})
let stopBtn = new Button(10, 160, 94, 14, 'stop')
stopBtn.onClick(() => {
vm.setMode("noop").then(() => {
stopBtn.good("ok", 500)
}).catch((err) => {
console.error(err)
stopBtn.bad("err", 500)
})
})
// -------------------------------------------------------- PID Values
let pVal = new TextInput(10, 190, 100, 20, '-0.09')
let iVal = new TextInput(10, 220, 100, 20, '-0.002')
let iLimVal = new TextInput(10, 250, 100, 20, '0.8')
let dVal = new TextInput(10, 280, 100, 20, '-0.0003')
let aVal = new TextInput(10, 310, 100, 20, '0.2')
let aDotVal = new TextInput(10, 340, 100, 20, '0.05')
let pidSetBtn = new Button(10, 370, 94, 14, 'set PID / a')
pidSetBtn.onClick(() => {
let p = parseFloat(pVal.value)
let i = parseFloat(iVal.value)
let ilim = parseFloat(iLimVal.value)
let d = parseFloat(dVal.value)
let a = parseFloat(aVal.value)
let ad = parseFloat(aDotVal.value)
if (Number.isNaN(p) || Number.isNaN(i) || Number.isNaN(d)) {
pidSetBtn.bad("bad parse", 1000)
return
}
vm.setPIDTerms([p, i, ilim, d]).then(() => {
return vm.setAlphas([a, ad])
}).then(() => {
pidSetBtn.good("ok", 500)
}).catch((err) => {
console.error(err)
pidSetBtn.bad("err", 1000)
})
})
let angleRandoBtn = new Button(10, 400, 94, 14, 'targ')
angleRandoBtn.onClick(() => {
let targ = Math.random() * 360
vm.setTarget(targ).then(() => {
angleRandoBtn.good(`${targ.toFixed(3)}`, 250)
}).catch((err) => {
console.error(err)
angleRandoBtn.bad("err", 500)
})
})
let angleWrapBtn = new Button(10, 430, 94, 14, 'wrap')
angleWrapBtn.onClick(() => {
vm.setTarget(360.0).then(() => {
angleWrapBtn.good("ok", 500)
}).catch((err) => {
console.error(err)
angleWrapBtn.bad("err", 500)
})
})
// units per revolution
let uprVal = new TextInput(10, 460, 100, 20, '59.6929')
let uprBtn = new Button(10, 490, 94, 14, 'upr')
uprBtn.onClick(() => {
let upr = parseFloat(uprVal.value)
if(Number.isNaN(upr)){
uprBtn.bad("bad parse", 500)
return
}
vm.setUPR(upr).then(() => {
uprBtn.good("ok", 500)
}).catch((err) => {
console.error(err)
uprBtn.bad("err", 500)
})
})
// -------------------------------------------------------- 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)
}
})