Skip to content
Snippets Groups Projects
Select Git revision
  • ec27cc7de53120cfff33db5634ae6c9ec6b8cc3d
  • main default protected
2 results

clankClient.js

Blame
  • clankClient.js 9.06 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/osapRoot.js'
    import { PK, TS, VT, EP, TIMES } from '../osapjs/core/ts.js'
    
    // the clank 'virtual machine'
    import ClankVM from './vms/clankVirtualMachine.js'
    
    import Grid from '../osapjs/client/interface/grid.js' // main drawing API 
    import { Button, EZButton, TextBlock, TextInput } from '../osapjs/client/interface/basics.js'
    import { GCodePanel } from '../osapjs/client/components/gCodePanel.js'
    
    import { JogBox } from '../osapjs/client/components/jogBox.js'
    
    console.log("hello clank controller")
    
    // the osap root node:
    let osap = new OSAP()
    
    let grid = new Grid()
    
    // -------------------------------------------------------- SETUP NETWORK / PORT 
    
    let wscVPort = osap.vPort()
    
    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/osapSerialBridge.js', (res) => {
      if (res.includes('OSAP-wss-addr:')) {
        let addr = res.substring(res.indexOf(':') + 2)
        if (addr.includes('ws://')) {
          let status = "opening"
          wscVPort.cts = () => {
            if (status == "open") {
              return true
            } else {
              return false
            }
          }
          // start up, 
          console.log('starting socket to remote at', addr)
          let ws = new WebSocket(addr)
          ws.binaryType = "arraybuffer"
          // opens, 
          ws.onopen = (evt) => {
            status = "open"
            // implement rx
            ws.onmessage = (msg) => {
              let uint = new Uint8Array(msg.data)
              wscVPort.receive(uint)
            }
            // implement tx 
            wscVPort.send = (buffer) => {
              if (LOGPHY) console.log('PHY WSC Send', buffer)
              ws.send(buffer)
            }
          }
          ws.onerror = (err) => {
            status = "closed"
            console.log('sckt err', err)
          }
          ws.onclose = (evt) => {
            status = "closed"
            console.log('sckt closed', evt)
          }
        }
      } else {
        console.error('remote OSAP not established', res)
      }
    })
    
    // -------------------------------------------------------- THE VM
    
    // vm, 
    let vm = new ClankVM(osap)
    
    // ---------------------------------------------- setup routine
    
    // init... should setup basic motion settings and motors 
    // when green: machine is setup 
    let initBtn = new Button(10, 10, 84, 104, 'setup')
    initBtn.red()
    initBtn.onClick(async () => {
      // setup motion basics: accel, max rates (defined in virtual machine)
      initBtn.yellow('awaiting motion end to setup motion settings...')
      try {
        await vm.motion.setup()
      } catch (err) {
        console.error(err)
        initBtn.red('motion setup err, see console')
        return
      }
      // setup motor settings (axis pick, inversion, steps per unit)
      for (let mot in vm.motors) {
        initBtn.yellow(`setting up ${mot} motor...`)
        try {
          await vm.motors[mot].setup()
        } catch (err) {
          console.error(err)
          initBtn.red(`${mot} motor setup err, see console`)
          return
        }
      }
      // enable motors 
      initBtn.yellow(`enabling motors...`)
      if (!motorEnableState) {
        try {
          await toggleMotorEnable()
        } catch (err) {
          console.error(err)
          initBtn.red(`failed to enable motors, see console`)
          return
        }
      }
      // home the machine, 
      // initBtn.yellow(`homing machine...`)
      // try {
      //   await runHomeRoutine()
      // } catch (err) {
      //   console.error(err)
      //   initBtn.red(`failed to home machine, see console`)
      //   return
      // }
      // start position loop (?) 
      //posDisplayKick()
      initBtn.green('setup ok')
    })
    
    // ---------------------------------------------- motor power toggle 
    
    let motorEnableBtn = new Button(10, 130, 84, 24, 'motors: ?')
    motorEnableBtn.red()
    let motorEnableState = false
    let toggleMotorEnable = async () => {
      if (motorEnableState) {
        try {
          await vm.disableMotors()
          motorEnableState = false
          motorEnableBtn.yellow('motors: disabled')
        } catch (err) {
          motorEnableBtn.red('motor err, see console')
          throw err
        }
      } else {
        try {
          await vm.enableMotors()
          motorEnableState = true
          motorEnableBtn.green('motors: enabled')
        } catch (err) {
          motorEnableBtn.red('motor err, see console')
          throw err
        }
      }
    }
    motorEnableBtn.onClick(toggleMotorEnable)
    
    // ---------------------------------------------- home routine setup 
    
    let homeBtn = new Button(10, 170, 84, 34, 'home: ?')
    homeBtn.red()
    let runHomeRoutine = async () => {
      homeBtn.yellow('homing...')
      vm.home()
      homeBtn.green('home: ok')
    }
    homeBtn.onClick(runHomeRoutine)
    
    // 214, 162, 111
    
    // ---------------------------------------------- position loop toggle 
    
    let posDisplay = new Button(10, 220, 84, 44, `pos: ?`, true)
    //posDisplay.red()
    posDisplay.setHTML(`X: ?<br>Y: ?<br>Z: ?`)
    let posDisplayRunning = false
    let runPosUpdate = async () => {
      if (posDisplayRunning) {
        try {
          let pos = await vm.motion.getPos()
          posDisplay.green()
          posDisplay.setHTML(`
            X: ${pos.X.toFixed(2)}<br>
            Y: ${pos.Y.toFixed(2)}<br>
            Z: ${pos.Z.toFixed(2)}
            `)
          setTimeout(runPosUpdate, 10)
        } catch (err) {
          console.error(err)
          posDisplay.red('position update err, see console')
        }
      } else {
        posDisplay.grey()
      }
    }
    let posDisplayKick = () => {
      if (posDisplayRunning) {
        posDisplayRunning = false
      } else {
        posDisplayRunning = true
        runPosUpdate()
      }
    }
    posDisplay.onClick(posDisplayKick)
    
    // -------------------------------------------------------- JOGGING 
    
    let jogBox = new JogBox(10, 300, vm, 1000)
    
    // -------------------------------------------------------- All Zero
    
    let zeroSetBtn = new EZButton(10, 550, 84, 14, 'set XYZ zero')
    zeroSetBtn.onClick(() => {
      vm.motion.setPos({ X: 0, Y: 0, Z: 0 }).then(() => {
        zeroSetBtn.good("all set 0", 750)
      }).catch((err) => {
        console.error(err)
        zeroSetBtn.bad("err, see console")
      })
    })
    
    // -------------------------------------------------------- XY Zero
    
    let centerSetBtn = new EZButton(10, 580, 84, 14, 'set XY zero')
    centerSetBtn.onClick(() => {
      vm.motion.getPos().then((pos) => {
        return vm.motion.setPos({
          X: 0, Y: 0,
          Z: pos.Z
        })
      }).then(() => {
        centerSetBtn.good('xy set 0', 750)
      }).catch((err) => {
        console.error(err)
        centerSetBtn.bad("err, see console")
      })
    })
    
    // -------------------------------------------------------- Z Zero 
    
    let zZeroSetBtn = new EZButton(10, 610, 84, 14, 'set Z zero')
    zZeroSetBtn.onClick(() => {
      vm.motion.setZ(0).then(() => {
        zZeroSetBtn.good("z set 0", 750)
      }).catch((err) => {
        console.error(err)
        zZeroSetBtn.bad("err, see console")
      })
    })
    
    // -------------------------------------------------------- goto zero 
    
    let gotoZeroBtn = new EZButton(10, 640, 81, 14, 'goto zero')
    gotoZeroBtn.onClick(async () => {
      try {
        await vm.motion.awaitMotionEnd()
        await vm.motion.setWaitTime(10)
        await vm.motion.addMoveToQueue({
          position: {
            X: 0, Y: 0, Z: 0
          },
          rate: 50
        })
        await vm.motion.awaitMotionEnd()
        await vm.motion.setWaitTime(1000)
        gotoZeroBtn.good("ok")
      } catch (err) {
        gotoZeroBtn.bad("err!")
        console.error(err)
      }
    })
    
    // -------------------------------------------------------- GCode Consumer 
    
    let gCodePanel = new GCodePanel(120, 10, 300, vm)
    // to load on restart...
    /*
    gCodePanel.loadServerFile('save/3p30mm_pacman.gcode').then(() => {
      console.log("gcode initial file load OK")
    }).catch((err) => {
      console.error("failed to load default gcode from server")
    })
    */
    
    /*
    // test x motor (bus debug) 
    
    let tstBtn = new EZButton(450, 650, 84, 84, 'test x bus')
    tstBtn.onClick(() => {
      vm.motors.X.setup().then(() => {
        tstBtn.good()
      }).catch((err) => {
        console.error(err)
        tstBtn.bad()
      })
      return
      vm.motors.YL.setup().then(() => {
        tstBtn.good()
      }).catch((err) => {
        console.error(err)
        tstBtn.bad()
      })
    })
    
    // test d21 stepper 
    
    let d21Demo = osap.endpoint()
    d21Demo.addRoute(PK.route().sib(0).pfwd().sib(1).pfwd().sib(1).bfwd(2).sib(2).end())
    let doDemo = () => {
      let datagram = new Uint8Array(12)
      return new Promise((resolve, reject) => {
        d21Demo.write(datagram, "acked").then(() => {
          resolve()
        }).catch((err) => { reject(err) })
      })
    }
    
    let dtst = new EZButton(450, 750, 84, 84, 'test d21')
    dtst.onClick(() => {
      doDemo().then(() => {
        dtst.good()
      }).catch((err) => {
        console.error(err)
        dtst.bad()
      })
    })
    */