From 37bea394e4debe8c4348fe1d6b57a7cc5cc91b45 Mon Sep 17 00:00:00 2001
From: Jake <jake.read@cba.mit.edu>
Date: Sun, 9 Dec 2018 12:50:06 -0500
Subject: [PATCH] robot program ready for forward transform and lsqr
---
README.md | 1 +
client/client.js | 2 +
modules/util/array.js | 8 +-
modules/util/collector.js | 77 ++++
modules/util/gate.js | 6 +-
modules/util/gateCounter.js | 79 ++++
modules/util/parallelContencator.js | 93 +++++
programs/temp.json | 564 ++++++++++++++++++++++++++++
robot.js | 11 +-
rundmc.js | 4 +-
10 files changed, 832 insertions(+), 13 deletions(-)
create mode 100644 modules/util/collector.js
create mode 100644 modules/util/gateCounter.js
create mode 100644 modules/util/parallelContencator.js
create mode 100644 programs/temp.json
diff --git a/README.md b/README.md
index 509b6be..d2f4db3 100644
--- a/README.md
+++ b/README.md
@@ -316,6 +316,7 @@ View.assignProgram(program)
- module deletion seems unclean
- input / output objects should be able to unhook themselves:
- keep references of what-is-attached ?
+ - would like to be able to default prevent state variables from being changed by users, i.e. in 'collector' the 'count' variable
## WRT Representations
diff --git a/client/client.js b/client/client.js
index 851796a..4ca0cd2 100644
--- a/client/client.js
+++ b/client/client.js
@@ -510,6 +510,8 @@ document.onkeydown = function(evt) {
case 'd':
console.log(program)
break
+ case 'k':
+ socketSend('save program', 'temp')
default:
break
}
diff --git a/modules/util/array.js b/modules/util/array.js
index ade6932..9de3e74 100644
--- a/modules/util/array.js
+++ b/modules/util/array.js
@@ -49,12 +49,12 @@ function UIArray() {
// here's our input callback, specified in the input constructor
function onThruInput(input){
- if(typeof input == 'number'){
- state.number = input
+ if(Array.isArray(input)){
+ state.array = input
+ onArrayDesire()
} else {
- state.number = parseFloat(input)
+ console.log("ERR input to array module is non-array")
}
- onArrayDesire()
}
function onArrayDesire(){
diff --git a/modules/util/collector.js b/modules/util/collector.js
new file mode 100644
index 0000000..d34e8ab
--- /dev/null
+++ b/modules/util/collector.js
@@ -0,0 +1,77 @@
+// boilerplate rndmc header
+const JSUnit = require('../../src/jsunit.js')
+let Input = JSUnit.Input
+let Output = JSUnit.Output
+let State = JSUnit.State
+
+// interface elements
+const JSUI = require('../../src/jsui.js')
+let UI = JSUI.UI
+
+/*
+collector
+
+takes samples from what-ever output, stores in an array until a 'dump' input,
+outputs that array, clears internals
+
+*/
+
+// a constructor, a fn, a javascript mess
+function Collector() {
+
+ // this is the tiny program-as-and-object that we'll load into rundmc
+ // description / name is required to load successfully
+ var collector = {
+ description: {
+ name: 'collector',
+ alt: 'collect and dump'
+ }
+ }
+
+ // the State() object is what the system scrapes for ui variables / updates from the UI
+ // this includes things like Button('title', callback), which are unique state variables
+ // they can also be found in jsunit.js
+ collector.state = State()
+ // alias !
+ var state = collector.state
+
+ state.count = 0
+
+ var collection = new Array()
+
+ collector.ui = UI()
+ var ui = collector.ui
+ ui.addElement('onDumpButton', './ui/uiButton.js', onDumpDesire)
+ ui.onDumpButton.onload = function() {
+ ui.onDumpButton.setText('array out ->')
+ }
+
+ // inputs are required, and must be Input('type', callback)
+ collector.inputs = {
+ collect: Input('any', onNewItem), // makes anything into num event
+ dump: Input('evt', onDumpDesire)
+ }
+
+ // outputs: Output('type')
+ collector.outputs = {
+ pass: Output('any')
+ }
+
+ // here's our input callback, specified in the input constructor
+ function onNewItem(input){
+ collection.push(input)
+ state.count = collection.length
+ }
+
+ function onDumpDesire(){
+ collector.outputs.pass.emit(collection)
+ collection = new Array()
+ state.count = collection.length
+ }
+
+ // gotta give the program this thing we made
+ return collector
+}
+
+// this for node.js's require() function
+module.exports = Collector
\ No newline at end of file
diff --git a/modules/util/gate.js b/modules/util/gate.js
index 7378615..7a24c4b 100644
--- a/modules/util/gate.js
+++ b/modules/util/gate.js
@@ -29,7 +29,7 @@ function Gate() {
var ui = gate.ui
ui.addElement('openButton', './ui/uiButton.js', onButtonPress)
ui.openButton.onload = function() {
- ui.openButton.setText('toggle gate')
+ ui.openButton.setText('click to open gate')
}
// yikes
@@ -44,14 +44,14 @@ function Gate() {
}
function onButtonPress(evt) {
- console.log("GATE BUTTON")
if (gate.isOpen) {
gate.isOpen = false
state.message = 'closed'
+ ui.openButton.setText('click to open gate')
} else {
gate.isOpen = true
state.message = 'open'
- //gate.outputs.out.emit('go')
+ ui.openButton.setText('click to close gate')
}
}
diff --git a/modules/util/gateCounter.js b/modules/util/gateCounter.js
new file mode 100644
index 0000000..b367b56
--- /dev/null
+++ b/modules/util/gateCounter.js
@@ -0,0 +1,79 @@
+// boilerplate header
+const JSUnit = require('../../src/jsunit.js')
+let Input = JSUnit.Input
+let Output = JSUnit.Output
+let State = JSUnit.State
+
+// interface elements
+const JSUI = require('../../src/jsui.js')
+let UI = JSUI.UI
+
+// a constructor, a fn, a javascript mess
+function GateCounter() {
+
+ var gateCounter = {
+ // descriptions are used in UI
+ description: {
+ name: 'gateCounter',
+ alt: 'in ... out'
+ }
+ }
+
+ gateCounter.state = State()
+ // alias !
+ var state = gateCounter.state
+
+ state.addThis = 10
+ state.count = 0
+
+ gateCounter.ui = UI()
+ var ui = gateCounter.ui
+ ui.addElement('openButton', './ui/uiButton.js', onButtonPress)
+ ui.openButton.onload = function() {
+ ui.openButton.setText('click to add ' + state.addThis.toString() + ' to count')
+ }
+
+ state.onUiChange('addThis', function(){
+ ui.openButton.setText('click to add ' + state.addThis.toString() + ' to count')
+ })
+
+ // yikes
+ gateCounter.isOpen = false
+
+ gateCounter.inputs = {
+ thru: Input('any', gateCounterKeeper), // makes anything into '1' event
+ setCount: Input('number', onSetCount),
+ addEvent: Input('any', onAddEvent)
+ }
+
+ gateCounter.outputs = {
+ out: Output('any')
+ }
+
+ function onButtonPress(evt) {
+ console.log("gateCounter BUTTON")
+ state.count += state.addThis
+ }
+
+ function onSetCount(num){
+ state.addThis = num
+ state.count = num
+ }
+
+ function onAddEvent(evt){
+ state.count = state.addThis
+ }
+
+ function gateCounterKeeper(input) {
+ if (state.count > 0) {
+ var outVar = JSON.parse(JSON.stringify(input))
+ gateCounter.outputs.out.emit(outVar)
+ state.count --
+ }
+ }
+
+ return gateCounter
+}
+
+// exports
+module.exports = GateCounter
\ No newline at end of file
diff --git a/modules/util/parallelContencator.js b/modules/util/parallelContencator.js
new file mode 100644
index 0000000..14647e2
--- /dev/null
+++ b/modules/util/parallelContencator.js
@@ -0,0 +1,93 @@
+// boilerplate rndmc header
+const JSUnit = require('../../src/jsunit.js')
+let Input = JSUnit.Input
+let Output = JSUnit.Output
+let State = JSUnit.State
+
+// interface elements
+const JSUI = require('../../src/jsui.js')
+let UI = JSUI.UI
+
+// a constructor, a fn, a *hot* javascript mess
+function ParallelContencator() {
+
+ // this is the tiny program-as-and-object that we'll load into rundmc
+ // description / name is required to load successfully
+ var parallelContencator = {
+ description: {
+ name: 'parallelContencator',
+ alt: 'inputs -> arrays'
+ }
+ }
+
+ // the State() object is what the system scrapes for ui variables / updates from the UI
+ // this includes things like Button('title', callback), which are unique state variables
+ // they can also be found in jsunit.js
+ parallelContencator.state = State()
+ // alias !
+ var state = parallelContencator.state
+
+ state.gateKeep = true
+
+ parallelContencator.ui = UI()
+ var ui = parallelContencator.ui
+ ui.addElement('onOutputButton', './ui/uiButton.js', doThroughput)
+ ui.onOutputButton.onload = function() {
+ ui.onOutputButton.setText('array out ->')
+ }
+
+ // inputs are required, and must be Input('type', callback)
+ parallelContencator.inputs = {
+ in0: Input('any', onIn0),
+ in1: Input('any', onIn1),
+ push: Input('evt', doThroughput) // makes anything into num event
+ }
+
+ // outputs: Output('type')
+ parallelContencator.outputs = {
+ out: Output('array')
+ }
+
+ var contencated = [0, 0]
+ var recent = [false, false]
+
+ function onIn0(inp) {
+ contencated[0] = inp
+ recent[0] = true
+ doGateCheck()
+ }
+
+ function onIn1(inp) {
+ contencated[1] = inp
+ recent[1] = true
+ doGateCheck()
+ }
+
+ function doGateCheck() {
+ if (state.gateKeep) {
+ var count = 0
+ recent.forEach(function(element) {
+ if (element) {
+ count++
+ }
+ })
+ if (count == recent.length) {
+ doThroughput()
+ }
+ } else {
+ doThroughput()
+ }
+ }
+
+ function doThroughput() {
+ // here's how we fire an output.
+ parallelContencator.outputs.out.emit(contencated)
+ recent.fill(false)
+ }
+
+ // gotta give the program this thing we made
+ return parallelContencator
+}
+
+// this for node.js's require() function
+module.exports = ParallelContencator
\ No newline at end of file
diff --git a/programs/temp.json b/programs/temp.json
new file mode 100644
index 0000000..904ccd3
--- /dev/null
+++ b/programs/temp.json
@@ -0,0 +1,564 @@
+{
+ "description": {
+ "name": "new program",
+ "counter": 14
+ },
+ "modules": {
+ "SerialportATKLink-0": {
+ "description": {
+ "isHardware": true,
+ "isLink": true,
+ "name": "SerialportATKLink",
+ "alt": "window into hardware world",
+ "id": "SerialportATKLink-0",
+ "path": "./modules/hardware/atkseriallink.js",
+ "position": {
+ "left": 734,
+ "top": -191
+ }
+ },
+ "inputs": {},
+ "outputs": {},
+ "state": {
+ "portName": "---",
+ "portStatus": "closed",
+ "log": true
+ },
+ "ui": {
+ "kickButton": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "atk-math-robot-joint-1": {
+ "description": {
+ "name": "atk-math-robot-joint",
+ "alt": "software representation of networked hardware object",
+ "isHardware": true,
+ "id": "atk-math-robot-joint-1",
+ "path": "./modules/hardware/atkmrobot.js",
+ "position": {
+ "left": 600,
+ "top": 50
+ }
+ },
+ "inputs": {
+ "tick": {
+ "accepts": "event"
+ },
+ "set_pc_t": {
+ "accepts": "number"
+ },
+ "get_pos": {
+ "accepts": "event"
+ }
+ },
+ "outputs": {
+ "ok": {
+ "emits": "nothing-yet",
+ "calls": []
+ },
+ "pos": {
+ "emits": "uint16_t",
+ "calls": [
+ {
+ "parentId": "logger-6",
+ "key": "thru"
+ },
+ {
+ "parentId": "gateCounter-9",
+ "key": "thru"
+ }
+ ]
+ }
+ },
+ "state": {
+ "message": "no packet yet",
+ "route": "0,0",
+ "enc_cnt": 16384,
+ "pc_t": 2048,
+ "pKp": 4.5,
+ "pKi": 0,
+ "pKd": 0,
+ "cKp": 4,
+ "cKi": 0,
+ "walk": 1024
+ },
+ "ui": {
+ "walkValButton": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "atk-math-robot-joint-2": {
+ "description": {
+ "name": "atk-math-robot-joint",
+ "alt": "software representation of networked hardware object",
+ "isHardware": true,
+ "id": "atk-math-robot-joint-2",
+ "path": "./modules/hardware/atkmrobot.js",
+ "position": {
+ "left": 600,
+ "top": 450
+ }
+ },
+ "inputs": {
+ "tick": {
+ "accepts": "event"
+ },
+ "set_pc_t": {
+ "accepts": "number"
+ },
+ "get_pos": {
+ "accepts": "event"
+ }
+ },
+ "outputs": {
+ "ok": {
+ "emits": "nothing-yet",
+ "calls": []
+ },
+ "pos": {
+ "emits": "uint16_t",
+ "calls": [
+ {
+ "parentId": "gateCounter-12",
+ "key": "thru"
+ },
+ {
+ "parentId": "logger-14",
+ "key": "thru"
+ }
+ ]
+ }
+ },
+ "state": {
+ "message": "no packet yet",
+ "route": "0,1",
+ "enc_cnt": 16384,
+ "pc_t": 2048,
+ "pKp": 4.5,
+ "pKi": 0,
+ "pKd": 0,
+ "cKp": 4,
+ "cKi": 0,
+ "walk": 1024
+ },
+ "ui": {
+ "walkValButton": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "Button-3": {
+ "description": {
+ "name": "Button",
+ "alt": "for clicking",
+ "id": "Button-3",
+ "path": "./modules/ui/button.js",
+ "position": {
+ "left": 90,
+ "top": 50
+ }
+ },
+ "inputs": {
+ "thru": {
+ "accepts": "any"
+ }
+ },
+ "outputs": {
+ "whammy": {
+ "emits": "number",
+ "calls": [
+ {
+ "parentId": "atk-math-robot-joint-1",
+ "key": "get_pos"
+ },
+ {
+ "parentId": "delay-4",
+ "key": "thru"
+ },
+ {
+ "parentId": "atk-math-robot-joint-2",
+ "key": "get_pos"
+ }
+ ]
+ }
+ },
+ "state": {},
+ "ui": {
+ "btn": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "delay-4": {
+ "description": {
+ "name": "delay",
+ "alt": "in ... out",
+ "id": "delay-4",
+ "path": "./modules/util/delay.js",
+ "position": {
+ "left": 90,
+ "top": 250
+ }
+ },
+ "inputs": {
+ "thru": {
+ "accepts": "any"
+ }
+ },
+ "outputs": {
+ "out": {
+ "emits": "any",
+ "calls": [
+ {
+ "parentId": "gate-5",
+ "key": "thru"
+ }
+ ]
+ }
+ },
+ "state": {
+ "ms": 100
+ },
+ "ui": {}
+ },
+ "gate-5": {
+ "description": {
+ "name": "gate",
+ "alt": "in ... out",
+ "id": "gate-5",
+ "path": "./modules/util/gate.js",
+ "position": {
+ "left": 90,
+ "top": 400
+ }
+ },
+ "inputs": {
+ "thru": {
+ "accepts": "any"
+ }
+ },
+ "outputs": {
+ "out": {
+ "emits": "any",
+ "calls": [
+ {
+ "parentId": "Button-3",
+ "key": "thru"
+ }
+ ]
+ }
+ },
+ "state": {
+ "message": "closed"
+ },
+ "ui": {
+ "openButton": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "logger-6": {
+ "description": {
+ "name": "logger",
+ "alt": "in ... out to console",
+ "id": "logger-6",
+ "path": "./modules/util/log.js",
+ "position": {
+ "left": 1318,
+ "top": -170
+ }
+ },
+ "inputs": {
+ "thru": {
+ "accepts": "any"
+ }
+ },
+ "outputs": {
+ "throughput": {
+ "emits": "any",
+ "calls": []
+ }
+ },
+ "state": {
+ "prefix": "JTN1:",
+ "message": "---"
+ },
+ "ui": {}
+ },
+ "ThreeJS-Canvas-7": {
+ "description": {
+ "name": "ThreeJS-Canvas",
+ "alt": "graphix",
+ "id": "ThreeJS-Canvas-7",
+ "path": "./modules/ui/threeCanvas.js",
+ "position": {
+ "left": 2263,
+ "top": 326
+ }
+ },
+ "inputs": {
+ "xy1": {
+ "accepts": "array"
+ },
+ "xy2": {
+ "accepts": "array"
+ }
+ },
+ "outputs": {},
+ "state": {},
+ "ui": {
+ "threeCanvas": {
+ "type": "threeCanvas",
+ "clientPath": "ui/threeCanvas.js",
+ "libPath": "ui/libs/three.js"
+ }
+ }
+ },
+ "collector-8": {
+ "description": {
+ "name": "collector",
+ "alt": "collect and dump",
+ "id": "collector-8",
+ "path": "./modules/util/collector.js",
+ "position": {
+ "left": 1728,
+ "top": 1057
+ }
+ },
+ "inputs": {
+ "collect": {
+ "accepts": "any"
+ },
+ "dump": {
+ "accepts": "evt"
+ }
+ },
+ "outputs": {
+ "pass": {
+ "emits": "any",
+ "calls": []
+ }
+ },
+ "state": {
+ "count": 0
+ },
+ "ui": {
+ "onDumpButton": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "gateCounter-9": {
+ "description": {
+ "name": "gateCounter",
+ "alt": "in ... out",
+ "id": "gateCounter-9",
+ "path": "./modules/util/gateCounter.js",
+ "position": {
+ "left": 732,
+ "top": 976
+ }
+ },
+ "inputs": {
+ "thru": {
+ "accepts": "any"
+ },
+ "setCount": {
+ "accepts": "number"
+ },
+ "addEvent": {
+ "accepts": "any"
+ }
+ },
+ "outputs": {
+ "out": {
+ "emits": "any",
+ "calls": [
+ {
+ "parentId": "parallelContencator-11",
+ "key": "in0"
+ }
+ ]
+ }
+ },
+ "state": {
+ "addThis": 10,
+ "count": 0
+ },
+ "ui": {
+ "openButton": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "parallelContencator-11": {
+ "description": {
+ "name": "parallelContencator",
+ "alt": "inputs -> arrays",
+ "id": "parallelContencator-11",
+ "path": "./modules/util/parallelContencator.js",
+ "position": {
+ "left": 1232,
+ "top": 1053
+ }
+ },
+ "inputs": {
+ "in0": {
+ "accepts": "any"
+ },
+ "in1": {
+ "accepts": "any"
+ },
+ "push": {
+ "accepts": "evt"
+ }
+ },
+ "outputs": {
+ "out": {
+ "emits": "array",
+ "calls": [
+ {
+ "parentId": "collector-8",
+ "key": "collect"
+ }
+ ]
+ }
+ },
+ "state": {
+ "gateKeep": true
+ },
+ "ui": {
+ "onOutputButton": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "gateCounter-12": {
+ "description": {
+ "name": "gateCounter",
+ "alt": "in ... out",
+ "id": "gateCounter-12",
+ "path": "./modules/util/gateCounter.js",
+ "position": {
+ "left": 726,
+ "top": 1174
+ }
+ },
+ "inputs": {
+ "thru": {
+ "accepts": "any"
+ },
+ "setCount": {
+ "accepts": "number"
+ },
+ "addEvent": {
+ "accepts": "any"
+ }
+ },
+ "outputs": {
+ "out": {
+ "emits": "any",
+ "calls": [
+ {
+ "parentId": "parallelContencator-11",
+ "key": "in1"
+ }
+ ]
+ }
+ },
+ "state": {
+ "addThis": 10,
+ "count": 0
+ },
+ "ui": {
+ "openButton": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "number-output-13": {
+ "description": {
+ "name": "number-output",
+ "alt": "for clicking",
+ "id": "number-output-13",
+ "path": "./modules/util/number.js",
+ "position": {
+ "left": 168,
+ "top": 1045
+ }
+ },
+ "inputs": {
+ "thru": {
+ "accepts": "any"
+ },
+ "evt": {
+ "accepts": "any"
+ }
+ },
+ "outputs": {
+ "out": {
+ "emits": "number",
+ "calls": [
+ {
+ "parentId": "gateCounter-9",
+ "key": "setCount"
+ },
+ {
+ "parentId": "gateCounter-12",
+ "key": "setCount"
+ }
+ ]
+ }
+ },
+ "state": {
+ "number": 1
+ },
+ "ui": {
+ "onNumberButton": {
+ "type": "button",
+ "clientPath": "ui/uiButton.js"
+ }
+ }
+ },
+ "logger-14": {
+ "description": {
+ "name": "logger",
+ "alt": "in ... out to console",
+ "id": "logger-14",
+ "path": "./modules/util/log.js",
+ "position": {
+ "left": 1319,
+ "top": -44
+ }
+ },
+ "inputs": {
+ "thru": {
+ "accepts": "any"
+ }
+ },
+ "outputs": {
+ "throughput": {
+ "emits": "any",
+ "calls": []
+ }
+ },
+ "state": {
+ "prefix": "JTN2:",
+ "message": "---"
+ },
+ "ui": {}
+ }
+ }
+}
\ No newline at end of file
diff --git a/robot.js b/robot.js
index ae66d56..6ec40ee 100644
--- a/robot.js
+++ b/robot.js
@@ -16,11 +16,6 @@ var program = Programs.new('new program')
- robot does forward transform with live [t1, t2]
- robot displays forward transform with [t1, t2]
-- modules needed
- - object collector (i.e. collects inputs into a list, has 'output' and 'reset' input triggers / buttons as well)
- - two-up contencator (i.e. takes two inputs, puts them into arrays)
- - gate opens, lets a count thru, shuts
-
*/
var link = Programs.loadModuleFromSource(program, './modules/hardware/atkseriallink.js')
@@ -55,6 +50,12 @@ mrbotone.outputs.pos.attach(log.inputs.thru)
var canvas = Programs.loadModuleFromSource(program, './modules/ui/threeCanvas.js')
Programs.setUI(canvas, 1500, 650)
+var collector = Programs.loadModuleFromSource(program, './modules/util/collector.js')
+Programs.setUI(collector, 1050, 800)
+
+var gateCounter = Programs.loadModuleFromSource(program, './modules/util/gateCounter.js')
+Programs.setUI(gateCounter, 600, 850)
+
/*
var stest = Programs.loadModuleFromSource(program, './modules/ui/stest.js')
diff --git a/rundmc.js b/rundmc.js
index 0e9922f..189ac68 100644
--- a/rundmc.js
+++ b/rundmc.js
@@ -29,7 +29,9 @@ const Reps = require('./reps.js')
const Programs = require('./programs.js')
// the program object: real simple, just has a description, and a 'modules'
-var program = Programs.new('new program')
+// var program = Programs.new('new program')
+
+var program = Programs.open('./programs/temp.json')
/*
var stest = Programs.loadModuleFromSource(program, './modules/ui/stest.js')
--
GitLab