diff --git a/README.md b/README.md index 3bac1b2b363acac2be83bfd05152ccee59d557e9..a1a33084e46bc50df474c20d76902bd9979c371d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ ## oy +- planner reporting lengths that are 100 total when should be 10 +- stepper not having individual instances of state ? + - callback-via-hookup ... steppers -> network, planner -> steppers both want this - understand how callbacks work, how often used, etc, cc @ sean - button / multiline / 3js UI elements / ui handling throughout ? diff --git a/server.js b/server.js index db68de2e7427440047d7dfe80ab6ae7f79ecbc4f..795b9d514f5605c83f96c234e0e8c9b232832884 100644 --- a/server.js +++ b/server.js @@ -137,16 +137,20 @@ zm.outputs.ack.attach(planner.inputs.acks) // same motors / bridge xm.state.axis = 'X' +xm.axis = 'X' xm.outputs.packet.attach(bridge.inputs.A) bridge.outputs.A.attach(xm.inputs.packet) yma.state.axis = 'Y' +yma.axis = 'Y' yma.outputs.packet.attach(bridge.inputs.B) bridge.outputs.B.attach(yma.inputs.packet) ymb.state.axis = 'Y' +ymb.axis = 'Y' ymb.state.spu = -200 ymb.outputs.packet.attach(bridge.inputs.C) bridge.outputs.C.attach(ymb.inputs.packet) -zm.state.axis = 'Z' +zm.state.axis = 'ZA' +zm.axis = 'Z' zm.outputs.packet.attach(bridge.inputs.D) bridge.outputs.D.attach(zm.inputs.packet) @@ -164,9 +168,13 @@ setUiPos(zm, 600, 780) setUiPos(bridge, 600, 980) // setting ui elements / state +planner.state.isRunning = 0 term.state.uiInput = "G1 F100 X10" term.state.uiInput = "G1 Y10" -term.state.uiInput = "G1 X5 Y1500" +term.state.uiInput = "G1 X0" +term.state.uiInput = "G1 Y0" +planner.state.isRunning = 1 + /* term.state.uiInput = "G1 X0 Y10" term.state.uiInput = "G1 X-1 Y0" diff --git a/src/hardware/stepper.js b/src/hardware/stepper.js index 81f53e7f5d624c47c37d928b62faabe311ea2fa2..e4ca235de0201dbb0a28fe85e48775f27642ede8 100644 --- a/src/hardware/stepper.js +++ b/src/hardware/stepper.js @@ -6,110 +6,204 @@ let Output = InOut.Output let State = InOut.State let Button = InOut.Button -const MJS = require ('mathjs') +const MJS = require('mathjs') +const DCRT = require('../../lib/cartesian.js') function Stepper() { - var stepper = { - description: { - name: 'ATK Network Stepper Driver', - alt: 'software representation of stepper', - isHardware: true - } - } - - stepper.state = State() - state = stepper.state - - state.axis = 'X' - state.spu = 200 // steps per unit - state.rawMove = -10 - - state.makeMove = Button('test move') - - state.position = 0 // in steps - - state.onChange('makeMove', function(){ - onRawMove() - state.makeMove.isPressed = false - }) - - stepper.inputs = { - move: Input('move instruction', onNewInstruction), - packet: Input('headless packet', onHardwareIn) - } - - stepper.outputs = { - ack: Output('move acknowledgement'), - q: Output('number'), // how much juice used for last move - packet: Output('headless packet') - } - - function onHardwareIn(pckt){ - console.log('packet from stepper', pckt) - } - - function onRawMove(){ - console.log('raw move for', state.rawMove) - // finds type of ramp, calculates entry and exit ramp lengths - var length = Math.abs(state.rawMove) - var testTrapezoid = calcDiscreteMoves(state.rawMove, 10, 100, length / 2 - length/4, length / 2 + length / 4) - console.log(testTrapezoid) - /* - var machineTrap = calcDiscreteMoves(rawTrap) - var packet = makeTrapezoidPacket(machineTrap) - // send it - stepper.outputs.packet.emit(machineTrap) - */ - } - - function onNewInstruction(move){ - console.log('move to stepper', move) - // pick out axis (check if it's a wait move) - - // write trapezoid - - // machine trapezoid - - // send and setup for ack ? - } - - - function calcDiscreteMoves(delta, entry, accel, aLength, dLength){ - // steps, entryspeed, accel, accellength, deccellength - var dLength = watchRounding(Math.abs(delta * state.spu)) - var dDelta = 0 - if(delta < 0){ - dDelta = - dLength - } else { - dDelta = dLength - } - var dEntry = watchRounding(entry * state.spu) - var dAccel = watchRounding(accel * state.spu) - var dALength = watchRounding(aLength * state.spu) - var dDLength = watchRounding(dLength * state.spu) - - var discreteTrap = { - // HERE ! - } - // from float to step conversions, watching for corner (haha) cases - } - - function watchRounding(val){ - var rounded = Math.round(val) - if(rounded < 0){ - console.log('WATCH ZERO', val, rounded) - } - var error = Math.abs(val/rounded - 1) - if(error > 0.05){ - console.log('WATCH ROUNDING', val, rounded, error) - } - } - - function makeTrapezoidPacket(machineTrapezoid){ - // make a packit - } - - return stepper + var stepper = { + description: { + name: 'ATK Network Stepper Driver', + alt: 'software representation of stepper', + isHardware: true + } + } + + stepper.state = State() + state = stepper.state + + state.axis = 'X' + state.spu = 200 // steps per unit + state.rawMove = -10 + + state.makeMove = Button('test move') + + state.lead = 0 + state.position = 0 // in steps + + state.onChange('makeMove', function() { + onRawMove() + state.makeMove.isPressed = false + }) + + stepper.inputs = { + move: Input('move instruction', onNewInstruction), + packet: Input('headless packet', onHardwareIn) + } + + stepper.outputs = { + ack: Output('move acknowledgement'), + q: Output('number'), // how much juice used for last move + packet: Output('headless packet') + } + + function onHardwareIn(pckt) { + console.log('packet from stepper', pckt) + } + + function onRawMove() { + console.log('raw move for', state.rawMove) + // finds type of ramp, calculates entry and exit ramp lengths + var length = Math.abs(state.rawMove) + var testTrapezoid = calcDiscreteMoves(state.rawMove, 10, 100, length / 2 - length / 4, length / 2 + length / 4) + console.log(testTrapezoid) + /* + var machineTrap = calcDiscreteMoves(rawTrap) + var packet = makeTrapezoidPacket(machineTrap) + // send it + stepper.outputs.packet.emit(machineTrap) + */ + } + + function onNewInstruction(move) { + console.log('move to stepper', stepper.id, state.axis, stepper.axis, stepper.state.axis) + // pick out axis (check if it's a wait move) + // like + /* + var move = { + p1, p2, + cruise, entry, exit, + vector, + type, + t1, d1, t2, d2, t3, d3 + } + */ + + // axis values + var axisIndex = move.axes.indexOf(state.axis) + console.log('axisIndex', axisIndex, state.axis) + if (axisIndex == -1) { + console.log('STEPPER AXIS NOT FOUND IN MOVE') + } else { + // have to watch out for zero-lengths on this axis, also + var delta = move.p2[axisIndex] - move.p1[axisIndex] + console.log('delta', delta) + if (delta <= 0) { + // find a DOF w/o zlv + var fnd = false + var altAxis = null + for (i in move.p1) { + if (Math.abs(move.p2[i] - move.p1[i]) > 0) { + altAxis = i + } + } + if (altAxis != null) { + var axisMove = pullAxis(move, i) + axisMove.isWait = true + sendToHardware(axisMove) + } else { + console.log("ZERO LENGTH INTO STEPPER") + } + } else { + var axisMove = pullAxis(move, axisIndex) + axisMove.isWait = false + sendToHardware(axisMove) + } + } + } + + function pullAxis(move, i) { + // like + /* + var move = { + p1, p2, + cruise, entry, exit, + vector, + type, + t1, d1, t2, d2, t3, d3 + } + */ + /* + var pckt = { + steps, + entry, + accel, + accelLen, + deccelLen + } + */ + var delta = move.p2[i] - move.p1[i] + var frLen = DCRT.length(move.vector) + var rel = Math.abs(delta) / frLen + + console.log(delta, frLen, rel) + + var entry = move.entry * rel + var accel = move.accel * rel + var accelLen = move.accelLen * rel + var deccelLen = move.deccelLen * rel + + var aMove = { + delta: delta, + entry: entry, + accel: accel, + accelLen: accelLen, + deccelLen: deccelLen + } + + console.log('return pull', aMove) + + return aMove + } + + function sendToHardware(aMove) { + // 'axis' move and discreet move + var dMove = {} + dMove.steps = watchRounding(aMove.delta) + dMove.entry = watchRounding(aMove.entry) + dMove.accel = watchRounding(aMove.accel) + dMove.accelLen = Math.round(aMove.accelLen) + dMove.deccelLen = Math.round(aMove.deccelLen) + + var packet = new Array() + // step blocks are #131 + // wait blocks are #132 + if(aMove.isWait){ + packet.push(132) + } else { + packet.push(131) + } + packet = packet.concat(pack32(dMove.steps)) + packet = packet.concat(pack32(dMove.entry)) + packet = packet.concat(pack32(dMove.accel)) + packet = packet.concat(pack32(dMove.accelLen)) + packet = packet.concat(pack32(dMove.deccelLen)) + + state.lead = state.lead + dMove.steps + stepper.outputs.packet.emit(packet) + + console.log('stepper packet out', packet) + } + + function sendToHardware(dMove){ + + } + + function watchRounding(val) { + var rounded = Math.round(val) + if (rounded == 0 ) { + console.log('WATCH ZERO', val, rounded) + } + var error = Math.abs(val / rounded - 1) + if (error > 0.05) { + console.log('WATCH ROUNDING', val, rounded, error) + } + } + + function makeTrapezoidPacket(machineTrapezoid) { + // make a packit + } + + return stepper } -module.exports = Stepper \ No newline at end of file +module.exports = Stepper \ No newline at end of file diff --git a/src/motion/planner.js b/src/motion/planner.js index 64540b9ea0f9a0e0fc82204fb1190e945b807ce6..cd4d5bf7726ec2901113aa26d51bb457cc472574 100644 --- a/src/motion/planner.js +++ b/src/motion/planner.js @@ -54,17 +54,17 @@ function Planner() { ------------------------------------------------------ */ - function onAck(msg){ + function onAck(msg) { console.log("Planner onAck:", msg) // stepper has moved, ID to position & speed state, count for time to send new move } - function axisIDUpdate(){ + function axisIDUpdate() { var axes = state.axisIDs.split(',') var position = new Array(axes.length) position.fill(0) var packetState = new Array(axes.length) - for(i in axes){ + for (i in axes) { position.push(0) packetState.push(0) // could do @@ -75,14 +75,44 @@ function Planner() { console.log(planner) } - function onPlannerReset(){ + function onPlannerReset() { console.log("RESET PLANNER") } - function netStateRefresh(){ - + function netStateRefresh() { + // if there are less packets on the network than our window + // and the planner is running + // send a packet + if(state.isRunning){ + var ns = state.netState + var i = 0 + while(ns[i] == ns[i+1]){ + i ++ + if(i > ns.length - 1){ + break + } + } + if(i == ns.length - 1){ + if(ns[i] < state.netWindow){ + sendMoveToNetwork() + } + } + } + } + + function sendMoveToNetwork(){ + if(mq.length > 0){ + for(i in state.netState){ + state.netState[i] ++ + } + // dereference + var move = JSON.parse(JSON.stringify(mq.shift())) + console.log("MOVE FROM PLANNER", move) + planner.outputs.moves.emit(move) + } else { + planner.isRunning = 0 + } } -} /* ------------------------------------------------------ @@ -98,7 +128,7 @@ function Planner() { var axes = state.axisIDs.split(',') // we'll make a new move object - // start and end points + // start and end points, and axes to track var p1 = [] var p2 = new Array(axes.length) p2.fill(0) @@ -125,6 +155,7 @@ function Planner() { console.log('planner throwing zero length vector') } else { var newMove = { + axes: axes, p1: p1, p2: p2, cruise: move.speed, @@ -220,7 +251,7 @@ function Planner() { console.log('TRAPEZOIDS') for (var i = 0; i < mq.length; i++) { calcTrap(mq[i], accel, false) - if(moveTime(mq[i]) < 0.1){ + if (moveTime(mq[i]) < 0.1) { console.log("WARN! move time here", moveTime(mq[i])) } console.log(moveTime(mq[i]))