100 likes | 234 Views
IoT and RESTful Hardware What We’ve Learned from Three Years Treating Motion as REST. Alden Hart - Synthetos O’Reilly Solid Conference May 21, 2014. TinyG Motion Controller. what’s TinyG ? multi-axis motion control system designed for desktop CNC, 3D printing, pick & place…
E N D
IoT and RESTful HardwareWhat We’ve Learned from Three Years Treating Motion as REST Alden Hart - Synthetos O’Reilly Solid Conference May 21, 2014
TinyG Motion Controller what’s TinyG? • multi-axis motion control system designed for desktop CNC, 3D printing, pick & place… • accepts Gcode from USB port and executes it locally on the board • behaves like a RESTful server
The Controller Problem & Design Goals the problem • the motion control functions are all good – but people got stuck at controller implementation • specialized parsers and stateful clients got in the way design goals • control interface that’s easy and intuitive • simple • compact / lightweight • human readable / typeable / hackable • relatively ubiquitous / low learning curve • easily persisted and instantiated • object oriented • don’t have to be an industrial automation engineer to use (1 : 1000) • does not require gateways or other additional hardware not design goals • highly optimized transfer / storage • support bandwidth starved and flakey communications channels • support for hard, a-priori contracts • XML-isms like Xpath/Xquery, annotation, schemas
RESTful Hardware what is RESTful? • state exists on the server and is transferred to the client • representation is flexible, independent • well-defined resource model RESTful hardware • server is an embedded chip / may not have an OS • RESTful conventions make talking to the device very easy JSON • JSON is the natural representation • meets most of our design goals • simple • compact / lightweight • human readable / typeable / hackable • relatively ubiquitous / low learning curve • easily persisted and instantiated • object oriented
Putting JSON / REST on the Hardware put it On.The.Hardware • code runs on the chip - not a gateway / translator / some-other-intermediary • “Run JSON right over the traces” • simple JSON parser, serializer, dispatcher and serial IO in < 8K C/C++ code • bind names to dispatch tables to perform actions for the verbs • marshalling in and out of floating point • strtof() < 70 uSec on a 16 MHz AVR atmega328P (Arduino Uno) • strtof() < 7uSec on a 84 MHz ARM Cortex M3 core • all memory statically allocated – no mallocs • transport doesn’t matter • USB, SPI, Serial, MQTT, CoAP, HTTP… subset of JSON spec • 7 bit ASCII only (UTF-8 sub-set) • objects on a single line (no embedded line feeds) • objects limited to 512 characters (less on smaller CPUs) • decimal only, no hexadecimal • limited support for arrays
Implementation Considerations well defined resource model • static model – e.g. X axis, motor 1, machine setup parameters… • dynamic model – e.g. position, velocity, coordinate system in use, tool in use… • favor flat namespaces – right level of object granularity keeping it compact • short, mnemonic tokens for names – e.g. xvm instead of XaxisVelocityMaximum • don’t need to be globally unique – objects define scope • many values are enumerated – e.g. 3 instead of GcodeProgramStop • simple verbs (get, post) cheats & shortcuts • no request headers. Use null to mean get • no request ID – request / response is synchronous • can consume Gcode natively without a JSON wrapper • so people don’t have to pre-process their Gcodefiles
Implementation Examples from TinyG(1 of 2) footer revision status code flow control checksum • footers • f:[1,0,6,5473] get • {“xvm”:null} • {“ct”:null} • {xvm:n} • {ct:n} post (set) • {xvm:16000} • {ct:0.01} objects • {x:{vm:16000}} • {r:{x:{am:1,vm:16000,fr:10000,tn:0,tm:100,jm:200,jh:10000,jd:0.0100,sn:0,sx:0,sv:3000,lv:100,lb:20.000,zb:3.000}},f:[1,0,6,5473]} • {r:{sys:{fb:428.01,fv:0.970,hp:1,hv:8,id:"2X2660-EVD”… • {gc:”N75 G3 X0.6785 Y2.2371 Z0.0014 I0.0003 J0.0594”}
Implementation Examples from TinyG(2 of 2) status reports • event reporting for the dynamic model • timed and filtered • timed reports during movement – e.g. every 250 milliseconds and at end-of-move • filtered so only changed values are reported • setup status report • {sr:{posx:true,posy:true,posz:true, vel:true, momo:true, stat:true}} • status reports for an X move from 0 to 100 • {sr:{posx:0.000,vel:1.54,momo:0,stat:5}} • {sr:{posx:2.494,vel:1740.87}} • {sr:{posx:18.137,vel:5540.05}} • {sr:{posx:43.528,vel:6500.00}} • {sr:{posx:69.885,vel:6393.34}} • {sr:{posx:91.760,vel:3918.13}} • {sr:{posx:99.670,vel:479.38}} • {sr:{posx:100.000,vel:0.00,stat:3}} exception reports • {er:{fb:428.01,st:29,msg:"Generic exception report"}}
Useful Conventions We need some conventions for non-application specific functions don’t innovate. copy. • $ root to discover objects (cribbed from JSONpath) • {$:null} return top-level objects • {r:{x:n,y:n,z:n,a:n,b:n,c:n,1:n,2:n,3:n,4:n,5:n,6:n,sys:n,gm:n,rm:n}},f:[1,0,6,6271]} • @ prefix for addressing, binding and routing • {@3F2504E0-4F89-41D3-9A0C-0305E82C3301:ex1} assign a short name (handle) • {ex1:null} address device “ex1” and route object to that device • # topic prefix • {#time:”2013-03-28T15:52:49.680Z”} devices that want time will process this message • ! priority. Jump the queue • {!fh:true} stop movement now! (feedhold)