Skip to content
Snippets Groups Projects
README.md 15.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jake Read's avatar
    Jake Read committed
    # RNDMC
    
    Jake Read's avatar
    Jake Read committed
    
    
    Jake Read's avatar
    Jake Read committed
    **Reconfigurable Numeric Dataflow Machine Controller**
    
    *aka project 'consistent-sandbox'*
    
    Jake Read's avatar
    Jake Read committed
    ![img software](doc/images/atkapi.png)
    ![img hardware](doc/images/machine-with-atkapi.jpg)
    
    Jake Read's avatar
    Jake Read committed
    This is a piece of software that is designed to help you assemble high level controllers from dataflow software elements. It serves a graphical programming interface, and is meant to live with dataflow hardware elements from [this project 'automatakit'](https://gitlab.cba.mit.edu/jakeread/automatakit).
    
    It's in the early stages, so bear with us. Everything is going to be great. 
    
    # Usage 
    
    
    ## Installing Node.js, WebSocket and SerialPort, and MathJS
    
    Jake Read's avatar
    Jake Read committed
    
    To Run DMC, you'll need to install node.js, and then the packages serialport and ws (websocket).
    
    
    Jake Read's avatar
    Jake Read committed
    ### Install Node.js
    
    Jake Read's avatar
    Jake Read committed
    
    Node.js is a runtime environment for javascript, so you can write and run js locally. [Download and install it here](https://nodejs.org/en/download/). 
    
    To check that node is installed, you can use
    
    ``node -v``
    
    In Windows check that in *Environment Variables, System Variables, Path* there is a path for C:\Users\yourusername\npm folder. If the folder does not exist, create it and set the path.  
    
    
    Jake Read's avatar
    Jake Read committed
    ### Packages
    
    I've added a package.json file to the repo, which is [another cool node.js trick](https://docs.npmjs.com/files/package.json) - this means that to install everything, you should be able to (after downloading the repo and cd-ing into it) run:
    
    ```npm install```
    
    This should install everything else. If this fails, you can install things one-by-one as listed below.
    
    
    Jake Read's avatar
    Jake Read committed
    ### Install Serialport
    
    Jake Read's avatar
    Jake Read committed
    
    Node comes with a package controller called 'npm' - node package manager. You can use this to install dependencies for node programs. 
    
    Serialport is a package for node that allows it to interact with a hardware serial port.
    
    Navigate to the directory where you'll be running from (atkapi). Do
    
    ``npm install serialport``
    
    
    Jake Read's avatar
    Jake Read committed
    ### Install WS (WebSocket)
    
    Jake Read's avatar
    Jake Read committed
    
    WebSockets are very simple web connections. We use them to chat between the 'server' / heap (node) and the 'view' (your browser).
    
    To install ws, do
    
    ``npm install ws``
    
    Jake Read's avatar
    Jake Read committed
    ### Install MathJS 
    
    
    MathJS is just a node package that does maths. To install, you guessed it, do
    
    ```npm install mathjs``` 
    
    
    Jake Read's avatar
    Jake Read committed
    ## Installing Serial Port Drivers
    
    The ATKRouter uses a ```CP2102N``` USB-to-UART bridge to transmit and receive serial characters. 
    
    [**Drivers are available for all platforms at SiLabs' Website**](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)
    
    Download and install drivers, and check in your system's device manager that a 'CP210x USB to UART Bridge' appears.
    
    
    Jake Read's avatar
    Jake Read committed
    # Running DMC
    
    To run the program, we launch the main.js file with node, from the command line. One of the things this does is run a tiny HTTP server that we can use to access the UI.
    
    Jake Read's avatar
    Jake Read committed
    
    
    Jake Read's avatar
    Jake Read committed
    cd to the rndmc folder and run: 
    
    
    Jake Read's avatar
    Jake Read committed
    ``node rundmc``
    
    Jake Read's avatar
    Jake Read committed
    
    It's handy to keep a terminal window open beside a browser when running the software - it's not perfect yet - I do this:
    
    
    Jake Read's avatar
    Jake Read committed
    ![term](doc/images/termopen.png)
    
    Jake Read's avatar
    Jake Read committed
    
    This way I can watch for errors, and restart it when it crashes. Hopefully not a lot of this will happen.
    
    ## Open a Browser
    
    The program is now running a tiny HTTP server, where it will deliver an interface. It's set to show up at your local address on port 8080.
    
    In a browser open *localhost:8080* you will see the mods and this msg in the terminal *SEND PROGRAMS TO UI* 
    
    ## Using the Browser Interface 
    
    Jake Read's avatar
    Jake Read committed
    
    
    Jake Read's avatar
    Jake Read committed
    ![img moving](doc/images/mothermother.gif)
    
    Jake Read's avatar
    Jake Read committed
    **Words of Warning** 
    
    This is very new software, so bear with me. It's worth having whomever on the team is in charge of controls read the section (below) on what-all is going on with the software, and understanding how to write new modules, and assemble programs. 
    
    #### Getting Around
    
    To navigate, you can scroll in-and-out (try this once there is actually a program loaded) and drag to pan around.
    
    #### Loading a Program
    
    To load a program, hit 'l' on your keyboard. This will open a menu of all of the .json program representations in the /programs directory.
    
    There is an example program there, that will do acceleration-controlled motion with gcode as input. 
    
    #### Loading a Module
    
    To load a module, right-click anywhere on the screen. 
    
    #### Deleting a Module
    
    To delete or copy a module, right-click on its title. 
    
    #### Connecting Outputs to Inputs
    
    Once loaded, modules can be connected by first clicking on the *output* of one and the *input* of another. This will cause events on that output to call events associated with the input.
    
    #### Disconnecting Outputs from Inputs
    
    To disconnect, click the output to disconnect, and then the input to disconnect it from. 
    
    # Troubleshooting
    
    
    Jake Read's avatar
    Jake Read committed
    - ?
    
    # RuNDMC Architecture 
    
    
    ![arch](doc/images/rndmc-architecture.png)
    
    Jake Read's avatar
    Jake Read committed
    
    
    Above is a somewhat-complete representation of what-all is going on in software.
    
    Essentially, we load tiny programs (```modules/sub/modulename.js```) using node.js's *require* function. These programs each have inputs and outputs, and some state. Each also has a description (an example of a complete module is below).
    
    The UI serves a representation of this through a websocket.
    
    Pardon my at-the-moment brief explanation. 
    
    Jake Read's avatar
    Jake Read committed
    # Writing New Modules 
    
    
    Whenever a menu is requested, the system searches ```modules/ * ``` for *anything*. When you write a new module, just include your newmodule.js there, and the program should find it.
    
    
    These modules are written with objects inherited from ```lib/jsunit.js``` 
    
    Here's an example. This is modules/ui/number.js. 
    
    Besides Inputs, Outputs, a Description and State object, anything else goes. I.E. local functions, other Node.JS packages, etc.
    
    
    Jake Read's avatar
    Jake Read committed
    ```javascript
    
    // boilerplate rndmc header
    
    Jake Read's avatar
    Jake Read committed
    const JSUnit = require('../../src/jsunit.js')
    let Input = JSUnit.Input
    let Output = JSUnit.Output
    let State = JSUnit.State
    let Button = JSUnit.Button
    
    
    // a constructor, a fn, a javascript mess
    function uiNum() {
    
        // this is the tiny program-as-and-object that we'll load into rundmc 
        // description / name is required to load successfully 
        var uinum = {
            description: {
                name: 'number-output',
                alt: 'for clicking'
            }
        }
    
        // 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 
        uinum.state = State()
        // alias !
        var state = uinum.state 
    
        state.number = 10
    
    Jake Read's avatar
    Jake Read committed
        state.onUiChange('number', onNumberDesire)
    
    
        state.button = Button('WHAM', onNumberDesire)
    
        // inputs are required, and must be Input('type', callback) 
        uinum.inputs = {
            thru: Input('any', onThruInput), // makes anything into num event 
            evt: Input('any', onNumberDesire)
        }
    
        // outputs: Output('type')
        uinum.outputs = {
            out: Output('number')
        }
    
        // here's our input callback, specified in the input constructor 
        function onThruInput(input){
            if(typeof input == 'number'){
                state.number = input
            } else {
                state.number = parseFloat(input)
            }
            onNumberDesire()
        }
    
        function onNumberDesire(){
            // here's how we fire an output. 
            uinum.outputs.out.emit(state.number)
        }
    
        // gotta give the program this thing we made 
        return uinum
    }
    
    // this for node.js's require() function 
    module.exports = uiNum
    ``` 
    
    Jake Read's avatar
    Jake Read committed
    
    # Writing Hardware Modules 
    
    
    Hardware Modules are identical to other modules, but they inherit a class that can be found and examined at ```lib/atkunit.js``` which subsequently calls hardware-interfacing classes from ```lib/atkroute.js``` and often use tools from ```lib/packets.js``` (packets.js is mostly about packing 64-bit information into byte-size units).
    
    # Programatically Connecting and Loading Modules
    
    We can also write and manipulate modules as software objects. This is sometimes very nice.
    
    I.E. here is 'main.js' as configured to run the small program described.
    
    ```javascript
    
    // business 
    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')
    
    /* example program-like-an-api */
    // load some modules
    var multiline = Programs.loadModuleFromSource(program, './modules/ui/multiline.js')
    var gcode = Programs.loadModuleFromSource(program, './modules/parsing/gcode.js')
    
    // attaching: always like outputs to inputs
    multiline.outputs.lineOut.attach(gcode.inputs.lineIn)
    
    // we can move things around here as well
    multiline.description.position = {
        left: 50,
        top: 50
    }
    
    gcode.description.position = {
        left: 500,
        top: 100
    }
    
    // if I have a public function in a module, I can also use that
    multiline.load('./files/dogbone.gcode')
    
    // UI 
    const View = require('./views.js')
    View.startHttp() 
    View.startWs() 
    
    Programs.assignSocket(View.uiSocket)
    View.assignProgram(program)
    ```
    
    
    Jake Read's avatar
    Jake Read committed
    # Development Notes 
    
    
    Jake Read's avatar
    Jake Read committed
    ## Immediately
    
    Jake Read's avatar
    Jake Read committed
    - nice work on generic ui classes / ui.thing.call('function', arg)
    - finish robot flow: offsets, ok, 100ms updates, ok
     - forward transform object -> three.js canvas
     - do key-binding ui for robot jogging, write video 
    
    Jake Read's avatar
    Jake Read committed
    - three robot canvas 
    - set module display width 
    
    
    Jake Read's avatar
    Jake Read committed
    - saved program doesn't save state booleans 
    
    
    Jake Read's avatar
    Jake Read committed
    - ui objects ... refresh ... use state model ? 
    - ui objects client drop below inputs / outputs 
    
    
    Jake Read's avatar
    Jake Read committed
    - ui / button 
    
    Jake Read's avatar
    Jake Read committed
    
    
    Jake Read's avatar
    Jake Read committed
    - svg doesn't display on chrome 
    
    
    Jake Read's avatar
    Jake Read committed
    - would like to send board with new buck out to fab
    - just do stepper23, bc if that's it, that's it ?
    
    Jake Read's avatar
    Jake Read committed
    - tuning:
     - mrobot having PI, PID terms
    
    Jake Read's avatar
    Jake Read committed
     - probably good to do a remote-get ... 
    
    Jake Read's avatar
    Jake Read committed
     - having position-set input (also gets output?)
     - having position-actual output
     - graphing these things
     - use UI slider (external) to set PID terms?
     - should be able to use the same slider element directly inline 
    
    Jake Read's avatar
    Jake Read committed
    - cleaning up reps 
    - looking for heirarchy demonstration 
    - imagining microcontrollers 
    - working on robot to inform desires: i.e. ui charts and graphs 
    
    ## For Madison Park
    
    - want that better-planner, better-stepper, better-inputs and graphic ui w/ 3js 
    - want network to not blow
     - tokens w/ crc bit-level ? 
     - app does keepalive / green-when-on etc ? 
     - example of setup-for-consistent-feedback of variable, on a timer? tuning loops ... search ... 
    - do axis pullout separately from stepper motor ? accel command ? deep jog desire ... architecture still messy though
    
    - bug hunting
     - multiline change input paste doesn't work ... big state problem 
     - is load / save really consistent ? what is the state answer ? 
     - expected behavior: pressing the button on the raw move module should result in a move for every button press
     - observed behavior: to send another raw move (via the button on the raw move module), we must reset the motor drivers.
    
    Jake Read's avatar
    Jake Read committed
    
    
    Jake Read's avatar
    Jake Read committed
    - add router for reset, test 
    
    Jake Read's avatar
    Jake Read committed
    ## Forever
    
    - open the door, no cuffs 
    - option for 'native' multithreading by opening workers on each event ?
    
    Jake Read's avatar
    Jake Read committed
    ## Questionable Moves
    
    Jake Read's avatar
    Jake Read committed
    - module deletion seems unclean 
    
    Jake Read's avatar
    Jake Read committed
     - input / output objects should be able to unhook themselves: 
    
    Jake Read's avatar
    Jake Read committed
     - 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 
    
    Jake Read's avatar
    Jake Read committed
    
    
    Jake Read's avatar
    Jake Read committed
    ## WRT Representations
    
    Module have 
     Inputs
     Outputs
     State (initial states are settings)
    
    
    Jake Read's avatar
    Jake Read committed
    Hardware Modules have
     routes
     connected to 
     links 
    
    
    Jake Read's avatar
    Jake Read committed
    Also
     Names, IDs
     Paths-to-source 
    
    To assemble a representation of these, we want to have a kind of 'netlist' that, for convenience, we'll treat like a JSON object. We want heirarchy, so consider the representation having 'top-level' outputs / inputs / state as well ? 
    
    
    ## Programming Notes
    
    ### 15 Minute Tasks 
     - @ views.js, uiRequestModuleMenu and uiRequestProgramMenu don't properly build trees from folder structure. similarly, reciprical fn's in client.js do the same 
     - @ these load / save functions could also reach into the modules' source to retrieve their proper names, as spec'd in description ... 
     - 's' for save program uses hack-asf DOM alert to ask for path
    
    Jake Read's avatar
    Jake Read committed
    ## Desires 
    
    Jake Read's avatar
    Jake Read committed
    - reload / edit individual modules ? 
    - modules spawn new inputs / outputs ? 
    - big UI ? 
     - arrows catch for jogging 
    - editing ? 
    
    Jake Read's avatar
    Jake Read committed
    - heirarchy zoom 
    
    Jake Read's avatar
    Jake Read committed
     - architectural clarity betwixt UI and Heap 
    
    - some auto load / save currently.json file so that we can restart program w/o pain ... maybe just save on new user inputs ? 
    
    Jake Read's avatar
    Jake Read committed
    - state.setDefault('var', num) or etc / types
    - perhaps all state objects like this ... still somehow state.var = // is a good operator ? don't really want state.var.set(num) and state.var.get() 
    
    Jake Read's avatar
    Jake Read committed
    - states / uis / etc - one off / one-at-a-time for updates 
     - i.e. all f'n update calls are to single module-global state update
     - ! 
    - states / getters / setters not applicable to sub-elements in an object within state
     - i.e. array access 
    - consistent dereferencing, type checking implementation?
    
    
    Jake Read's avatar
    Jake Read committed
    ## UI Desires
    
    Jake Read's avatar
    Jake Read committed
    - scroll / grab events for touchpads etc ... find a mac user and workshop this for one afternoon ? 
    
    Jake Read's avatar
    Jake Read committed
    - modules have visual ways to throw errors - i.e. flashing red, popping up... 
    - off-screen divs get pointers-to so that we don't get lost
      - 'h' or something to zoom-to-extents
    - better module menu
    - hover for alt descriptions 
    
    
    Jake Read's avatar
    Jake Read committed
    ## Planner Bugs
     - trapezoid linking doesn't account for speed changes properly, i.e. doesn't ramp down into next move if next move's cruise speed is less than our exit speed 
    
    Jake Read's avatar
    Jake Read committed
     - should have some stronger ideas about flow control, allowable segment size (based on time) 
    
    Jake Read's avatar
    Jake Read committed
    
    
    Jake Read's avatar
    Jake Read committed
    ## Want 
    
    Jake Read's avatar
    Jake Read committed
    - log() for logs-from-module tagged 
    
    ## Demo Desires 
    - want to show immediacy of hardware: software representation
    - want to show physical reconfigurability and software reconfigurability
     - i.e. mill, add rotary tool, pull normal vector from planner moves and route to r motor 
    - want to have UI elements
     - button, terminal, 
    - live motor torque display, vector from accelerometer 
    
    ## Network Desires
    - c improvements / dma etc, would be very cool
    - flow control probably desired ... what can we model with uart and implement with fpga?
    - proper speed tests
    - DMA not possible / not enough channels for router implementation / not portable enough ... 
    - lights displaying activity
    
    ## Bugs
    - cannot connect input to output w/o backwards bezier 
    
    Jake Read's avatar
    Jake Read committed
    - when source has changed, opening programs that have references to that source should be carefully done ... 
    
    Jake Read's avatar
    Jake Read committed
    # The RPI
    
    
    Jake Read's avatar
    Jake Read committed
    One of the desires here is to run programs headlessly on small embedded computers like the Raspberry Pi. The router has pogo-pins for this, so that when it's mounted beneath a Raspberry Pi the USB and Power lines are automatically hooked up - the 2A Buck Converter on the Router can also be used to power the RPI, so it can all run on one DC power bus. Nice! 
    
    ![ATKRouter](https://gitlab.cba.mit.edu/jakeread/atkrouter/raw/master/images/atkrouter.jpg)
    
    
    Jake Read's avatar
    Jake Read committed
    ### Setup the Raspberry Pi
    
     - [download raspbian](https://www.raspberrypi.org/documentation/installation/installing-images/README.md)
     - [flash and boot, setup etc](https://www.raspberrypi.org/documentation/setup/)
    
    ### Install Node on the Raspberry Pi
    
     - to install node, download the distro you want from nodejs.org 
     - extract the files, and hit these commands
    
    navigate to the distribution
    `` cd <distro> `` 
    copy that to local space on the pi
    `` sudo cp -R * /usr/local/ ``
    
    to check that node is installed, check the version using
    `` node -v ``
    which should return the version number of the distro you installed.
    
    
    Jake Read's avatar
    Jake Read committed
    However:
    
    
    Jake Read's avatar
    Jake Read committed
    ``` need to figure out how to get the RPI serialport to talk ``` 
    
    Jake Read's avatar
    Jake Read committed
    
    - https://cnc.js.org/ 
    
    Jake Read's avatar
    Jake Read committed
    - https://github.com/cncjs/cncjs/wiki/Setup-Guide:-Raspberry-Pi-%7C-Install-Node.js-via-Node-Version-Manager-(NVM)