├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── docs ├── circuits │ ├── avoidance.fzz │ ├── line_follower.fzz │ ├── motor_no_bt.fzz │ └── motor_with_bt.fzz ├── images │ ├── avoidance_schem.png │ ├── flipper.jpg │ ├── full_bot.fzz │ ├── full_bot_schem.png │ ├── line_follower_schem.png │ ├── motor_no_bt_schem.png │ ├── motor_with_bt_schem.png │ ├── sumo.jpg │ ├── wedge.jpg │ └── whirlygig.jpg ├── img │ ├── blink.jpg │ ├── simplebot-proto.jpg │ ├── simplebot-wifi.jpg │ ├── simplebot_basic.jpg │ ├── simplebot_battle.jpg │ └── simplepibots.jpg ├── linefollower.md ├── obstacleavoider.md └── sumobot.md ├── examples ├── SimpleBotShield │ ├── README.md │ ├── np.js │ ├── ping.js │ └── simplebot.js ├── avoidance.js ├── backoff.js ├── ble-esc.js ├── ble.js ├── blink.js ├── calibrate-line.js ├── esc.js ├── line.js ├── motors.js ├── network_sb.js ├── parking.js ├── sb-controller.js ├── servos.js ├── snes-controller.js ├── snes-controller.png ├── test_servos.js └── wiring │ ├── basic_wiring.fzz │ ├── basic_wiring_bb.png │ └── basic_wiring_schematic.png ├── firmata-license ├── firmware ├── bin │ ├── network │ │ ├── nano │ │ │ └── simplebot_firmata.ino.hex │ │ └── uno │ │ │ └── simplebot_firmata.ino.hex │ └── standard │ │ ├── nano │ │ └── simplebot_firmata.ino.hex │ │ └── uno │ │ └── simplebot_firmata.ino.hex ├── build │ ├── esp8266 │ │ ├── 0x00000.bin │ │ └── 0x40000.bin │ ├── network │ │ └── simplebot_firmata │ │ │ ├── Boards.h │ │ │ ├── Firmata.cpp │ │ │ ├── Firmata.h │ │ │ └── simplebot_firmata.ino │ ├── sbs │ │ └── sbs_firmata │ │ │ ├── Boards.h │ │ │ ├── Firmata.cpp │ │ │ ├── Firmata.h │ │ │ └── sbs_firmata.ino │ └── standard │ │ └── simplebot_firmata │ │ ├── Boards.h │ │ ├── Firmata.cpp │ │ ├── Firmata.h │ │ └── simplebot_firmata.ino └── src │ ├── controller_src │ ├── sbs_firmata │ │ └── sbs_firmata.ino │ └── simplebot_firmata │ │ └── simplebot_firmata.ino │ └── libs │ └── firmata │ ├── Boards.h │ ├── Firmata.cpp │ └── Firmata.h ├── lib └── kb_controller.js ├── package-lock.json ├── package.json ├── physical ├── layout.png ├── plates-sbpi.cb ├── plates-sbpi.dxf ├── plates-sbpi.svg ├── plates.dxf ├── plates.svg └── plates_printed.svg └── utils └── env_template.sh /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "10" 5 | - "8" 6 | git: 7 | submodules: false 8 | 9 | before_install: 10 | # package-lock.json was introduced in npm@5 11 | # skipped when using node 9 12 | - '[[ $(node -v) =~ ^v9.*$ ]] || npm install -g npm@latest' 13 | - npm install -g greenkeeper-lockfile 14 | 15 | install: npm install 16 | 17 | before_script: greenkeeper-lockfile-update 18 | # only v10 will upload the lockfile 19 | after_script: greenkeeper-lockfile-upload 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # SimpleBot project changelog 2 | 3 | ## 0.6 4 | 5 | * Updated dependecies for all packages 6 | * Updated firmata to 2.5.1 7 | * Simplified build process touse same core firmata and update relevant parts 8 | for those targets that need it. 9 | * Deploy bins for uno and nano for the firmware 10 | * Added documentation for the different styles 11 | * Updated readme docs generally. 12 | 13 | ## 0.5 14 | 15 | * Removed some old cruft floating around 16 | * Fixed dependencies to now build from node-pixel source rather than a lock copy 17 | * Updated avoidance example to use Proximity class 18 | * Fixed documentation to be up to date, link to build video and point to the 19 | current serial bridge implementation for WiFi. 20 | * Fixed `simplebot.js` code to be in line with the circuit diagram 21 | * Broke out controller to be more reusable and updated examples with it. 22 | 23 | ## 0.4 24 | 25 | * Updated all packages to latest versions 26 | * changed build packages to use new grunt build process to make them 27 | * Updated firmata to use new proximity firmata in line with J5 28 | * updated examples to use new `Proximity class` 29 | * Updated pixel for SBS to use new `node-pixel` version. 30 | * Added firmware for ESP8266 transparent bridge 31 | * Added example for network simplebot 32 | * Added `network_simplebot_firmata` 33 | 34 | ## 0.3.2 35 | 36 | * Removed some old cruft and old physical files no longer needed. 37 | * Updated SimpleBot chassis with some mods to make simpler and no 3d printed part required. 38 | 39 | ## 0.3.1 40 | 41 | * Added changelog, typos, fixed old NPM url. 42 | 43 | ## 0.3.0 44 | 45 | * New variation added for Simple Pi Bot - RPi based SimpleBot, including new designed chassis. 46 | * Significant repo restructure to accomodate SimpleBot Shield and ino build chain 47 | * Brought in attribution and licenses for everything being used properly 48 | * Migrated build tools to use ino for firmware rather than Arduino 49 | * Updated firmata to latest stable version, 2.4 and ported @jgautier's pulseIn 50 | modifications to it as well as wrapped previous work from RGBLED to use NeoPixels 51 | * Merged example from @holodigm for collision avoidance (https://github.com/nodebotsau/simplebot/pull/12) 52 | * Cleaned out any leostick cruft 53 | * Updated libraries to latest stables. 54 | 55 | ### Contributor acknowledgments: 56 | 57 | * [Alec Clews](https://github.com/alecthegeek) - Rasbian install scripts for RPi (https://github.com/alecthegeek/CCHS_Raspian_for_IoT) 58 | * [Andy Gelme](https://github.com/geekscape) - Continued testing, design advice, 59 | * [Angus Gratton](https://github.com/projectgus) - SimpleBot Shield design and bumper design mods 60 | * [Kym McInerney](https://github.com/holodigm) - collision avoidance example 61 | * [Rick Waldron](https://github.com/rwaldron) - Pixel API suggestions and deep firmata architecture discussion 62 | 63 | ## 0.2.0 64 | 65 | Can't remember before this time. 66 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | var arduino = process.env.ARDUINO_PATH; 2 | 3 | // these are the main target boards for the SimpleBot. 4 | var boards = { 5 | "uno" :{ 6 | package: "arduino:avr:uno", 7 | }, 8 | "nano": { 9 | cpu: "atmega328", 10 | package: "arduino:avr:nano:cpu=atmega328", 11 | }, 12 | }; 13 | 14 | // use this so we can expand it later. 15 | var boardlist = Object.keys(boards).toString(); 16 | 17 | module.exports = function(grunt) { 18 | 19 | // configure the tasks 20 | grunt.initConfig({ 21 | clean: { 22 | firmware_build: { 23 | src: [ 24 | 'firmware/build/standard/simplebot_firmata', 25 | 'firmware/build/sbs/sbs_firmata', 26 | 'firmware/build/network/simplebot_firmata', 27 | ] 28 | }, 29 | compiled_bins: { 30 | src: [ 31 | 'firmware/bin/*' 32 | ] 33 | }, 34 | post_compile: { 35 | src: [ 36 | 'firmware/bin/standard/{' + boardlist + '}/!(*ino.hex)', 37 | 'firmware/bin/network/{' + boardlist + '}/!(*ino.hex)', 38 | ] 39 | }, 40 | }, 41 | copy: { 42 | options: { 43 | timestamp: true, 44 | }, 45 | 46 | simplebot_firmata: { 47 | cwd: 'firmware/src/', 48 | flatten: true, 49 | src: [ 'libs/firmata/**', 'controller_src/simplebot_firmata/*' ], 50 | dest: 'firmware/build/standard/simplebot_firmata/', 51 | expand: true, 52 | filter: 'isFile', 53 | }, 54 | sbs_firmata: { 55 | cwd: './', 56 | flatten: true, 57 | src: [ 'firmware/src/libs/firmata/**', 58 | 'firmware/src/controller_src/sbs_firmata/*', 59 | 'node_modules/node-pixel/firmware/src/libs/neopixel/*', 60 | 'node_modules/node-pixel/firmware/src/libs/ws2812/*' 61 | ], 62 | dest: 'firmware/build/sbs/sbs_firmata/', 63 | expand: true, 64 | filter: 'isFile', 65 | }, 66 | network_simplebot_firmata: { 67 | cwd: 'firmware/src/', 68 | flatten: true, 69 | src: [ 'libs/firmata/**', 'controller_src/simplebot_firmata/*' ], 70 | dest: 'firmware/build/network/simplebot_firmata/', 71 | expand: true, 72 | filter: 'isFile', 73 | }, 74 | }, 75 | 'string-replace': { 76 | precompile: { 77 | files: [{ 78 | src: 'firmware/build/network/simplebot_firmata/simplebot_firmata.ino', 79 | dest: 'firmware/build/network/simplebot_firmata/simplebot_firmata.ino', 80 | }], 81 | options: { 82 | replacements: [{ 83 | pattern: /57600/, 84 | replacement: '115200', 85 | }], 86 | }, 87 | }, 88 | }, 89 | }); 90 | 91 | // load the tasks 92 | grunt.loadNpmTasks('grunt-contrib-copy'); 93 | grunt.loadNpmTasks('grunt-contrib-clean'); 94 | grunt.loadNpmTasks('grunt-string-replace'); 95 | grunt.loadNpmTasks('grunt-exec'); 96 | 97 | // build the bins for the target 98 | // dynamically create the compile targets for the various boards 99 | Object.keys(boards).forEach(function(board) { 100 | var cwd = 'firmware/build/'; 101 | 102 | grunt.config(["exec", board + "_standard"], { 103 | command:function() { 104 | return arduino + " --verify --verbose-build --board " + boards[board].package + 105 | " --pref build.path=firmware/bin/standard/" + board + " " + cwd + 106 | "standard/simplebot_firmata/simplebot_firmata.ino"; 107 | }, 108 | }); 109 | grunt.config(["exec", board + "_network"], { 110 | command:function() { 111 | return arduino + " --verify --verbose-build --board " + boards[board].package + 112 | " --pref build.path=firmware/bin/network/" + board + " " + cwd + 113 | "network/simplebot_firmata/simplebot_firmata.ino"; 114 | }, 115 | }); 116 | }); 117 | 118 | grunt.registerTask('build', ['clean:firmware_build', 'clean:compiled_bins', 'copy', 'string-replace']); 119 | grunt.registerTask('compile', ['build', 'exec', 'clean:post_compile']); 120 | }; 121 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2014 Andrew Fisher 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleBot 2 | 3 | [![Greenkeeper badge](https://badges.greenkeeper.io/nodebotsau/simplebot.svg)](https://greenkeeper.io/) 4 | 5 | ![SimpleBot](docs/img/simplebot_basic.jpg) 6 | 7 | ## Overview 8 | 9 | This is one of the most simple robots you can make. Features are: 10 | 11 | * quick to put together (about an hour) 12 | * very hackable (it can be built with cardboard, corflute or laser cut acrylic 13 | or wood so very easily modifiable) 14 | * can move pretty fast (at full tilt it will go about half a metre a second - 15 | faster if you have more juice for the motors!) 16 | * very extendable (much of the magic happens in code and sensors can be easily added) 17 | * Cheap (costs less than AUD$100 which is very cheap for your first robot) 18 | 19 | This bot is an adaptation of the excellent [SumoBot Jr](https://github.com/makenai/sumobot-jr/) 20 | made by [Paweł Szymczykowski](http://twitter.com/makenai) but doesn't require 21 | laser cutting wood or plastic to make. However you can laser cut it if you want 22 | something a bit more long lasting. 23 | 24 | ## Capabilities 25 | 26 | The SimpleBot can be tethered over USB or controlled via Bluetooth Serial or 27 | over the network using WiFi. Your computer will do all the hard work of 28 | control processing and interface control etc and just send messages to the 29 | board to steer it. 30 | 31 | If you get really sophisticated you can make it have some AI. 32 | 33 | This is the very first prototype, put together in about 30 minutes one evening. 34 | 35 | ![SimpleBot](docs/img/simplebot-proto.jpg) 36 | 37 | As this is such a simple robot, once you've got it working you can then extend 38 | it to make it much more capable including becoming wireless. This one has been 39 | extended with a wifi module to untether it from your computer.. 40 | 41 | ![SimpleBot MkII](docs/img/simplebot-wifi.jpg) 42 | 43 | Once you understand how things work you can reuse all of the components to 44 | make a bigger, badder, faster robot and switch the cardboard for more durable 45 | elements such as laser cut wood or plastic if you desire. 46 | We've even [supplied the SVG and DXF files to do exactly that](/physical). 47 | 48 | Add a raspberry pi and you get a SimplePiBot which can be made fully autonomous. 49 | 50 | ![SimplePiBot](docs/img/simplepibots.jpg) 51 | 52 | ## Materials needed 53 | 54 | The following are the various components you need to get hold of to make a basic 55 | SimpleBot. If you're making this at a NodeBots event you'll have a set of 56 | components in your kits. 57 | 58 | | # | Component | Notes | 59 | |:--:|------------------|-----------------------------------------------------------------------------------------| 60 | | 1 | Arduino | We use Nanos because they are small and inexpensive (and light) but any arduino will do | 61 | | 10 | M-M Jumper wires | The more the better but 10 will be enough to build with | 62 | | 2 | DC Motors | These are common - get ones with wheels & gears | 63 | | 1 | Battery pack | LiPo or 4xAA - about 5V is what you're after | 64 | | 1 | Mini breadboard | Smaller is better | 65 | | 10 | Cable ties | 3-4mm wide and about 100-200mm long is a good size to work with. The more the better | 66 | 67 | Other things you might want to add to your bot: 68 | 69 | * Laser pointer to make an annoying cat toy. 70 | * Stickers to bling out your bot. 71 | * Spikes to take out others; Ben Hur or Mad Max style. 72 | * USB WebCam if you want to give your bot some vision. 73 | * USB cable extender if you want some range. 74 | * Bluetooth or wireless modules to remove the USB cable. 75 | * An Ultrasonic sensor to do obstacle detection 76 | * Reflectance sensors to do line following 77 | 78 | # Installation and setup 79 | 80 | Start with the [installation process outlined here](https://github.com/nodebotsau/nbdau/blob/master/setup.md) 81 | if you haven't already done so. 82 | 83 | ## Install the code dependencies 84 | 85 | Clone the repo and install everything from here: 86 | 87 | ``` 88 | git clone https://github.com/nodebotsau/simplebot.git 89 | cd simplebot 90 | npm install 91 | ``` 92 | 93 | ## Flashing the arduino 94 | 95 | Use `interchange` to install the firmware to the arduino. Plug the arduino in 96 | and then run the following command from your terminal. 97 | 98 | ``` 99 | interchange install hc-sr04 -a nano --firmata 100 | ``` 101 | 102 | Assuming you get no errors, you're good to go on that front. 103 | 104 | ## Run a basic blink program 105 | 106 | Next, to test you've got Firmata running, run a basic blink program with the following command: 107 | 108 | ``` 109 | node examples/blink.js 110 | ``` 111 | 112 | If it all goes well. You'll see a blinking LED positioned next to the L on your arduino. 113 | 114 | ``` 115 | [ ] RX 116 | [ ] TX 117 | [*] POW 118 | [*] L <--- this light will start flashing 119 | ``` 120 | 121 | ![docs/img/blink.jpg](docs/img/blink.jpg) 122 | 123 | Open the [`examples/blink.js`](examples/blink.js) program in an editor and look at the code. Its currently set to blink every 500ms. 124 | 125 | Try changing this to 100ms and see if it blinks faster now. 126 | 127 | ```js 128 | board.on("ready", function() { 129 | var led = new five.Led(13); 130 | led.blink(500); // <--- try changing this value see if it blinks faster/slower 131 | }); 132 | ``` 133 | 134 | ## Build a SimpleBot 135 | 136 | You can go in a few different directions with the SimpleBot. Details for the 137 | different styles can be found below however the common principles are 138 | discussed in the next section. 139 | 140 | * [SumoBot](docs/sumobot.md) 141 | * [Line Follower](docs/linefollower.md) 142 | * [Obstacle avoider](docs/obstacleavoider.md) 143 | 144 | ### Differential drive 145 | 146 | Each SimpleBot is a little different because it's yours but the general principles 147 | are the same. You have two motors, each of which drive a wheel - this is called 148 | [differential drive](https://en.wikipedia.org/wiki/Differential_wheeled_robot) - 149 | and the combination of these working together will drive the robot forward, backwards 150 | and turn on the spot each way. 151 | 152 | Use cable-ties (zip ties) to join everything to the chassis. 153 | 154 | If you want to see a video explaining this in more detail there's a version 155 | on [you tube](https://www.youtube.com/watch?v=KoACCjtkHIg) (this uses servos on 156 | an older Mark III SimpleBot but the principle holds). 157 | 158 | ### Basic wiring 159 | 160 | The wiring diagrams are provided here: 161 | 162 | Schematic: 163 | 164 | ![SimpleBot schematic](docs/images/motor_no_bt_schem.png) 165 | 166 | 167 | # Examples 168 | 169 | ## A simple drive example 170 | 171 | In the `examples` folder you can see an example called `motors.js` or 172 | `servos.js` - choose the version depending on your motor types. This is 173 | a very simple control example which uses the arrow and space keys on the keyboard 174 | to drive the SimpleBot around. 175 | 176 | Simply run: 177 | 178 | ```shell 179 | node examples/motors.js SERIAL_DEVICE 180 | ``` 181 | 182 | ```shell 183 | node examples/servos.js SERIAL_DEVICE 184 | ``` 185 | 186 | Where `SERIAL_DEVICE` is the path to the serial port (eg `/dev/tty/USB0`). 187 | 188 | You should now be able to drive your robot around happily. Go get a few friends 189 | to build one too and you can have SumoBot Battles. 190 | 191 | ![A simplebot battle royale at NodeBots Day](docs/img/simplebot_battle.jpg) 192 | 193 | 194 | ### Tuning servos 195 | 196 | If you are using servos and they don't entirely stop then tune the stop value in the code by 197 | setting a LSTOP and RSTOP value that is a little either side of 90 (this is 198 | because CR servos are a hack and may need some tuning). 199 | 200 | ## Driving over Bluetooth 201 | 202 | You can use bluetooth to drive the simplebot. 203 | 204 | Get a bluetooth module and configure it. This is a mandatory step before you can 205 | do it properly.. 206 | 207 | Per [this wiki entry in J5](https://github.com/rwaldron/johnny-five/wiki/Getting-Started-with-Johnny-Five-and-JY-MCU-Bluetooth-Serial-Port-Module) 208 | 209 | ### Wiring for BT. 210 | 211 | Connect the BT Module TX pin to the Arduino RX pin and the BT Module RX pin to 212 | the Arduino TX pin and you should be ready to go. Note that if you need to 213 | flash the arduino or anything you need to unplug the BT module. 214 | 215 | ### Connecting 216 | 217 | Once you've got your bluetooth set up, pair it with your computer so it appears 218 | as a serial device. 219 | 220 | Simply go: 221 | 222 | ``` 223 | node examples/motors.js /dev/tty.SERIALPORT 224 | ``` 225 | 226 | Changing the device path to whatever yours is to the Bluetooth Module. You 227 | should now be able to drive using wireless over bluetooth just the same as 228 | using a USB cable. 229 | 230 | ## Game controller 231 | 232 | If you happen to have a playstation controller then you can use the 233 | sb-controller.js example to drive your simplebot using a console controller 234 | which is pretty cool. 235 | 236 | # LICENSE NOTES 237 | 238 | This SimpleBot repo is licensed using the MIT license for all components. 239 | 240 | Firmata implementations are modifications of 241 | [https://github.com/firmata/arduino/](Firmata for Arduino) by 242 | [https://github.com/soundanalogous](Jeff Hoefs @soundanalagous) and others and 243 | is used according to the GPL. 244 | 245 | Firmata modifications include merged components of 246 | the [https://github.com/jgautier/arduino-1/tree/pulseIn](pulseIn code) as 247 | created by [https://github.com/jgautier](Julian Gautier @jgautier). 248 | 249 | -------------------------------------------------------------------------------- /docs/circuits/avoidance.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/circuits/avoidance.fzz -------------------------------------------------------------------------------- /docs/circuits/line_follower.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/circuits/line_follower.fzz -------------------------------------------------------------------------------- /docs/circuits/motor_no_bt.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/circuits/motor_no_bt.fzz -------------------------------------------------------------------------------- /docs/circuits/motor_with_bt.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/circuits/motor_with_bt.fzz -------------------------------------------------------------------------------- /docs/images/avoidance_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/avoidance_schem.png -------------------------------------------------------------------------------- /docs/images/flipper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/flipper.jpg -------------------------------------------------------------------------------- /docs/images/full_bot.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/full_bot.fzz -------------------------------------------------------------------------------- /docs/images/full_bot_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/full_bot_schem.png -------------------------------------------------------------------------------- /docs/images/line_follower_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/line_follower_schem.png -------------------------------------------------------------------------------- /docs/images/motor_no_bt_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/motor_no_bt_schem.png -------------------------------------------------------------------------------- /docs/images/motor_with_bt_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/motor_with_bt_schem.png -------------------------------------------------------------------------------- /docs/images/sumo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/sumo.jpg -------------------------------------------------------------------------------- /docs/images/wedge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/wedge.jpg -------------------------------------------------------------------------------- /docs/images/whirlygig.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/images/whirlygig.jpg -------------------------------------------------------------------------------- /docs/img/blink.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/img/blink.jpg -------------------------------------------------------------------------------- /docs/img/simplebot-proto.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/img/simplebot-proto.jpg -------------------------------------------------------------------------------- /docs/img/simplebot-wifi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/img/simplebot-wifi.jpg -------------------------------------------------------------------------------- /docs/img/simplebot_basic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/img/simplebot_basic.jpg -------------------------------------------------------------------------------- /docs/img/simplebot_battle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/img/simplebot_battle.jpg -------------------------------------------------------------------------------- /docs/img/simplepibots.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/docs/img/simplepibots.jpg -------------------------------------------------------------------------------- /docs/linefollower.md: -------------------------------------------------------------------------------- 1 | # Physical layout and design considerations for a Line Following robot 2 | 3 | This document explains some of the design considerations you might want to 4 | think about when building your robot. 5 | 6 | ## Electronics 7 | 8 | The core electronics are as discussed for the basic SimpleBot build. You should 9 | have a robot you can control with a keyboard to drive around. 10 | 11 | ### Additional components 12 | 13 | * 2x Reflectance sensors 14 | 15 | The diagram below shows the electronics schematic for a basic set up. 16 | 17 | ![](images/line_follower_schem.png) 18 | 19 | ## Physical modifications 20 | 21 | The reflectance sensors need to be pretty close to the ground, less than 1cm 22 | is ideal. Mount them the same distance apart as the tape you'll be detecting. 23 | What you want is for both sensors to be on the tape at the same time and you 24 | can then tell when you are drifting off. 25 | 26 | ## Calibrating your sensors 27 | 28 | Once you have the sensors wired up run `examples/calibrate-line.js` and 29 | then slowly turn your bot back and forth over the line in order to get a sense 30 | of what the minimum and maximum numbers it's seeing. 31 | 32 | If you have a really contrasty surface you should get numbers close to 1023 for 33 | full reflection and close to 0 for full absorption. The reality is you'll see 34 | something inside that range. 35 | 36 | Note down numbers that give you fairly definitive "on the line" and "off the line" 37 | values. 38 | 39 | ## How line following works 40 | 41 | The most simple line following algorithm is this: 42 | 43 | ``` 44 | // precondition: Both sensors start on the line 45 | 46 | loop: 47 | drive both motors forward 48 | if (left sensor is off line): 49 | turn off right motor 50 | if (right sensor is off line): 51 | turn off left motor 52 | ``` 53 | 54 | This very simple code will check each of the sensors every time it loops. If 55 | the sensor is on the line then that wheel will stay on as you want it to drive 56 | forwards. If it comes off the line however, you turn the *opposite* wheel off 57 | so that the wheel on the same side of the robot as the sensor is keeps driving. 58 | This will pivot the bot back towards the line and it should move forwards again. 59 | 60 | This algorithm is a naive approach and it does work but it is prone to 61 | overshooting and not handling sharp turns. You can make it better with more 62 | line sensors but also by reading the drift to see how much you've drifted or 63 | for how long, this allows you to determine how much to turn back. 64 | 65 | ## Examples 66 | 67 | In the `examples/simplebot-line.js` file you can see a basic example of this 68 | algorithm in practice. If you put your bot on the test track and and run this 69 | code you should see it slowly drive around the track, correcting its position 70 | if it starts to drive off. 71 | 72 | -------------------------------------------------------------------------------- /docs/obstacleavoider.md: -------------------------------------------------------------------------------- 1 | # Physical layout and design considerations for an obstacle avoiding robot 2 | 3 | This document explains some of the design considerations you might want to 4 | think about when building your robot. 5 | 6 | ## Electronics 7 | 8 | The core electronics are as discussed for the basic SimpleBot build. You should 9 | have a robot you can control with a keyboard to drive around. 10 | 11 | ### Additional components 12 | 13 | * 1x Ultrasonic range finder 14 | 15 | The diagram below shows the electronics schematic for a basic set up. 16 | 17 | 18 | ![](images/avoidance_schem.png) 19 | 20 | Note that the echo and trigger pins on the sensor are wired to the same pin 21 | as the arduino can use both. 22 | 23 | ## Physical modifications 24 | 25 | As you see the range finder looks like a pair of eyes and it does "see" like 26 | a bat. As such you want to mount these on the front of your robot so they are 27 | unobstructed. Cable ties work very well for this. 28 | 29 | ## Examples 30 | 31 | In the `examples/simplebot-avoidance.js` file you can see a basic example that 32 | will allow you to drive around until you get within 10cm of an obstacle and 33 | then the SimpleBot will stop. 34 | -------------------------------------------------------------------------------- /docs/sumobot.md: -------------------------------------------------------------------------------- 1 | # Physical layout and design considerations for a SumoBot 2 | 3 | This document explains some of the design considerations you might want to 4 | think about when building your robot. 5 | 6 | ## Electronics 7 | 8 | The diagram below shows the electronics schematic for a basic set up. 9 | 10 | ![Full schematic](images/motor_with_bt_schem.png) 11 | 12 | If you do this however, once you move to bluetooth you may run into power 13 | issues where the arduino resets on you. This will be particularly noticeable 14 | when the battery is running flat. So what can you do? 15 | 16 | First, keep your battery charged up. You have a charger to do exactly that so 17 | use it. A full LiPo battery gives a nice solid voltage everything can use so 18 | charge between tests and battles. 19 | 20 | The second option is to use two batteries. One for your controllers and one for 21 | your motors. The schematic for this is mostly the same except the VCC and GND 22 | lines for your motors and servo connect to the second battery instead. 23 | 24 | ## Design styles 25 | 26 | The maximum size of your bot is 25cm x 25cm x25cm - it has to fit inside that 27 | to go in the ring. Too big and you're disqualified. 28 | 29 | There are several design archetypes: 30 | 31 | ### The Wedge 32 | 33 | This is a triangular wedge shape with the main aim being to stay low, move 34 | fast and get under your opponent and run them out of the ring. 35 | 36 | ![A perfect example of the Wedge](images/wedge.jpg) 37 | 38 | To do this effectively: 39 | 40 | * Go as light as possible - everything extraneous must be removed 41 | * Attempt to deliver as much speed as possible. This will affect your steering so 42 | drivers need to practice rapid changes of direction and control. 43 | * Traction is critical - when hit an opponent you need traction, make sure 44 | your wheels will grip the floor. 45 | * You need a wedge - it sounds obvious but your whole robot needs to be a wedge 46 | to effectively slide under your opponent. Fabrication of this is critical. 47 | 48 | Tactics: 49 | 50 | The wedge is all about speed and out manoeuvring your oppenent, especially 51 | those who are slow or have poor turning capability. Look for areas on the 52 | opponent that are raised that will allow you to get underneath. Attack from a 53 | weak side and go fast - don't be afraid to peel off and come back for another run. 54 | 55 | ### The Sumo 56 | 57 | This design calls for weight. You'll move more slowly but with more mass. The 58 | aim is to use your superior weight advantage to push the other opponent out 59 | of the ring. 60 | 61 | ![A tractor style design. Push, push, push!](images/sumo.jpg) 62 | 63 | To do this effectively: 64 | 65 | * Look how you can weight your whole robot. Avoid just weighting one part as 66 | this will make you unbalanced. 67 | * You need traction. You're going to go slow, so deliver all the force you can 68 | to your wheels. 69 | * Protect your flanks - your turning speed will be poor so look at ways to 70 | protect your sides (or better yet, make your bot usable in any direction not just 71 | forwards). 72 | * Snarl your opponent - if your opponent can't move then you can just grind them 73 | out of the ring. 74 | 75 | Tactics: 76 | 77 | Slow and steady wins the bout. Stay to the middle until your opponent is nearby 78 | then wait for them to try and attack you. Make sure you meet them head on and 79 | then use your superior weight to just push them out of the circle. Don't get 80 | caught on the edge. 81 | 82 | ### The flipper 83 | 84 | Hard to pull off effectively, this design is all about winning in style. The aim is to 85 | make a section of your bot that can use servos to flip an opponent. Once they 86 | are incapable of moving, it's a simple task to push them out. 87 | 88 | ![You definitely don't want to be anywhere near the front of this](images/flipper.jpg) 89 | 90 | To do this effectively: 91 | 92 | * Keep your servo movement small. Servos move at a fixed speed and you want 93 | this to happen fast to catch your opponent off guard. Use mechanical means to 94 | amplify your servo movement into bigger actions. 95 | * Practice your flips against things. It sounds obvious but does your flipper 96 | flip? 97 | 98 | Tactics: 99 | 100 | Your objective is to close front on and then get your flipper under your 101 | opponent. From there, ACTIVATE and turn that other bot over. Once you've 102 | incapacitated your opponent, just push them out. Your flipper is your key 103 | weapon so make sure you're bringing it to bear on your opponent. 104 | 105 | ### The whirlygig 106 | 107 | This is possibly the craziest design, but pulled off well and it's brutally 108 | effective. You aim is the wholesale destruction of your opponents' electronics 109 | by using a whirling arm mounted on your bot. 110 | 111 | ![The pickaxe is a classic of this style](images/whirlygig.jpg) 112 | 113 | To do this effectively: 114 | 115 | * Use servos attached to choppers or other mechanical means of wrecking your 116 | opponent's systems. 117 | * It makes you unbalanced but the higher you can come over the top of your 118 | opponent the more chance you have to rip something important out of their 119 | robot. 120 | * Some particularly devastating whirlygigs just spear their opponent then drop 121 | them outside the ring. 122 | 123 | Tactics: 124 | 125 | You really only have one objective, close with your opponent and unleash your 126 | chopper, smasher, grabber or whirler as fast and as frequently as possible in 127 | an attempt to maximise damage. A few stray wires ripped out and your opponent 128 | will be dead in the ring. Use that opportunity to just ram them out of it. 129 | -------------------------------------------------------------------------------- /examples/SimpleBotShield/README.md: -------------------------------------------------------------------------------- 1 | # Using the SimpleBot Shield 2 | 3 | If you have a SimpleBot shield you will need an arduino to go with it. 4 | 5 | Key features of the shield are: 6 | 7 | * Servo headers broken out for Left and Right wheels on pins 9 & 10 8 | * Additional headers broken out for pins 2,3,5,6 using servo pin out style (sig, 5v, gnd) 9 | * 4xWS2812b RGB LEDs (NeoPixels) on the corners of the board attached to pin 6 10 | * Ultrasonic sensor broken out attached to pin 8 11 | * Breakouts for Analog pins 1-5 using screw terminals 12 | * I2C breakout for optional IMU9 module 13 | 14 | ## Populating the board 15 | 16 | Here are the [build instructions for the board](http://www.openhardwareconf.org/wiki/SimpleBot_Shield_Assembly). 17 | 18 | More [detailed instructions](http://www.openhardwareconf.org/wiki/Surface_Mount_Assembly_for_SimpleBot_Shield) on soldering the WS2812 LEDs is available here. 19 | 20 | ## Preparing custom firmata 21 | 22 | To use this shield in total you will need a custom version of firmata that 23 | comprises all the additional libraries you need to make it work. This ships 24 | as part of this repo in the firmware directory. You will need to use ino tool to 25 | compile and upload this to the board so [follow the getting started directions](http://inotool.org/#installation) for 26 | ino tool before attempting the next component. 27 | 28 | To install firmata (and install all node dependencies also) follow the directions below. 29 | 30 | ``` 31 | cd ~ 32 | git clone https://github.com/nodebotsau/simplebot 33 | cd simplebot 34 | npm install 35 | cd firmware/ino/SBSFirmata 36 | ino clean && ino build -m uno 37 | ``` 38 | 39 | You should see the output of the build sequence and get a positive response from ino 40 | as below: 41 | 42 | ``` 43 | Searching for Board description file (boards.txt) ... /home/pi/arduino-1.0.5/hardware/arduino/boards.txt 44 | Searching for Arduino lib version file (version.txt) ... /home/pi/arduino-1.0.5/lib/version.txt 45 | Detecting Arduino software version ... 1.0.5 (1.0.5) 46 | Searching for Arduino core library ... /home/pi/arduino-1.0.5/hardware/arduino/cores/arduino 47 | Searching for Arduino variants directory ... /home/pi/arduino-1.0.5/hardware/arduino/variants 48 | Searching for Arduino standard libraries ... /home/pi/arduino-1.0.5/libraries 49 | Searching for make ... /usr/bin/make 50 | Searching for avr-gcc ... /usr/bin/avr-gcc 51 | Searching for avr-g++ ... /usr/bin/avr-g++ 52 | Searching for avr-ar ... /usr/bin/avr-ar 53 | Searching for avr-objcopy ... /usr/bin/avr-objcopy 54 | src/SBSFirmata.ino 55 | Searching for Arduino lib version file (version.txt) ... /home/pi/arduino-1.0.5/lib/version.txt 56 | Detecting Arduino software version ... 1.0.5 (1.0.5) 57 | Scanning dependencies of src 58 | Scanning dependencies of Servo 59 | Scanning dependencies of neopixel 60 | Scanning dependencies of ws2812 61 | Scanning dependencies of Wire 62 | Scanning dependencies of arduino 63 | src/Firmata.cpp 64 | src/SBSFirmata.cpp 65 | Servo/Servo.cpp 66 | Linking libServo.a 67 | ws2812/ws2812.cpp 68 | Linking libws2812.a 69 | Wire/utility/twi.c 70 | Wire/Wire.cpp 71 | Linking libWire.a 72 | neopixel/Adafruit_NeoPixel.cpp 73 | Linking libneopixel.a 74 | arduino/wiring_pulse.c 75 | arduino/wiring_analog.c 76 | arduino/WInterrupts.c 77 | arduino/wiring_shift.c 78 | arduino/avr-libc/malloc.c 79 | arduino/avr-libc/realloc.c 80 | arduino/wiring_digital.c 81 | arduino/wiring.c 82 | arduino/WString.cpp 83 | arduino/new.cpp 84 | arduino/Print.cpp 85 | arduino/main.cpp 86 | arduino/Stream.cpp 87 | arduino/CDC.cpp 88 | arduino/HID.cpp 89 | arduino/USBCore.cpp 90 | arduino/WMath.cpp 91 | arduino/Tone.cpp 92 | arduino/HardwareSerial.cpp 93 | arduino/IPAddress.cpp 94 | Linking libarduino.a 95 | Linking firmware.elf 96 | Converting to firmware.hex 97 | ``` 98 | 99 | Assuming no errors go ahead and upload using one of the options below. 100 | 101 | If just a standard Arduino then: 102 | 103 | ino upload -m uno 104 | 105 | If you're using a PiLeven then: 106 | 107 | ino upload -m uno -p /dev/ttyS99 108 | 109 | You will get something similar to the following output: 110 | 111 | ``` 112 | Searching for stty ... /bin/stty 113 | Searching for avrdude ... /home/pi/arduino-1.0.5/hardware/tools/avrdude 114 | Searching for avrdude.conf ... /home/pi/arduino-1.0.5/hardware/tools/avrdude.conf 115 | Guessing serial port ... /dev/ttyACM0 116 | 117 | avrdude: AVR device initialized and ready to accept instructions 118 | 119 | Reading | ################################################## | 100% 0.00s 120 | 121 | avrdude: Device signature = 0x1e950f 122 | avrdude: reading input file ".build/uno-620a679d/firmware.hex" 123 | avrdude: writing flash (17628 bytes): 124 | 125 | Writing | ################################################## | 100% 3.16s 126 | 127 | avrdude: 17628 bytes of flash written 128 | avrdude: verifying flash memory against .build/uno-620a679d/firmware.hex: 129 | avrdude: load data flash data from input file .build/uno-620a679d/firmware.hex: 130 | avrdude: input file .build/uno-620a679d/firmware.hex contains 17628 bytes 131 | avrdude: reading on-chip flash data: 132 | 133 | Reading | ################################################## | 100% 2.47s 134 | 135 | avrdude: verifying ... 136 | avrdude: 17628 bytes of flash verified 137 | 138 | avrdude: safemode: Fuses OK 139 | 140 | avrdude done. Thank you. 141 | ``` 142 | 143 | If there's no errors then you now have the relevant firmata on your arduino for the 144 | SimpleBot Shield. 145 | 146 | ## Using the examples 147 | 148 | AS part of the repos, three examples are provided that are designed to work 149 | specifically to the shield. These are located in the same folder as this 150 | README and are described below 151 | 152 | All examples should be called from the root of the repo after having executed: 153 | 154 | ``` 155 | npm install 156 | ``` 157 | 158 | In order to install the node dependencies. 159 | 160 | ### simplebot.js 161 | 162 | This is a simple driving example taking input from the keyboard to drive your 163 | SimpleBot around. The arrow keys drive it forward, backwards and turn it 164 | left and right. Space will stop it. 165 | 166 | To run, use the command below, substituting /dev/ttyS99 for the port of your 167 | arduino for your environment. 168 | 169 | ``` 170 | nodejs examples/SimpleBotShield/simplebot.js /dev/ttyS99 171 | ``` 172 | 173 | ### ping.js 174 | 175 | This example shows how the ping sensor works and reports back the range in 176 | cm and inches to an obstacle. 177 | 178 | To run, use the command below, substituting /dev/ttyACM0 for the port of your 179 | arduino for your environment. 180 | 181 | ``` 182 | nodejs examples/SimpleBotShield/ping.js /dev/ttyACM0 183 | ``` 184 | 185 | Output will look like this (use Ctrl+C to quit): 186 | 187 | ``` 188 | 1420024159594 Connected /dev/ttyACM0 189 | 1420024159599 Repl Initialized 190 | >> Object is 15.259 cm away 191 | Object is 5.98 inches away 192 | Object is 33.431 cm away 193 | Object is 13.1 inches away 194 | ``` 195 | 196 | ### np.js 197 | 198 | This example shows how the neopixels can be lit and will move a single pixel 199 | clockwise around the board moving through different colours. 200 | 201 | To run, use the command below, substituting /dev/ttyACM0 for the port of your 202 | arduino in your environment. 203 | 204 | ``` 205 | nodejs examples/SimpleBotShield/np.js /dev/ttyACM0 206 | ``` 207 | 208 | If you review the code you can see a single pixel is being updated and cycling 209 | through various color names. Pixel can take a few options as illustrated below: 210 | 211 | ``` 212 | // strip.color() applies to the whole set of LEDs 213 | // strip.show() is required once you have made your color manipulations in order 214 | // to latch the LED strip and make them work. 215 | 216 | strip.color("#ff0000"); // set whole strip red 217 | 218 | // You can use HTML CSS color names and RGB values will be created 219 | strip.color("teal"); // sets strip to a blue-green color. 220 | 221 | // You can also use RGB values if you desire as shown below 222 | strip.color("rgb(0, 255, 0)"); // sets strip to green. 223 | 224 | // individual pixels can be addressed as well. 225 | var p = strip.pixel(1); // get second LED 226 | 227 | // and colors work just the same way on individual pixels too. 228 | p.color("#0000FF"); // set second pixel blue. 229 | 230 | // calling color() by itself will return an object with the current color 231 | p.color(); // returns {r:0, g:0, b:255, hexcode:"#0000ff", color:"blue"} 232 | ``` 233 | 234 | ## Going further 235 | 236 | There are plenty of things you can do with a simplebot shield for example: 237 | 238 | * Use the pixels to give you blinkers when you turn 239 | * Back up when you get too close to an obstacle. 240 | * direct the LEDs and use it to signal another SimpleBot 241 | * Make a bot that dances and lights up when you get a tweet. 242 | -------------------------------------------------------------------------------- /examples/SimpleBotShield/np.js: -------------------------------------------------------------------------------- 1 | var five = require("johnny-five"); 2 | var pixel = require("node-pixel"); 3 | 4 | var opts = {}; 5 | opts.port = process.argv[2] || ""; 6 | 7 | var board = new five.Board(opts); 8 | var strip = null; 9 | 10 | console.log("Starting"); 11 | 12 | board.on("ready", function() { 13 | 14 | console.log("Board ready, lets add light"); 15 | 16 | strip = new pixel.Strip({ 17 | data: 6, 18 | length: 4, 19 | board: this, 20 | controller: "FIRMATA", 21 | }); 22 | 23 | var pos = 0; 24 | var colors = ["red", "green", "blue", "yellow", "cyan", "magenta", "white"]; 25 | var current_color = 0; 26 | 27 | var blinker = setInterval(function() { 28 | 29 | strip.color("#000"); // blanks it out 30 | 31 | if (++pos >= strip.stripLength()) { 32 | pos = 0; 33 | if (++current_color>= colors.length) current_color = 0; 34 | } 35 | strip.pixel(pos).color(colors[current_color]); 36 | 37 | strip.show(); 38 | }, 1000/2); 39 | }); 40 | -------------------------------------------------------------------------------- /examples/SimpleBotShield/ping.js: -------------------------------------------------------------------------------- 1 | var five = require("johnny-five"); 2 | 3 | var opts = {}; 4 | opts.port = process.argv[2] || ""; 5 | 6 | var board = new five.Board(opts); 7 | 8 | board.on("ready", function() { 9 | 10 | //Create new Ping and show distance on change 11 | var ping = new five.Proximity({ 12 | pin: 8, 13 | controller: "HCSR04", 14 | freq: 200, 15 | }); 16 | 17 | ping.on("change", function( err, value ) { 18 | 19 | console.log('Object is ' + this.cm + ' cm away'); 20 | console.log('Object is ' + this.inches + ' inches away'); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /examples/SimpleBotShield/simplebot.js: -------------------------------------------------------------------------------- 1 | // ======================= 2 | // Derived from the work done by @makenai on the 3 | // SumoBot Jr 4 | // ======================= 5 | 6 | var five = require("johnny-five"); 7 | var keypress = require('keypress'); 8 | 9 | var RSTOPVAL = 93; 10 | var LSTOPVAL = 90; 11 | 12 | var opts = {}; 13 | opts.port = process.argv[2] || ""; 14 | 15 | keypress(process.stdin); 16 | 17 | var board = new five.Board(opts); 18 | 19 | board.on("ready", function() { 20 | 21 | console.log("Control the bot with the arrow keys, and SPACE to stop.") 22 | 23 | var left_wheel = new five.Servo({ pin: 9, type: 'continuous' }); 24 | var right_wheel = new five.Servo({ pin: 10, type: 'continuous' }); 25 | 26 | process.stdin.resume(); 27 | process.stdin.setEncoding('utf8'); 28 | process.stdin.setRawMode(true); 29 | 30 | process.stdin.on('keypress', function (ch, key) { 31 | 32 | if ( !key ) return; 33 | 34 | if ( key.name == 'q' ) { 35 | console.log('Quitting'); 36 | process.exit(); 37 | } else if ( key.name == 'up' ) { 38 | 39 | console.log('Forward'); 40 | left_wheel.cw(); 41 | right_wheel.ccw(); 42 | 43 | } else if ( key.name == 'down' ) { 44 | 45 | console.log('Backward'); 46 | left_wheel.ccw(); 47 | right_wheel.cw(); 48 | 49 | } else if ( key.name == 'left' ) { 50 | 51 | console.log('Left'); 52 | left_wheel.ccw(); 53 | right_wheel.ccw(); 54 | 55 | } else if ( key.name == 'right' ) { 56 | 57 | console.log('Right'); 58 | left_wheel.cw(); 59 | right_wheel.cw(); 60 | 61 | } else if ( key.name == 'space' ) { 62 | 63 | console.log('Stopping'); 64 | left_wheel.to(LSTOPVAL); 65 | right_wheel.to(RSTOPVAL); 66 | 67 | } 68 | }); 69 | }); 70 | 71 | board.on("error", function(err) { 72 | console.log(err.message); 73 | process.exit(); 74 | }); 75 | 76 | -------------------------------------------------------------------------------- /examples/avoidance.js: -------------------------------------------------------------------------------- 1 | // ======================= 2 | // Build off the basic simplebot for avoidance 3 | // 4 | // ======================= 5 | var five = require("johnny-five"); 6 | var Controller = require("../lib/kb_controller.js"); 7 | 8 | var opts = {}; 9 | var board = new five.Board(opts); 10 | 11 | var range = 10 // distance in cms 12 | 13 | board.on("ready", function() { 14 | 15 | var left_wheel = new five.Servo.Continuous(9); 16 | var right_wheel = new five.Servo.Continuous(8); 17 | 18 | var controller = new Controller({ 19 | left: left_wheel, 20 | right: right_wheel, 21 | lstop: 90, // use these to set the stop value of the servo 22 | rstop: 90, 23 | }); 24 | 25 | // Create new Ping and use to avoid collisions. 26 | 27 | console.log('Initialising Range Finder'); 28 | var ping = new five.Proximity({ 29 | pin: 10, 30 | freq: 200, 31 | controller: "HCSR04" 32 | }); 33 | 34 | ping.on("change", function( err, value ) { 35 | 36 | if (this.cm < range) { 37 | console.log('WARNING: Collision avoidance activated at: ' + this.cm + ' cm'); 38 | left_wheel.to(controller.LSTOPVAL); 39 | right_wheel.to(controller.RSTOPVAL); 40 | } 41 | 42 | }); 43 | }); 44 | 45 | board.on("error", function(err) { 46 | console.log(err.message); 47 | process.exit(); 48 | }); 49 | -------------------------------------------------------------------------------- /examples/backoff.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | // Simplebot program that backs off when something is detected in front of the 3 | // robot and waits until it's safe, then returns to original position 4 | 5 | const PORT = 'COM3' 6 | const SENSOR_PIN = 7 7 | const LEFT_PIN = 9 8 | const RIGHT_PIN = 8 9 | const LEFT_DEADBAND = [88, 88] 10 | const RIGHT_DEADBAND = [92, 92] 11 | const MIN_DISTANCE = 10 12 | const SAFE_DISTANCE = 15 13 | const WAIT = 1000 14 | const INTERVAL = 10 15 | 16 | const five = require("johnny-five") 17 | const board = new five.Board({port: PORT}) 18 | 19 | board.on("ready", function() { 20 | const left = new five.Servo({pin: LEFT_PIN, type: 'continuous', invert: true, deadband: LEFT_DEADBAND}) 21 | const right = new five.Servo({pin: RIGHT_PIN, type: 'continuous', deadband: RIGHT_DEADBAND}) 22 | const proximity = new five.Proximity({ 23 | controller: "HCSR04", 24 | pin: SENSOR_PIN 25 | }) 26 | 27 | let backoff = 0 28 | let backingOff = false 29 | let waiting = 0 30 | let safe = true 31 | 32 | setInterval(() => { 33 | if (backingOff) { 34 | left.cw() 35 | right.cw() 36 | backoff = backoff + INTERVAL 37 | waiting = 0 38 | } else if (waiting < WAIT && safe) { 39 | waiting = waiting + INTERVAL 40 | left.stop() 41 | right.stop() 42 | } else if (backoff > 0 && safe) { 43 | left.ccw() 44 | right.ccw() 45 | backoff = backoff - INTERVAL 46 | } else { 47 | left.stop() 48 | right.stop() 49 | } 50 | // console.log(backoff, waiting, backingOff, safe) 51 | }, INTERVAL) 52 | 53 | proximity.on("change", function() { 54 | backingOff = (this.cm < MIN_DISTANCE) 55 | safe = (this.cm > SAFE_DISTANCE) 56 | }); 57 | 58 | this.repl.inject({ 59 | left: left, right: right, proximity: proximity 60 | }) 61 | }) -------------------------------------------------------------------------------- /examples/ble-esc.js: -------------------------------------------------------------------------------- 1 | const BleIO = require("ble-io"); 2 | const five = require("johnny-five"); 3 | const keypress = require("keypress"); 4 | 5 | let esc; 6 | let cur_pos = 90; 7 | const MAX = 130; 8 | const MIN = 75; 9 | const STOP = 90; 10 | 11 | // set up the input 12 | //keypress(process.stdin); 13 | 14 | process.stdin.resume(); 15 | process.stdin.setEncoding('utf8'); 16 | process.stdin.setRawMode(true); 17 | 18 | console.info("Setting up robot. Attempting J5 connect to Arduino") 19 | 20 | const board = new five.Board({ 21 | io: new BleIO() 22 | }); 23 | 24 | /**board.on("ready", function() { 25 | const led = new five.Led(32); 26 | led.blink(500); 27 | const servo = new five.Servo(33); 28 | 29 | servo.sweep([45, 135]); 30 | 31 | //servo.to(20); 32 | });**/ 33 | 34 | board.on("ready", function() { 35 | 36 | console.log("Control the bot with the arrow keys, and SPACE to stop.") 37 | 38 | esc = new five.Servo(25); 39 | esc.to(STOP); 40 | cur_pos = STOP; 41 | const led = five.Led(32); 42 | led.on(); 43 | }); 44 | 45 | board.on("error", function(err) { 46 | console.log(err.message); 47 | process.exit(); 48 | }); 49 | 50 | process.stdin.on('keypress', function(chunk, key) { 51 | // process the keypresses 52 | 53 | if (key) { 54 | switch (key.name) { 55 | case "left": 56 | // motor_r.reverse(speed_setting); 57 | break; 58 | case "right": 59 | // motor_r.forward(speed_setting); 60 | break; 61 | case "up": 62 | console.log("Go faster"); 63 | cur_pos = (cur_pos >= MAX) ? MAX : cur_pos + 1; 64 | break; 65 | case "down": 66 | // motor_r.forward(speed_setting); 67 | console.log("Go slower"); 68 | cur_pos = (cur_pos <= MIN) ? MIN : cur_pos - 1; 69 | break; 70 | case "space": 71 | console.log("stopping"); 72 | esc.to(STOP); 73 | cur_pos = STOP; 74 | break; 75 | case "l": 76 | console.log("LED ON"); 77 | led.on(); 78 | break; 79 | case "o": 80 | console.log("LED OFF"); 81 | led.off(); 82 | break; 83 | case "q": 84 | console.log("Exiting"); 85 | esc.stop(); 86 | process.exit(); 87 | } 88 | 89 | } 90 | console.log("Cur: " + cur_pos); 91 | esc.to(cur_pos); 92 | 93 | }); 94 | -------------------------------------------------------------------------------- /examples/ble.js: -------------------------------------------------------------------------------- 1 | const BleIO = require("ble-io"); 2 | const five = require("johnny-five"); 3 | 4 | var Controller = require("../lib/kb_controller.js"); 5 | 6 | const board = new five.Board({ 7 | io: new BleIO() 8 | }); 9 | 10 | /**board.on("ready", function() { 11 | const led = new five.Led(32); 12 | led.blink(500); 13 | const servo = new five.Servo(33); 14 | 15 | servo.sweep([45, 135]); 16 | 17 | //servo.to(20); 18 | });**/ 19 | 20 | board.on("ready", function() { 21 | 22 | console.log("Control the bot with the arrow keys, and SPACE to stop."); 23 | 24 | const led = five.Led(32); 25 | var controller = new Controller({ 26 | left: new five.Servo.Continuous(25), 27 | right: new five.Servo.Continuous(33), 28 | lstop: 90, // use these to set the stop value of the servo 29 | rstop: 90, 30 | }); 31 | led.on(); 32 | }); 33 | 34 | board.on("error", function(err) { 35 | console.log(err.message); 36 | process.exit(); 37 | }); 38 | 39 | -------------------------------------------------------------------------------- /examples/blink.js: -------------------------------------------------------------------------------- 1 | // 2 | // Use this to test your board 3 | // If it blinks you are good to go. 4 | // 5 | // $ node blink.js 6 | // 7 | 8 | var five = require("johnny-five"); 9 | var board = new five.Board({port: process.argv[2]}); 10 | 11 | board.on("ready", function() { 12 | var led = new five.Led(13); 13 | led.blink(500); 14 | }); 15 | 16 | 17 | // Credit http://johnny-five.io 18 | -------------------------------------------------------------------------------- /examples/calibrate-line.js: -------------------------------------------------------------------------------- 1 | var five = require("johnny-five"); 2 | 3 | var board; 4 | 5 | console.info("Setting up robot. Attempting J5 connect to Arduino") 6 | 7 | board = new five.Board({port: process.argv[2]}); 8 | 9 | board.on("ready", function(err) { 10 | 11 | if (err){ 12 | console.log(err); 13 | return; 14 | } 15 | 16 | console.info("Board connected. Robot set up"); 17 | console.info("Run the sensors back and forth over the line to get a sense"); 18 | console.info("of what values you're seeing"); 19 | var ir = new five.IR.Reflect.Array({ 20 | emitter: 13, 21 | pins: ["A0", "A1"], // any number of pins 22 | freq: 100 23 | }); 24 | 25 | ir.on('data', function() { 26 | console.log( "Raw Values: ", this.raw ); 27 | }); 28 | 29 | }); 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/esc.js: -------------------------------------------------------------------------------- 1 | const five = require("johnny-five"); 2 | const keypress = require("keypress"); 3 | 4 | let esc; 5 | let cur_pos = 90; 6 | const MAX = 130; 7 | const MIN = 75; 8 | const STOP = 90; 9 | 10 | // set up the input 11 | //keypress(process.stdin); 12 | 13 | process.stdin.resume(); 14 | process.stdin.setEncoding('utf8'); 15 | process.stdin.setRawMode(true); 16 | 17 | console.info("Setting up robot. Attempting J5 connect to Arduino") 18 | 19 | const board = new five.Board({port: process.argv[2]}); 20 | 21 | board.on("ready", function() { 22 | 23 | console.log("Control the bot with the arrow keys, and SPACE to stop.") 24 | 25 | esc = new five.Servo(9); 26 | esc.to(STOP); 27 | cur_pos = STOP; 28 | 29 | }); 30 | 31 | board.on("error", function(err) { 32 | console.log(err.message); 33 | process.exit(); 34 | }); 35 | 36 | process.stdin.on('keypress', function(chunk, key) { 37 | // process the keypresses 38 | 39 | if (key) { 40 | switch (key.name) { 41 | case "left": 42 | // motor_r.reverse(speed_setting); 43 | break; 44 | case "right": 45 | // motor_r.forward(speed_setting); 46 | break; 47 | case "up": 48 | console.log("Go faster"); 49 | cur_pos = (cur_pos >= MAX) ? MAX : cur_pos + 1; 50 | break; 51 | case "down": 52 | // motor_r.forward(speed_setting); 53 | console.log("Go slower"); 54 | cur_pos = (cur_pos <= MIN) ? MIN : cur_pos - 1; 55 | break; 56 | case "space": 57 | console.log("stopping"); 58 | esc.to(STOP); 59 | cur_pos = STOP; 60 | break; 61 | case "l": 62 | console.log("LED ON"); 63 | led.on(); 64 | break; 65 | case "o": 66 | console.log("LED OFF"); 67 | led.off(); 68 | break; 69 | case "q": 70 | console.log("Exiting"); 71 | esc.stop(); 72 | process.exit(); 73 | } 74 | 75 | } 76 | console.log("Cur: " + cur_pos); 77 | esc.to(cur_pos); 78 | 79 | }); 80 | -------------------------------------------------------------------------------- /examples/line.js: -------------------------------------------------------------------------------- 1 | var five = require("johnny-five"); 2 | 3 | var board, motor_l, motor_r; 4 | var calibrating = true; 5 | 6 | var speed = 0; 7 | var min_speed = 230; 8 | var max_speed = 255; 9 | var cur_speed_setting = 0.9 10 | 11 | console.info("Setting up robot. Attempting J5 connect to Arduino") 12 | 13 | board = new five.Board({port: process.argv[2]}); 14 | 15 | board.on("ready", function() { 16 | 17 | motor_r = new five.Motor({ 18 | pins: { 19 | pwm: 9, 20 | dir: 8, 21 | }, 22 | invertPWM: true, 23 | }); 24 | 25 | motor_l = new five.Motor({ 26 | pins: { 27 | pwm: 6, 28 | dir: 7, 29 | }, 30 | invertPWM: true, 31 | }); 32 | 33 | var ir = new five.IR.Reflect.Array({ 34 | emitter: 13, 35 | pins: ["A0", "A1"], // any number of pins 36 | freq: 100 37 | }); 38 | 39 | console.info("Board connected. Robot set up"); 40 | console.info("Calibrate the sensors by running them back and forth"); 41 | 42 | ir.calibrateUntil(function() { 43 | return !calibrating; 44 | }); 45 | 46 | setTimeout(function() { 47 | calibrating = false; 48 | console.log("Sensors calibrated, go for it"); 49 | }, 3000); 50 | 51 | ir.on('line', function() { 52 | if (!calibrating) { 53 | console.log( "Line val: ", this.line); 54 | 55 | if (this.line < 100) { 56 | motor_r.stop(); 57 | } else if (this.line > 900) { 58 | motor_l.stop(); 59 | } else { 60 | motor_l.forward(); 61 | motor_r.forward(); 62 | } 63 | } 64 | }); 65 | 66 | console.info("Robot running by default it will be stopped if it's off line"); 67 | }); 68 | 69 | 70 | -------------------------------------------------------------------------------- /examples/motors.js: -------------------------------------------------------------------------------- 1 | const five = require("johnny-five"); 2 | const keypress = require("keypress"); 3 | 4 | var board, motor_l, motor_r; 5 | var led; 6 | 7 | var speed_setting = 255; 8 | 9 | // set up the input 10 | keypress(process.stdin); 11 | 12 | process.stdin.resume(); 13 | process.stdin.setEncoding('utf8'); 14 | process.stdin.setRawMode(true); 15 | 16 | console.info("Setting up robot. Attempting J5 connect to Arduino") 17 | 18 | board = new five.Board({port: process.argv[2]}); 19 | 20 | board.on("ready", function(err) { 21 | 22 | if (err){ 23 | console.log(err); 24 | return; 25 | } 26 | 27 | console.info("Board connected. Robot set up"); 28 | 29 | motor_r = new five.Motor({ 30 | pins: { 31 | pwm: 9, 32 | dir: 8, 33 | }, 34 | invertPWM: true, 35 | }); 36 | 37 | motor_l = new five.Motor({ 38 | pins: { 39 | pwm: 6, 40 | dir: 7, 41 | }, 42 | invertPWM: true, 43 | }); 44 | 45 | led = new five.Led(11); 46 | 47 | console.info("Robot running issue commands to it."); 48 | console.info("LRUD arrows. Space stop. Q to quit"); 49 | 50 | }); 51 | 52 | process.stdin.on('keypress', function(chunk, key) { 53 | 54 | // is board ready? 55 | if (!board.repl.ready) { 56 | return; 57 | } 58 | 59 | // process the keypresses 60 | if (key) { 61 | switch (key.name) { 62 | case "left": 63 | motor_r.reverse(speed_setting); 64 | motor_l.forward(speed_setting); 65 | break; 66 | case "right": 67 | motor_r.forward(speed_setting); 68 | motor_l.reverse(speed_setting); 69 | break; 70 | case "up": 71 | motor_l.reverse(speed_setting); 72 | motor_r.reverse(speed_setting); 73 | break; 74 | case "down": 75 | motor_r.forward(speed_setting); 76 | motor_l.forward(speed_setting); 77 | break; 78 | case "space": 79 | motor_r.stop(); 80 | motor_l.stop(); 81 | break; 82 | case "l": 83 | console.log("LED ON"); 84 | led.on(); 85 | break; 86 | case "o": 87 | console.log("LED OFF"); 88 | led.off(); 89 | break; 90 | case "q": 91 | console.log("Exiting"); 92 | motor_r.stop(); 93 | motor_l.stop(); 94 | process.exit(); 95 | } 96 | } 97 | 98 | }); 99 | 100 | -------------------------------------------------------------------------------- /examples/network_sb.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Controller = require("../lib/kb_controller.js"); 4 | var firmata = require('firmata'); 5 | var five = require("johnny-five"); 6 | var readline = require("readline"); 7 | var VirtualSerialPort = require('udp-serial').SerialPort; 8 | 9 | //create the udp serialport and specify the host and port to connect to 10 | var sp = new VirtualSerialPort({ 11 | host: '192.168.4.1', 12 | type: 'udp4', 13 | port: 1025 14 | }); 15 | 16 | //use the serial port to send a command to a remote firmata(arduino) device 17 | var io = new firmata.Board(sp); 18 | io.once('ready', function(){ 19 | console.log('IO Ready'); 20 | io.isReady = true; 21 | 22 | var board = new five.Board({io: io, repl: true}); 23 | 24 | board.on('ready', function(){ 25 | console.log('five ready'); 26 | 27 | var controller = new Controller({ 28 | left: new five.Servo.Continuous(9), 29 | right: new five.Servo.Continuous(8), 30 | lstop: 90, // use these to set the stop value of the servo 31 | rstop: 90, 32 | }); 33 | }); 34 | }); 35 | 36 | -------------------------------------------------------------------------------- /examples/parking.js: -------------------------------------------------------------------------------- 1 | // Demos use of the ping sensor attached to the piezo as both a sensor 2 | // with an actuator 3 | // 4 | var five = require("johnny-five"), 5 | board = new five.Board(); 6 | 7 | board.on("ready", function() { 8 | 9 | //Create new Ping and show distance on change 10 | var ping = new five.Proximity({ 11 | pin: 7, 12 | freq: 200, 13 | controller: "HCSR04" 14 | }); 15 | 16 | var piezo = new five.Piezo(11); // leostick piezo 17 | 18 | var intervalID = 0; 19 | 20 | ping.on("change", function( err, value ) { 21 | 22 | console.log('Object is ' + this.cm + ' cm away'); 23 | // now we do a callback on the interval of the centimetres thus 24 | // shorter centimetres means less interval before calling the tone command 25 | clearInterval(intervalID); 26 | if (this.cm > 4) { // this is arbitrary to stop the conflicts with tone. 27 | intervalID = setInterval(function() { 28 | piezo.tone("e", "1"); 29 | }, Math.floor(this.cm)); 30 | } 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /examples/sb-controller.js: -------------------------------------------------------------------------------- 1 | // ======================= 2 | // Build off the basic simplebot base but now with a dualshock controller 3 | // interface 4 | // 5 | // Note dependency: npm install dualshock-controller 6 | // ======================= 7 | 8 | var five = require("johnny-five"); 9 | var dualshock = require("dualshock-controller"); 10 | 11 | var STOPVAL = 90; 12 | var RSTOPVAL = 88; 13 | var LSTOPVAL = 89; 14 | 15 | var port = process.argv[2] || ""; 16 | 17 | var opts = {}; 18 | 19 | if (port != "") { 20 | opts.port = port; 21 | } 22 | 23 | var controller = dualshock({ 24 | config: "dualshock3", 25 | analogStickSmoothing: true, 26 | }); 27 | 28 | 29 | var board = new five.Board(opts); 30 | //var board = new five.Board({port: "/dev/tty.FireFly-AF8A-SPP" }); 31 | 32 | board.on("ready", function() { 33 | 34 | console.log("Welcome to SimpleBot with PS3 Controller!") 35 | console.log("Control the bot with the left analog stick for throttle and reverse"); 36 | console.log("Right analog stick goes left and right"); 37 | console.log("Start button to quit"); 38 | 39 | var led = new five.Led(5); 40 | var left_wheel = new five.Servo({ pin: 9, type: 'continuous' }).to(LSTOPVAL); 41 | var right_wheel = new five.Servo({ pin: 10, type: 'continuous' }).to(RSTOPVAL); 42 | 43 | var accel = 0; // neutral 44 | var turn = 0; // neutral 45 | 46 | controller.on("start:release", function(data) { 47 | // set quit. 48 | left_wheel.to(LSTOPVAL); 49 | right_wheel.to(RSTOPVAL); 50 | console.log("Qutting"); 51 | process.exit(); 52 | }); 53 | 54 | controller.on("left:move", function(data) { 55 | // this is the throttle with 0 being full forward 56 | // 255 being full backwards and about 127 being much in the middle. 57 | if (data.y < 96) { 58 | accel = 1; 59 | } else if (data.y < 160) { 60 | accel = 0; 61 | } else { 62 | accel = -1; 63 | } 64 | }); 65 | 66 | controller.on("right:move", function(data) { 67 | // this is the turn with 0 being full left turn and 255 full right. 68 | 69 | if (data.x < 96) { 70 | turn = -1; 71 | } else if (data.x < 160) { 72 | turn = 0; 73 | } else { 74 | turn = 1; 75 | } 76 | }); 77 | 78 | 79 | // main loop that controls the vehicle. 80 | setInterval(function() { 81 | 82 | if (accel == 0 ) { 83 | left_wheel.to(LSTOPVAL); 84 | right_wheel.to(RSTOPVAL); 85 | return; 86 | } 87 | 88 | if (accel > 0) { 89 | // we're driving forward. 90 | if (turn < 0) { 91 | // turn left driving forward; 92 | left_wheel.cw(); 93 | right_wheel.cw(); 94 | } else if (turn > 0) { 95 | // turn right driving forward 96 | left_wheel.ccw(); 97 | right_wheel.ccw(); 98 | } else { 99 | // drive forward 100 | left_wheel.ccw(); 101 | right_wheel.cw(); 102 | } 103 | } else { 104 | 105 | if (turn < 0) { 106 | // turn left driving backward; 107 | left_wheel.ccw(); 108 | right_wheel.ccw(); 109 | } else if (turn > 0) { 110 | // turn right driving backward 111 | left_wheel.cw(); 112 | right_wheel.cw(); 113 | } else { 114 | // drive backwards 115 | left_wheel.cw(); 116 | right_wheel.ccw(); 117 | } 118 | } 119 | 120 | }, 50); 121 | 122 | 123 | var key = {"name": "yada"}; 124 | 125 | if ( key.name == 'q' ) { 126 | 127 | console.log('Quitting'); 128 | process.exit(); 129 | 130 | } else if ( key.name == 'up' ) { 131 | 132 | console.log('Forward'); 133 | left_wheel.ccw(); 134 | right_wheel.cw(); 135 | 136 | } else if ( key.name == 'down' ) { 137 | 138 | console.log('Backward'); 139 | left_wheel.cw(); 140 | right_wheel.ccw(); 141 | 142 | } else if ( key.name == 'left' ) { 143 | 144 | console.log('Left'); 145 | left_wheel.cw(); 146 | right_wheel.cw(); 147 | 148 | } else if ( key.name == 'right' ) { 149 | 150 | console.log('Right'); 151 | left_wheel.ccw(); 152 | right_wheel.ccw(); 153 | 154 | } else if ( key.name == 'space' ) { 155 | 156 | console.log('Stopping'); 157 | left_wheel.to(LSTOPVAL); 158 | right_wheel.to(RSTOPVAL); 159 | 160 | } else if (key.name == "o") { 161 | console.log("on"); 162 | led.on(); 163 | } else if (key.name == "f") { 164 | console.log("off"); 165 | led.off(); 166 | } else if (key.name == "s") { 167 | console.log("blink"); 168 | led.strobe(2000); 169 | } 170 | }); 171 | 172 | board.on("error", function(err) { 173 | console.log(err.message); 174 | process.exit(); 175 | }); 176 | 177 | -------------------------------------------------------------------------------- /examples/servos.js: -------------------------------------------------------------------------------- 1 | var five = require("johnny-five"); 2 | var Controller = require("../lib/kb_controller.js"); 3 | 4 | var opts = {}; 5 | opts.port = process.argv[2] || ""; 6 | 7 | var board = new five.Board(opts); 8 | 9 | board.on("ready", function() { 10 | 11 | console.log("Control the bot with the arrow keys, and SPACE to stop.") 12 | 13 | var controller = new Controller({ 14 | left: new five.Servo.Continuous(9), 15 | right: new five.Servo.Continuous(8), 16 | lstop: 90, // use these to set the stop value of the servo 17 | rstop: 90, 18 | }); 19 | }); 20 | 21 | board.on("error", function(err) { 22 | console.log(err.message); 23 | process.exit(); 24 | }); 25 | 26 | //************** 27 | // With acknowledgement to the awesome work done by @makenai on SumoBot Jr 28 | // code that started the idea of this originally 29 | // ******/ 30 | -------------------------------------------------------------------------------- /examples/snes-controller.js: -------------------------------------------------------------------------------- 1 | // ======================= 2 | // Build off the basic simplebot base but now with a USB SNES gamepad controller 3 | // 4 | // http://www.ebay.com.au/itm/Retro-SNES-USB-Wired-Classic-Controller-GamePad-for-Windows-PC-Color-/261348030489 5 | // 6 | // Note dependency: npm install node-gamepad 7 | // 8 | // Note also: you may need to update the 'vendorID' and 'productID' below to match your controller. 9 | // You should find your device listed under Windows > 'Control Panel' > 'Device Manager' > 'Human Interface Devices' 10 | // Refer to the screenshot attached 'snes-controller.png' for more details. 11 | // ======================= 12 | 13 | const five = require("johnny-five"); 14 | const Gamepad = require("node-gamepad"); 15 | const gamepad = new Gamepad('snes/retrolink', { vendorID: 0x0810, productID: 0xE501 }).connect(); 16 | const buttons = ['up', 'down', 'left', 'right', 'x', 'y', 'a', 'b', 'l', 'r']; 17 | const port = process.argv[2] || ""; 18 | 19 | let controller = {}; 20 | 21 | buttons.forEach(btn => gamepad.on(btn + ':press', () => handle(btn, 'press'))); 22 | buttons.forEach(btn => gamepad.on(btn + ':release', () => handle(btn, 'release'))); 23 | 24 | function handle(button, action) { 25 | console.log(`${button}:${action}`); 26 | switch(action) { 27 | case 'press': 28 | return controller[button] && controller[button](); 29 | case 'release': 30 | return controller.stop && controller.stop(); 31 | } 32 | } 33 | 34 | let board = new five.Board({ port }); 35 | 36 | board.on("ready", () => { 37 | 38 | let motor_r = new five.Motor({ 39 | pins: { pwm: 9, dir: 8 }, 40 | invertPWM: true, 41 | }); 42 | 43 | let motor_l = new five.Motor({ 44 | pins: { pwm: 6, dir: 7 }, 45 | invertPWM: true, 46 | }); 47 | 48 | let piezo = new five.Piezo(10); 49 | 50 | controller.up = () => { 51 | motor_l.forward(250); 52 | motor_r.forward(250); 53 | }; 54 | controller.down = () => { 55 | motor_l.reverse(250); 56 | motor_r.reverse(250); 57 | }; 58 | controller.left = () => { 59 | motor_l.forward(250); 60 | }; 61 | controller.right = () => { 62 | motor_r.forward(250); 63 | }; 64 | controller.l = () => { 65 | motor_l.forward(250); 66 | motor_r.reverse(250); 67 | }; 68 | controller.r = () => { 69 | motor_l.reverse(250); 70 | motor_r.forward(250); 71 | }; 72 | controller.b = () => { 73 | piezo.play({ 74 | // Old Macdonald 75 | song: "- C4 - C4 - C4 - G3 - A3 - A3 - G3 G3 - E4 - E4 - D4 - D4 - C4 C4 - - - -", 76 | beats: 1/4, 77 | tempo: 100 78 | }); 79 | }; 80 | controller.a = () => { 81 | piezo.play({ 82 | // Yankee doodle 83 | song: "- C4 C4 D4 E4 C4 E4 D4 - G3 C4 C4 D4 E4 C4 - B3 -", 84 | beats: 1/2, 85 | tempo: 200 86 | }); 87 | }; 88 | controller.y = () => { 89 | piezo.play({ 90 | // http://johnny-five.io/api/piezo/ 91 | song: "C D F D A - A A A A G G G G - - C D F D G - G G G G F F F F - -", 92 | beats: 1 / 4, 93 | tempo: 100 94 | }); 95 | }; 96 | controller.stop = () => { 97 | motor_l.stop(); 98 | motor_r.stop(); 99 | piezo.off(); 100 | }; 101 | 102 | }); 103 | -------------------------------------------------------------------------------- /examples/snes-controller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/examples/snes-controller.png -------------------------------------------------------------------------------- /examples/test_servos.js: -------------------------------------------------------------------------------- 1 | // Tests whether your servos are going the right way and all working 2 | // properly or not. Assumes that the left servo is on pin 9 and the right 3 | // wheel is on pin 8. 4 | // 5 | // call as: 6 | // node examples/test_servos.js PORT 7 | 8 | var five = require("johnny-five"); 9 | var temporal = require("temporal"); 10 | 11 | var opts = {}; 12 | opts.port = process.argv[2] || ""; 13 | 14 | var board = new five.Board(opts); 15 | 16 | board.on("ready", function() { 17 | 18 | console.log("This is a servo tester to see if everything is running properly"); 19 | console.log("Servos should run forward for 3s, stop for 3s, reverse 3s and stop"); 20 | 21 | var left_wheel = new five.Servo({ pin: 9, type: 'continuous' }); 22 | var right_wheel = new five.Servo({ pin: 8, type: 'continuous' }); 23 | 24 | temporal.queue([ 25 | { 26 | delay: 5000, 27 | task: function() { 28 | console.log("going forward"); 29 | left_wheel.cw(); 30 | right_wheel.ccw(); 31 | }, 32 | }, 33 | { 34 | delay: 3000, 35 | task: function() { 36 | console.log("stopping"); 37 | left_wheel.stop(); 38 | right_wheel.stop(); 39 | }, 40 | }, 41 | { 42 | delay: 3000, 43 | task: function() { 44 | console.log("going backward"); 45 | left_wheel.ccw(); 46 | right_wheel.cw(); 47 | }, 48 | }, 49 | { 50 | delay: 3000, 51 | task: function() { 52 | console.log("stopping"); 53 | left_wheel.stop(); 54 | right_wheel.stop(); 55 | }, 56 | }, 57 | { 58 | delay: 1500, 59 | task: function() { 60 | console.log("Test complete. Exiting."); 61 | process.exit(); 62 | }, 63 | }, 64 | ]); 65 | 66 | }); 67 | 68 | 69 | -------------------------------------------------------------------------------- /examples/wiring/basic_wiring.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/examples/wiring/basic_wiring.fzz -------------------------------------------------------------------------------- /examples/wiring/basic_wiring_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/examples/wiring/basic_wiring_bb.png -------------------------------------------------------------------------------- /examples/wiring/basic_wiring_schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/examples/wiring/basic_wiring_schematic.png -------------------------------------------------------------------------------- /firmware/build/esp8266/0x00000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/firmware/build/esp8266/0x00000.bin -------------------------------------------------------------------------------- /firmware/build/esp8266/0x40000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/firmware/build/esp8266/0x40000.bin -------------------------------------------------------------------------------- /firmware/build/network/simplebot_firmata/Firmata.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.cpp - Firmata library v2.5.3 - 2016-06-18 3 | Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | See file LICENSE.txt for further informations on licensing terms. 12 | */ 13 | 14 | //****************************************************************************** 15 | //* Includes 16 | //****************************************************************************** 17 | 18 | #include "Firmata.h" 19 | #include "HardwareSerial.h" 20 | 21 | extern "C" { 22 | #include 23 | #include 24 | } 25 | 26 | //****************************************************************************** 27 | //* Support Functions 28 | //****************************************************************************** 29 | 30 | /** 31 | * Split a 16-bit byte into two 7-bit values and write each value. 32 | * @param value The 16-bit value to be split and written separately. 33 | */ 34 | void FirmataClass::sendValueAsTwo7bitBytes(int value) 35 | { 36 | FirmataStream->write(value & 0x7F); // LSB 37 | FirmataStream->write(value >> 7 & 0x7F); // MSB 38 | } 39 | 40 | /** 41 | * A helper method to write the beginning of a Sysex message transmission. 42 | */ 43 | void FirmataClass::startSysex(void) 44 | { 45 | FirmataStream->write(START_SYSEX); 46 | } 47 | 48 | /** 49 | * A helper method to write the end of a Sysex message transmission. 50 | */ 51 | void FirmataClass::endSysex(void) 52 | { 53 | FirmataStream->write(END_SYSEX); 54 | } 55 | 56 | //****************************************************************************** 57 | //* Constructors 58 | //****************************************************************************** 59 | 60 | /** 61 | * The Firmata class. 62 | * An instance named "Firmata" is created automatically for the user. 63 | */ 64 | FirmataClass::FirmataClass() 65 | { 66 | firmwareVersionCount = 0; 67 | firmwareVersionVector = 0; 68 | systemReset(); 69 | } 70 | 71 | //****************************************************************************** 72 | //* Public Methods 73 | //****************************************************************************** 74 | 75 | /** 76 | * Initialize the default Serial transport at the default baud of 57600. 77 | */ 78 | void FirmataClass::begin(void) 79 | { 80 | begin(57600); 81 | } 82 | 83 | /** 84 | * Initialize the default Serial transport and override the default baud. 85 | * Sends the protocol version to the host application followed by the firmware version and name. 86 | * blinkVersion is also called. To skip the call to blinkVersion, call Firmata.disableBlinkVersion() 87 | * before calling Firmata.begin(baud). 88 | * @param speed The baud to use. 57600 baud is the default value. 89 | */ 90 | void FirmataClass::begin(long speed) 91 | { 92 | Serial.begin(speed); 93 | FirmataStream = &Serial; 94 | blinkVersion(); 95 | printVersion(); // send the protocol version 96 | printFirmwareVersion(); // send the firmware name and version 97 | } 98 | 99 | /** 100 | * Reassign the Firmata stream transport. 101 | * @param s A reference to the Stream transport object. This can be any type of 102 | * transport that implements the Stream interface. Some examples include Ethernet, WiFi 103 | * and other UARTs on the board (Serial1, Serial2, etc). 104 | */ 105 | void FirmataClass::begin(Stream &s) 106 | { 107 | FirmataStream = &s; 108 | // do not call blinkVersion() here because some hardware such as the 109 | // Ethernet shield use pin 13 110 | printVersion(); 111 | printFirmwareVersion(); 112 | } 113 | 114 | /** 115 | * Send the Firmata protocol version to the Firmata host application. 116 | */ 117 | void FirmataClass::printVersion(void) 118 | { 119 | FirmataStream->write(REPORT_VERSION); 120 | FirmataStream->write(FIRMATA_PROTOCOL_MAJOR_VERSION); 121 | FirmataStream->write(FIRMATA_PROTOCOL_MINOR_VERSION); 122 | } 123 | 124 | /** 125 | * Blink the Firmata protocol version to the onboard LEDs (if the board has an onboard LED). 126 | * If VERSION_BLINK_PIN is not defined in Boards.h for a particular board, then this method 127 | * does nothing. 128 | * The first series of flashes indicates the firmware major version (2 flashes = 2). 129 | * The second series of flashes indicates the firmware minor version (5 flashes = 5). 130 | */ 131 | void FirmataClass::blinkVersion(void) 132 | { 133 | #if defined(VERSION_BLINK_PIN) 134 | if (blinkVersionDisabled) return; 135 | // flash the pin with the protocol version 136 | pinMode(VERSION_BLINK_PIN, OUTPUT); 137 | strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MAJOR_VERSION, 40, 210); 138 | delay(250); 139 | strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MINOR_VERSION, 40, 210); 140 | delay(125); 141 | #endif 142 | } 143 | 144 | /** 145 | * Provides a means to disable the version blink sequence on the onboard LED, trimming startup 146 | * time by a couple of seconds. 147 | * Call this before Firmata.begin(). It only applies when using the default Serial transport. 148 | */ 149 | void FirmataClass::disableBlinkVersion() 150 | { 151 | blinkVersionDisabled = true; 152 | } 153 | 154 | /** 155 | * Sends the firmware name and version to the Firmata host application. The major and minor version 156 | * numbers are the first 2 bytes in the message. The following bytes are the characters of the 157 | * firmware name. 158 | */ 159 | void FirmataClass::printFirmwareVersion(void) 160 | { 161 | byte i; 162 | 163 | if (firmwareVersionCount) { // make sure that the name has been set before reporting 164 | startSysex(); 165 | FirmataStream->write(REPORT_FIRMWARE); 166 | FirmataStream->write(firmwareVersionVector[0]); // major version number 167 | FirmataStream->write(firmwareVersionVector[1]); // minor version number 168 | for (i = 2; i < firmwareVersionCount; ++i) { 169 | sendValueAsTwo7bitBytes(firmwareVersionVector[i]); 170 | } 171 | endSysex(); 172 | } 173 | } 174 | 175 | /** 176 | * Sets the name and version of the firmware. This is not the same version as the Firmata protocol 177 | * (although at times the firmware version and protocol version may be the same number). 178 | * @param name A pointer to the name char array 179 | * @param major The major version number 180 | * @param minor The minor version number 181 | */ 182 | void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) 183 | { 184 | const char *firmwareName; 185 | const char *extension; 186 | 187 | // parse out ".cpp" and "applet/" that comes from using __FILE__ 188 | extension = strstr(name, ".cpp"); 189 | firmwareName = strrchr(name, '/'); 190 | 191 | if (!firmwareName) { 192 | // windows 193 | firmwareName = strrchr(name, '\\'); 194 | } 195 | if (!firmwareName) { 196 | // user passed firmware name 197 | firmwareName = name; 198 | } else { 199 | firmwareName ++; 200 | } 201 | 202 | if (!extension) { 203 | firmwareVersionCount = strlen(firmwareName) + 2; 204 | } else { 205 | firmwareVersionCount = extension - firmwareName + 2; 206 | } 207 | 208 | // in case anyone calls setFirmwareNameAndVersion more than once 209 | free(firmwareVersionVector); 210 | 211 | firmwareVersionVector = (byte *) malloc(firmwareVersionCount + 1); 212 | firmwareVersionVector[firmwareVersionCount] = 0; 213 | firmwareVersionVector[0] = major; 214 | firmwareVersionVector[1] = minor; 215 | strncpy((char *)firmwareVersionVector + 2, firmwareName, firmwareVersionCount - 2); 216 | } 217 | 218 | //------------------------------------------------------------------------------ 219 | // Serial Receive Handling 220 | 221 | /** 222 | * A wrapper for Stream::available() 223 | * @return The number of bytes remaining in the input stream buffer. 224 | */ 225 | int FirmataClass::available(void) 226 | { 227 | return FirmataStream->available(); 228 | } 229 | 230 | /** 231 | * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. 232 | * Calls callback function for STRING_DATA and all other sysex messages. 233 | * @private 234 | */ 235 | void FirmataClass::processSysexMessage(void) 236 | { 237 | switch (storedInputData[0]) { //first byte in buffer is command 238 | case REPORT_FIRMWARE: 239 | printFirmwareVersion(); 240 | break; 241 | case STRING_DATA: 242 | if (currentStringCallback) { 243 | byte bufferLength = (sysexBytesRead - 1) / 2; 244 | byte i = 1; 245 | byte j = 0; 246 | while (j < bufferLength) { 247 | // The string length will only be at most half the size of the 248 | // stored input buffer so we can decode the string within the buffer. 249 | storedInputData[j] = storedInputData[i]; 250 | i++; 251 | storedInputData[j] += (storedInputData[i] << 7); 252 | i++; 253 | j++; 254 | } 255 | // Make sure string is null terminated. This may be the case for data 256 | // coming from client libraries in languages that don't null terminate 257 | // strings. 258 | if (storedInputData[j - 1] != '\0') { 259 | storedInputData[j] = '\0'; 260 | } 261 | (*currentStringCallback)((char *)&storedInputData[0]); 262 | } 263 | break; 264 | default: 265 | if (currentSysexCallback) 266 | (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); 267 | } 268 | } 269 | 270 | /** 271 | * Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte) 272 | */ 273 | void FirmataClass::processInput(void) 274 | { 275 | int inputData = FirmataStream->read(); // this is 'int' to handle -1 when no data 276 | if (inputData != -1) { 277 | parse(inputData); 278 | } 279 | } 280 | 281 | /** 282 | * Parse data from the input stream. 283 | * @param inputData A single byte to be added to the parser. 284 | */ 285 | void FirmataClass::parse(byte inputData) 286 | { 287 | int command; 288 | 289 | if (parsingSysex) { 290 | if (inputData == END_SYSEX) { 291 | //stop sysex byte 292 | parsingSysex = false; 293 | //fire off handler function 294 | processSysexMessage(); 295 | } else { 296 | //normal data byte - add to buffer 297 | storedInputData[sysexBytesRead] = inputData; 298 | sysexBytesRead++; 299 | } 300 | } else if ( (waitForData > 0) && (inputData < 128) ) { 301 | waitForData--; 302 | storedInputData[waitForData] = inputData; 303 | if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message 304 | switch (executeMultiByteCommand) { 305 | case ANALOG_MESSAGE: 306 | if (currentAnalogCallback) { 307 | (*currentAnalogCallback)(multiByteChannel, 308 | (storedInputData[0] << 7) 309 | + storedInputData[1]); 310 | } 311 | break; 312 | case DIGITAL_MESSAGE: 313 | if (currentDigitalCallback) { 314 | (*currentDigitalCallback)(multiByteChannel, 315 | (storedInputData[0] << 7) 316 | + storedInputData[1]); 317 | } 318 | break; 319 | case SET_PIN_MODE: 320 | if (currentPinModeCallback) 321 | (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); 322 | break; 323 | case SET_DIGITAL_PIN_VALUE: 324 | if (currentPinValueCallback) 325 | (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); 326 | break; 327 | case REPORT_ANALOG: 328 | if (currentReportAnalogCallback) 329 | (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); 330 | break; 331 | case REPORT_DIGITAL: 332 | if (currentReportDigitalCallback) 333 | (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); 334 | break; 335 | } 336 | executeMultiByteCommand = 0; 337 | } 338 | } else { 339 | // remove channel info from command byte if less than 0xF0 340 | if (inputData < 0xF0) { 341 | command = inputData & 0xF0; 342 | multiByteChannel = inputData & 0x0F; 343 | } else { 344 | command = inputData; 345 | // commands in the 0xF* range don't use channel data 346 | } 347 | switch (command) { 348 | case ANALOG_MESSAGE: 349 | case DIGITAL_MESSAGE: 350 | case SET_PIN_MODE: 351 | case SET_DIGITAL_PIN_VALUE: 352 | waitForData = 2; // two data bytes needed 353 | executeMultiByteCommand = command; 354 | break; 355 | case REPORT_ANALOG: 356 | case REPORT_DIGITAL: 357 | waitForData = 1; // one data byte needed 358 | executeMultiByteCommand = command; 359 | break; 360 | case START_SYSEX: 361 | parsingSysex = true; 362 | sysexBytesRead = 0; 363 | break; 364 | case SYSTEM_RESET: 365 | systemReset(); 366 | break; 367 | case REPORT_VERSION: 368 | Firmata.printVersion(); 369 | break; 370 | } 371 | } 372 | } 373 | 374 | /** 375 | * @return Returns true if the parser is actively parsing data. 376 | */ 377 | boolean FirmataClass::isParsingMessage(void) 378 | { 379 | return (waitForData > 0 || parsingSysex); 380 | } 381 | 382 | //------------------------------------------------------------------------------ 383 | // Output Stream Handling 384 | 385 | /** 386 | * Send an analog message to the Firmata host application. The range of pins is limited to [0..15] 387 | * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits 388 | * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG 389 | * message. 390 | * @param pin The analog pin to send the value of (limited to pins 0 - 15). 391 | * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). 392 | * The maximum value is 14-bits (16384). 393 | */ 394 | void FirmataClass::sendAnalog(byte pin, int value) 395 | { 396 | // pin can only be 0-15, so chop higher bits 397 | FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); 398 | sendValueAsTwo7bitBytes(value); 399 | } 400 | 401 | /* (intentionally left out asterix here) 402 | * STUB - NOT IMPLEMENTED 403 | * Send a single digital pin value to the Firmata host application. 404 | * @param pin The digital pin to send the value of. 405 | * @param value The value of the pin. 406 | */ 407 | void FirmataClass::sendDigital(byte pin, int value) 408 | { 409 | /* TODO add single pin digital messages to the protocol, this needs to 410 | * track the last digital data sent so that it can be sure to change just 411 | * one bit in the packet. This is complicated by the fact that the 412 | * numbering of the pins will probably differ on Arduino, Wiring, and 413 | * other boards. 414 | */ 415 | 416 | // TODO: the digital message should not be sent on the serial port every 417 | // time sendDigital() is called. Instead, it should add it to an int 418 | // which will be sent on a schedule. If a pin changes more than once 419 | // before the digital message is sent on the serial port, it should send a 420 | // digital message for each change. 421 | 422 | // if(value == 0) 423 | // sendDigitalPortPair(); 424 | } 425 | 426 | 427 | /** 428 | * Send an 8-bit port in a single digital message (protocol v2 and later). 429 | * Send 14-bits in a single digital message (protocol v1). 430 | * @param portNumber The port number to send. Note that this is not the same as a "port" on the 431 | * physical microcontroller. Ports are defined in order per every 8 pins in ascending order 432 | * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. 433 | * @param portData The value of the port. The value of each pin in the port is represented by a bit. 434 | */ 435 | void FirmataClass::sendDigitalPort(byte portNumber, int portData) 436 | { 437 | FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); 438 | FirmataStream->write((byte)portData % 128); // Tx bits 0-6 (protocol v1 and higher) 439 | FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) 440 | } 441 | 442 | /** 443 | * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes 444 | * (this is not always the case so this function is not always used to send sysex messages). 445 | * @param command The sysex command byte. 446 | * @param bytec The number of data bytes in the message (excludes start, command and end bytes). 447 | * @param bytev A pointer to the array of data bytes to send in the message. 448 | */ 449 | void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) 450 | { 451 | byte i; 452 | startSysex(); 453 | FirmataStream->write(command); 454 | for (i = 0; i < bytec; i++) { 455 | sendValueAsTwo7bitBytes(bytev[i]); 456 | } 457 | endSysex(); 458 | } 459 | 460 | /** 461 | * Send a string to the Firmata host application. 462 | * @param command Must be STRING_DATA 463 | * @param string A pointer to the char string 464 | */ 465 | void FirmataClass::sendString(byte command, const char *string) 466 | { 467 | if (command == STRING_DATA) { 468 | sendSysex(command, strlen(string), (byte *)string); 469 | } 470 | } 471 | 472 | /** 473 | * Send a string to the Firmata host application. 474 | * @param string A pointer to the char string 475 | */ 476 | void FirmataClass::sendString(const char *string) 477 | { 478 | sendString(STRING_DATA, string); 479 | } 480 | 481 | /** 482 | * A wrapper for Stream::available(). 483 | * Write a single byte to the output stream. 484 | * @param c The byte to be written. 485 | */ 486 | void FirmataClass::write(byte c) 487 | { 488 | FirmataStream->write(c); 489 | } 490 | 491 | /** 492 | * Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, 493 | * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). 494 | * @param command The ID of the command to attach a callback function to. 495 | * @param newFunction A reference to the callback function to attach. 496 | */ 497 | void FirmataClass::attach(byte command, callbackFunction newFunction) 498 | { 499 | switch (command) { 500 | case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; 501 | case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; 502 | case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; 503 | case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; 504 | case SET_PIN_MODE: currentPinModeCallback = newFunction; break; 505 | case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; 506 | } 507 | } 508 | 509 | /** 510 | * Attach a callback function for the SYSTEM_RESET command. 511 | * @param command Must be set to SYSTEM_RESET or it will be ignored. 512 | * @param newFunction A reference to the system reset callback function to attach. 513 | */ 514 | void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) 515 | { 516 | switch (command) { 517 | case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; 518 | } 519 | } 520 | 521 | /** 522 | * Attach a callback function for the STRING_DATA command. 523 | * @param command Must be set to STRING_DATA or it will be ignored. 524 | * @param newFunction A reference to the string callback function to attach. 525 | */ 526 | void FirmataClass::attach(byte command, stringCallbackFunction newFunction) 527 | { 528 | switch (command) { 529 | case STRING_DATA: currentStringCallback = newFunction; break; 530 | } 531 | } 532 | 533 | /** 534 | * Attach a generic sysex callback function to sysex command. 535 | * @param command The ID of the command to attach a callback function to. 536 | * @param newFunction A reference to the sysex callback function to attach. 537 | */ 538 | void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) 539 | { 540 | currentSysexCallback = newFunction; 541 | } 542 | 543 | /** 544 | * Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, 545 | * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). 546 | * @param command The ID of the command to detatch the callback function from. 547 | */ 548 | void FirmataClass::detach(byte command) 549 | { 550 | switch (command) { 551 | case SYSTEM_RESET: currentSystemResetCallback = NULL; break; 552 | case STRING_DATA: currentStringCallback = NULL; break; 553 | case START_SYSEX: currentSysexCallback = NULL; break; 554 | default: 555 | attach(command, (callbackFunction)NULL); 556 | } 557 | } 558 | 559 | /** 560 | * @param pin The pin to get the configuration of. 561 | * @return The configuration of the specified pin. 562 | */ 563 | byte FirmataClass::getPinMode(byte pin) 564 | { 565 | return pinConfig[pin]; 566 | } 567 | 568 | /** 569 | * Set the pin mode/configuration. The pin configuration (or mode) in Firmata represents the 570 | * current function of the pin. Examples are digital input or output, analog input, pwm, i2c, 571 | * serial (uart), etc. 572 | * @param pin The pin to configure. 573 | * @param config The configuration value for the specified pin. 574 | */ 575 | void FirmataClass::setPinMode(byte pin, byte config) 576 | { 577 | if (pinConfig[pin] == PIN_MODE_IGNORE) 578 | return; 579 | 580 | pinConfig[pin] = config; 581 | } 582 | 583 | /** 584 | * @param pin The pin to get the state of. 585 | * @return The state of the specified pin. 586 | */ 587 | int FirmataClass::getPinState(byte pin) 588 | { 589 | return pinState[pin]; 590 | } 591 | 592 | /** 593 | * Set the pin state. The pin state of an output pin is the pin value. The state of an 594 | * input pin is 0, unless the pin has it's internal pull up resistor enabled, then the value is 1. 595 | * @param pin The pin to set the state of 596 | * @param state Set the state of the specified pin 597 | */ 598 | void FirmataClass::setPinState(byte pin, int state) 599 | { 600 | pinState[pin] = state; 601 | } 602 | 603 | // sysex callbacks 604 | /* 605 | * this is too complicated for analogReceive, but maybe for Sysex? 606 | void FirmataClass::attachSysex(sysexFunction newFunction) 607 | { 608 | byte i; 609 | byte tmpCount = analogReceiveFunctionCount; 610 | analogReceiveFunction* tmpArray = analogReceiveFunctionArray; 611 | analogReceiveFunctionCount++; 612 | analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction)); 613 | for(i = 0; i < tmpCount; i++) { 614 | analogReceiveFunctionArray[i] = tmpArray[i]; 615 | } 616 | analogReceiveFunctionArray[tmpCount] = newFunction; 617 | free(tmpArray); 618 | } 619 | */ 620 | 621 | //****************************************************************************** 622 | //* Private Methods 623 | //****************************************************************************** 624 | 625 | /** 626 | * Resets the system state upon a SYSTEM_RESET message from the host software. 627 | * @private 628 | */ 629 | void FirmataClass::systemReset(void) 630 | { 631 | byte i; 632 | 633 | waitForData = 0; // this flag says the next serial input will be data 634 | executeMultiByteCommand = 0; // execute this after getting multi-byte data 635 | multiByteChannel = 0; // channel data for multiByteCommands 636 | 637 | for (i = 0; i < MAX_DATA_BYTES; i++) { 638 | storedInputData[i] = 0; 639 | } 640 | 641 | parsingSysex = false; 642 | sysexBytesRead = 0; 643 | 644 | if (currentSystemResetCallback) 645 | (*currentSystemResetCallback)(); 646 | } 647 | 648 | /** 649 | * Flashing the pin for the version number 650 | * @private 651 | * @param pin The pin the LED is attached to. 652 | * @param count The number of times to flash the LED. 653 | * @param onInterval The number of milliseconds for the LED to be ON during each interval. 654 | * @param offInterval The number of milliseconds for the LED to be OFF during each interval. 655 | */ 656 | void FirmataClass::strobeBlinkPin(byte pin, int count, int onInterval, int offInterval) 657 | { 658 | byte i; 659 | for (i = 0; i < count; i++) { 660 | delay(offInterval); 661 | digitalWrite(pin, HIGH); 662 | delay(onInterval); 663 | digitalWrite(pin, LOW); 664 | } 665 | } 666 | 667 | // make one instance for the user to use 668 | FirmataClass Firmata; 669 | -------------------------------------------------------------------------------- /firmware/build/network/simplebot_firmata/Firmata.h: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.h - Firmata library v2.5.3 - 2016-06-18 3 | Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | See file LICENSE.txt for further informations on licensing terms. 12 | */ 13 | 14 | #ifndef Firmata_h 15 | #define Firmata_h 16 | 17 | #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ 18 | 19 | /* Version numbers for the protocol. The protocol is still changing, so these 20 | * version numbers are important. 21 | * Query using the REPORT_VERSION message. 22 | */ 23 | #define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes 24 | #define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes 25 | #define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases 26 | 27 | /* Version numbers for the Firmata library. 28 | * The firmware version will not always equal the protocol version going forward. 29 | * Query using the REPORT_FIRMWARE message. 30 | */ 31 | #define FIRMATA_FIRMWARE_MAJOR_VERSION 2 32 | #define FIRMATA_FIRMWARE_MINOR_VERSION 5 33 | #define FIRMATA_FIRMWARE_BUGFIX_VERSION 3 34 | 35 | /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for 36 | * the protocol version and the firmware version. 37 | */ 38 | #define FIRMATA_MAJOR_VERSION 2 // same as FIRMATA_PROTOCOL_MAJOR_VERSION 39 | #define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION 40 | #define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION 41 | 42 | #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages 43 | 44 | // Arduino 101 also defines SET_PIN_MODE as a macro in scss_registers.h 45 | #ifdef SET_PIN_MODE 46 | #undef SET_PIN_MODE 47 | #endif 48 | 49 | // message command bytes (128-255/0x80-0xFF) 50 | #define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) 51 | #define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) 52 | #define REPORT_ANALOG 0xC0 // enable analog input by pin # 53 | #define REPORT_DIGITAL 0xD0 // enable digital input by port pair 54 | // 55 | #define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc 56 | #define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin 57 | // 58 | #define REPORT_VERSION 0xF9 // report protocol version 59 | #define SYSTEM_RESET 0xFF // reset from MIDI 60 | // 61 | #define START_SYSEX 0xF0 // start a MIDI Sysex message 62 | #define END_SYSEX 0xF7 // end a MIDI Sysex message 63 | 64 | // extended command set using sysex (0-127/0x00-0x7F) 65 | /* 0x00-0x0F reserved for user-defined commands */ 66 | #define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards 67 | #define ENCODER_DATA 0x61 // reply with encoders current positions 68 | #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq 69 | #define STRING_DATA 0x71 // a string message with 14-bits per char 70 | #define STEPPER_DATA 0x72 // control a stepper motor 71 | #define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request 72 | #define SHIFT_DATA 0x75 // a bitstream to/from a shift register 73 | #define I2C_REQUEST 0x76 // send an I2C read/write request 74 | #define I2C_REPLY 0x77 // a reply to an I2C read request 75 | #define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins 76 | #define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin 77 | #define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value 78 | #define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value 79 | #define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins 80 | #define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution 81 | #define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers 82 | #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info 83 | #define REPORT_FIRMWARE 0x79 // report name and version of the firmware 84 | #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop 85 | #define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler 86 | #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages 87 | #define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages 88 | // these are DEPRECATED to make the naming more consistent 89 | #define FIRMATA_STRING 0x71 // same as STRING_DATA 90 | #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST 91 | #define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY 92 | #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL 93 | 94 | // pin modes 95 | //#define INPUT 0x00 // defined in Arduino.h 96 | //#define OUTPUT 0x01 // defined in Arduino.h 97 | #define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode 98 | #define PIN_MODE_PWM 0x03 // digital pin in PWM output mode 99 | #define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode 100 | #define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode 101 | #define PIN_MODE_I2C 0x06 // pin included in I2C setup 102 | #define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire 103 | #define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor 104 | #define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders 105 | #define PIN_MODE_SERIAL 0x0A // pin configured for serial communication 106 | #define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin 107 | #define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse 108 | #define TOTAL_PIN_MODES 13 109 | // DEPRECATED as of Firmata v2.5 110 | #define ANALOG 0x02 // same as PIN_MODE_ANALOG 111 | #define PWM 0x03 // same as PIN_MODE_PWM 112 | #define SERVO 0x04 // same as PIN_MODE_SERVO 113 | #define SHIFT 0x05 // same as PIN_MODE_SHIFT 114 | #define I2C 0x06 // same as PIN_MODE_I2C 115 | #define ONEWIRE 0x07 // same as PIN_MODE_ONEWIRE 116 | #define STEPPER 0x08 // same as PIN_MODE_STEPPER 117 | #define ENCODER 0x09 // same as PIN_MODE_ENCODER 118 | #define IGNORE 0x7F // same as PIN_MODE_IGNORE 119 | 120 | extern "C" { 121 | // callback function types 122 | typedef void (*callbackFunction)(byte, int); 123 | typedef void (*systemResetCallbackFunction)(void); 124 | typedef void (*stringCallbackFunction)(char *); 125 | typedef void (*sysexCallbackFunction)(byte command, byte argc, byte *argv); 126 | } 127 | 128 | // TODO make it a subclass of a generic Serial/Stream base class 129 | class FirmataClass 130 | { 131 | public: 132 | FirmataClass(); 133 | /* Arduino constructors */ 134 | void begin(); 135 | void begin(long); 136 | void begin(Stream &s); 137 | /* querying functions */ 138 | void printVersion(void); 139 | void blinkVersion(void); 140 | void printFirmwareVersion(void); 141 | //void setFirmwareVersion(byte major, byte minor); // see macro below 142 | void setFirmwareNameAndVersion(const char *name, byte major, byte minor); 143 | void disableBlinkVersion(); 144 | /* serial receive handling */ 145 | int available(void); 146 | void processInput(void); 147 | void parse(unsigned char value); 148 | boolean isParsingMessage(void); 149 | /* serial send handling */ 150 | void sendAnalog(byte pin, int value); 151 | void sendDigital(byte pin, int value); // TODO implement this 152 | void sendDigitalPort(byte portNumber, int portData); 153 | void sendString(const char *string); 154 | void sendString(byte command, const char *string); 155 | void sendSysex(byte command, byte bytec, byte *bytev); 156 | void write(byte c); 157 | /* attach & detach callback functions to messages */ 158 | void attach(byte command, callbackFunction newFunction); 159 | void attach(byte command, systemResetCallbackFunction newFunction); 160 | void attach(byte command, stringCallbackFunction newFunction); 161 | void attach(byte command, sysexCallbackFunction newFunction); 162 | void detach(byte command); 163 | 164 | /* access pin state and config */ 165 | byte getPinMode(byte pin); 166 | void setPinMode(byte pin, byte config); 167 | /* access pin state */ 168 | int getPinState(byte pin); 169 | void setPinState(byte pin, int state); 170 | 171 | /* utility methods */ 172 | void sendValueAsTwo7bitBytes(int value); 173 | void startSysex(void); 174 | void endSysex(void); 175 | 176 | private: 177 | Stream *FirmataStream; 178 | /* firmware name and version */ 179 | byte firmwareVersionCount; 180 | byte *firmwareVersionVector; 181 | /* input message handling */ 182 | byte waitForData; // this flag says the next serial input will be data 183 | byte executeMultiByteCommand; // execute this after getting multi-byte data 184 | byte multiByteChannel; // channel data for multiByteCommands 185 | byte storedInputData[MAX_DATA_BYTES]; // multi-byte data 186 | /* sysex */ 187 | boolean parsingSysex; 188 | int sysexBytesRead; 189 | /* pin configuration */ 190 | byte pinConfig[TOTAL_PINS]; 191 | int pinState[TOTAL_PINS]; 192 | 193 | /* callback functions */ 194 | callbackFunction currentAnalogCallback; 195 | callbackFunction currentDigitalCallback; 196 | callbackFunction currentReportAnalogCallback; 197 | callbackFunction currentReportDigitalCallback; 198 | callbackFunction currentPinModeCallback; 199 | callbackFunction currentPinValueCallback; 200 | systemResetCallbackFunction currentSystemResetCallback; 201 | stringCallbackFunction currentStringCallback; 202 | sysexCallbackFunction currentSysexCallback; 203 | 204 | boolean blinkVersionDisabled = false; 205 | 206 | /* private methods ------------------------------ */ 207 | void processSysexMessage(void); 208 | void systemReset(void); 209 | void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); 210 | }; 211 | 212 | extern FirmataClass Firmata; 213 | 214 | /*============================================================================== 215 | * MACROS 216 | *============================================================================*/ 217 | 218 | /* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the 219 | * firmware name. It needs to be a macro so that __FILE__ is included in the 220 | * firmware source file rather than the library source file. 221 | */ 222 | #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y) 223 | 224 | #endif /* Firmata_h */ 225 | -------------------------------------------------------------------------------- /firmware/build/sbs/sbs_firmata/Firmata.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.cpp - Firmata library v2.5.3 - 2016-06-18 3 | Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | See file LICENSE.txt for further informations on licensing terms. 12 | */ 13 | 14 | //****************************************************************************** 15 | //* Includes 16 | //****************************************************************************** 17 | 18 | #include "Firmata.h" 19 | #include "HardwareSerial.h" 20 | 21 | extern "C" { 22 | #include 23 | #include 24 | } 25 | 26 | //****************************************************************************** 27 | //* Support Functions 28 | //****************************************************************************** 29 | 30 | /** 31 | * Split a 16-bit byte into two 7-bit values and write each value. 32 | * @param value The 16-bit value to be split and written separately. 33 | */ 34 | void FirmataClass::sendValueAsTwo7bitBytes(int value) 35 | { 36 | FirmataStream->write(value & 0x7F); // LSB 37 | FirmataStream->write(value >> 7 & 0x7F); // MSB 38 | } 39 | 40 | /** 41 | * A helper method to write the beginning of a Sysex message transmission. 42 | */ 43 | void FirmataClass::startSysex(void) 44 | { 45 | FirmataStream->write(START_SYSEX); 46 | } 47 | 48 | /** 49 | * A helper method to write the end of a Sysex message transmission. 50 | */ 51 | void FirmataClass::endSysex(void) 52 | { 53 | FirmataStream->write(END_SYSEX); 54 | } 55 | 56 | //****************************************************************************** 57 | //* Constructors 58 | //****************************************************************************** 59 | 60 | /** 61 | * The Firmata class. 62 | * An instance named "Firmata" is created automatically for the user. 63 | */ 64 | FirmataClass::FirmataClass() 65 | { 66 | firmwareVersionCount = 0; 67 | firmwareVersionVector = 0; 68 | systemReset(); 69 | } 70 | 71 | //****************************************************************************** 72 | //* Public Methods 73 | //****************************************************************************** 74 | 75 | /** 76 | * Initialize the default Serial transport at the default baud of 57600. 77 | */ 78 | void FirmataClass::begin(void) 79 | { 80 | begin(57600); 81 | } 82 | 83 | /** 84 | * Initialize the default Serial transport and override the default baud. 85 | * Sends the protocol version to the host application followed by the firmware version and name. 86 | * blinkVersion is also called. To skip the call to blinkVersion, call Firmata.disableBlinkVersion() 87 | * before calling Firmata.begin(baud). 88 | * @param speed The baud to use. 57600 baud is the default value. 89 | */ 90 | void FirmataClass::begin(long speed) 91 | { 92 | Serial.begin(speed); 93 | FirmataStream = &Serial; 94 | blinkVersion(); 95 | printVersion(); // send the protocol version 96 | printFirmwareVersion(); // send the firmware name and version 97 | } 98 | 99 | /** 100 | * Reassign the Firmata stream transport. 101 | * @param s A reference to the Stream transport object. This can be any type of 102 | * transport that implements the Stream interface. Some examples include Ethernet, WiFi 103 | * and other UARTs on the board (Serial1, Serial2, etc). 104 | */ 105 | void FirmataClass::begin(Stream &s) 106 | { 107 | FirmataStream = &s; 108 | // do not call blinkVersion() here because some hardware such as the 109 | // Ethernet shield use pin 13 110 | printVersion(); 111 | printFirmwareVersion(); 112 | } 113 | 114 | /** 115 | * Send the Firmata protocol version to the Firmata host application. 116 | */ 117 | void FirmataClass::printVersion(void) 118 | { 119 | FirmataStream->write(REPORT_VERSION); 120 | FirmataStream->write(FIRMATA_PROTOCOL_MAJOR_VERSION); 121 | FirmataStream->write(FIRMATA_PROTOCOL_MINOR_VERSION); 122 | } 123 | 124 | /** 125 | * Blink the Firmata protocol version to the onboard LEDs (if the board has an onboard LED). 126 | * If VERSION_BLINK_PIN is not defined in Boards.h for a particular board, then this method 127 | * does nothing. 128 | * The first series of flashes indicates the firmware major version (2 flashes = 2). 129 | * The second series of flashes indicates the firmware minor version (5 flashes = 5). 130 | */ 131 | void FirmataClass::blinkVersion(void) 132 | { 133 | #if defined(VERSION_BLINK_PIN) 134 | if (blinkVersionDisabled) return; 135 | // flash the pin with the protocol version 136 | pinMode(VERSION_BLINK_PIN, OUTPUT); 137 | strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MAJOR_VERSION, 40, 210); 138 | delay(250); 139 | strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MINOR_VERSION, 40, 210); 140 | delay(125); 141 | #endif 142 | } 143 | 144 | /** 145 | * Provides a means to disable the version blink sequence on the onboard LED, trimming startup 146 | * time by a couple of seconds. 147 | * Call this before Firmata.begin(). It only applies when using the default Serial transport. 148 | */ 149 | void FirmataClass::disableBlinkVersion() 150 | { 151 | blinkVersionDisabled = true; 152 | } 153 | 154 | /** 155 | * Sends the firmware name and version to the Firmata host application. The major and minor version 156 | * numbers are the first 2 bytes in the message. The following bytes are the characters of the 157 | * firmware name. 158 | */ 159 | void FirmataClass::printFirmwareVersion(void) 160 | { 161 | byte i; 162 | 163 | if (firmwareVersionCount) { // make sure that the name has been set before reporting 164 | startSysex(); 165 | FirmataStream->write(REPORT_FIRMWARE); 166 | FirmataStream->write(firmwareVersionVector[0]); // major version number 167 | FirmataStream->write(firmwareVersionVector[1]); // minor version number 168 | for (i = 2; i < firmwareVersionCount; ++i) { 169 | sendValueAsTwo7bitBytes(firmwareVersionVector[i]); 170 | } 171 | endSysex(); 172 | } 173 | } 174 | 175 | /** 176 | * Sets the name and version of the firmware. This is not the same version as the Firmata protocol 177 | * (although at times the firmware version and protocol version may be the same number). 178 | * @param name A pointer to the name char array 179 | * @param major The major version number 180 | * @param minor The minor version number 181 | */ 182 | void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) 183 | { 184 | const char *firmwareName; 185 | const char *extension; 186 | 187 | // parse out ".cpp" and "applet/" that comes from using __FILE__ 188 | extension = strstr(name, ".cpp"); 189 | firmwareName = strrchr(name, '/'); 190 | 191 | if (!firmwareName) { 192 | // windows 193 | firmwareName = strrchr(name, '\\'); 194 | } 195 | if (!firmwareName) { 196 | // user passed firmware name 197 | firmwareName = name; 198 | } else { 199 | firmwareName ++; 200 | } 201 | 202 | if (!extension) { 203 | firmwareVersionCount = strlen(firmwareName) + 2; 204 | } else { 205 | firmwareVersionCount = extension - firmwareName + 2; 206 | } 207 | 208 | // in case anyone calls setFirmwareNameAndVersion more than once 209 | free(firmwareVersionVector); 210 | 211 | firmwareVersionVector = (byte *) malloc(firmwareVersionCount + 1); 212 | firmwareVersionVector[firmwareVersionCount] = 0; 213 | firmwareVersionVector[0] = major; 214 | firmwareVersionVector[1] = minor; 215 | strncpy((char *)firmwareVersionVector + 2, firmwareName, firmwareVersionCount - 2); 216 | } 217 | 218 | //------------------------------------------------------------------------------ 219 | // Serial Receive Handling 220 | 221 | /** 222 | * A wrapper for Stream::available() 223 | * @return The number of bytes remaining in the input stream buffer. 224 | */ 225 | int FirmataClass::available(void) 226 | { 227 | return FirmataStream->available(); 228 | } 229 | 230 | /** 231 | * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. 232 | * Calls callback function for STRING_DATA and all other sysex messages. 233 | * @private 234 | */ 235 | void FirmataClass::processSysexMessage(void) 236 | { 237 | switch (storedInputData[0]) { //first byte in buffer is command 238 | case REPORT_FIRMWARE: 239 | printFirmwareVersion(); 240 | break; 241 | case STRING_DATA: 242 | if (currentStringCallback) { 243 | byte bufferLength = (sysexBytesRead - 1) / 2; 244 | byte i = 1; 245 | byte j = 0; 246 | while (j < bufferLength) { 247 | // The string length will only be at most half the size of the 248 | // stored input buffer so we can decode the string within the buffer. 249 | storedInputData[j] = storedInputData[i]; 250 | i++; 251 | storedInputData[j] += (storedInputData[i] << 7); 252 | i++; 253 | j++; 254 | } 255 | // Make sure string is null terminated. This may be the case for data 256 | // coming from client libraries in languages that don't null terminate 257 | // strings. 258 | if (storedInputData[j - 1] != '\0') { 259 | storedInputData[j] = '\0'; 260 | } 261 | (*currentStringCallback)((char *)&storedInputData[0]); 262 | } 263 | break; 264 | default: 265 | if (currentSysexCallback) 266 | (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); 267 | } 268 | } 269 | 270 | /** 271 | * Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte) 272 | */ 273 | void FirmataClass::processInput(void) 274 | { 275 | int inputData = FirmataStream->read(); // this is 'int' to handle -1 when no data 276 | if (inputData != -1) { 277 | parse(inputData); 278 | } 279 | } 280 | 281 | /** 282 | * Parse data from the input stream. 283 | * @param inputData A single byte to be added to the parser. 284 | */ 285 | void FirmataClass::parse(byte inputData) 286 | { 287 | int command; 288 | 289 | if (parsingSysex) { 290 | if (inputData == END_SYSEX) { 291 | //stop sysex byte 292 | parsingSysex = false; 293 | //fire off handler function 294 | processSysexMessage(); 295 | } else { 296 | //normal data byte - add to buffer 297 | storedInputData[sysexBytesRead] = inputData; 298 | sysexBytesRead++; 299 | } 300 | } else if ( (waitForData > 0) && (inputData < 128) ) { 301 | waitForData--; 302 | storedInputData[waitForData] = inputData; 303 | if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message 304 | switch (executeMultiByteCommand) { 305 | case ANALOG_MESSAGE: 306 | if (currentAnalogCallback) { 307 | (*currentAnalogCallback)(multiByteChannel, 308 | (storedInputData[0] << 7) 309 | + storedInputData[1]); 310 | } 311 | break; 312 | case DIGITAL_MESSAGE: 313 | if (currentDigitalCallback) { 314 | (*currentDigitalCallback)(multiByteChannel, 315 | (storedInputData[0] << 7) 316 | + storedInputData[1]); 317 | } 318 | break; 319 | case SET_PIN_MODE: 320 | if (currentPinModeCallback) 321 | (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); 322 | break; 323 | case SET_DIGITAL_PIN_VALUE: 324 | if (currentPinValueCallback) 325 | (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); 326 | break; 327 | case REPORT_ANALOG: 328 | if (currentReportAnalogCallback) 329 | (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); 330 | break; 331 | case REPORT_DIGITAL: 332 | if (currentReportDigitalCallback) 333 | (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); 334 | break; 335 | } 336 | executeMultiByteCommand = 0; 337 | } 338 | } else { 339 | // remove channel info from command byte if less than 0xF0 340 | if (inputData < 0xF0) { 341 | command = inputData & 0xF0; 342 | multiByteChannel = inputData & 0x0F; 343 | } else { 344 | command = inputData; 345 | // commands in the 0xF* range don't use channel data 346 | } 347 | switch (command) { 348 | case ANALOG_MESSAGE: 349 | case DIGITAL_MESSAGE: 350 | case SET_PIN_MODE: 351 | case SET_DIGITAL_PIN_VALUE: 352 | waitForData = 2; // two data bytes needed 353 | executeMultiByteCommand = command; 354 | break; 355 | case REPORT_ANALOG: 356 | case REPORT_DIGITAL: 357 | waitForData = 1; // one data byte needed 358 | executeMultiByteCommand = command; 359 | break; 360 | case START_SYSEX: 361 | parsingSysex = true; 362 | sysexBytesRead = 0; 363 | break; 364 | case SYSTEM_RESET: 365 | systemReset(); 366 | break; 367 | case REPORT_VERSION: 368 | Firmata.printVersion(); 369 | break; 370 | } 371 | } 372 | } 373 | 374 | /** 375 | * @return Returns true if the parser is actively parsing data. 376 | */ 377 | boolean FirmataClass::isParsingMessage(void) 378 | { 379 | return (waitForData > 0 || parsingSysex); 380 | } 381 | 382 | //------------------------------------------------------------------------------ 383 | // Output Stream Handling 384 | 385 | /** 386 | * Send an analog message to the Firmata host application. The range of pins is limited to [0..15] 387 | * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits 388 | * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG 389 | * message. 390 | * @param pin The analog pin to send the value of (limited to pins 0 - 15). 391 | * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). 392 | * The maximum value is 14-bits (16384). 393 | */ 394 | void FirmataClass::sendAnalog(byte pin, int value) 395 | { 396 | // pin can only be 0-15, so chop higher bits 397 | FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); 398 | sendValueAsTwo7bitBytes(value); 399 | } 400 | 401 | /* (intentionally left out asterix here) 402 | * STUB - NOT IMPLEMENTED 403 | * Send a single digital pin value to the Firmata host application. 404 | * @param pin The digital pin to send the value of. 405 | * @param value The value of the pin. 406 | */ 407 | void FirmataClass::sendDigital(byte pin, int value) 408 | { 409 | /* TODO add single pin digital messages to the protocol, this needs to 410 | * track the last digital data sent so that it can be sure to change just 411 | * one bit in the packet. This is complicated by the fact that the 412 | * numbering of the pins will probably differ on Arduino, Wiring, and 413 | * other boards. 414 | */ 415 | 416 | // TODO: the digital message should not be sent on the serial port every 417 | // time sendDigital() is called. Instead, it should add it to an int 418 | // which will be sent on a schedule. If a pin changes more than once 419 | // before the digital message is sent on the serial port, it should send a 420 | // digital message for each change. 421 | 422 | // if(value == 0) 423 | // sendDigitalPortPair(); 424 | } 425 | 426 | 427 | /** 428 | * Send an 8-bit port in a single digital message (protocol v2 and later). 429 | * Send 14-bits in a single digital message (protocol v1). 430 | * @param portNumber The port number to send. Note that this is not the same as a "port" on the 431 | * physical microcontroller. Ports are defined in order per every 8 pins in ascending order 432 | * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. 433 | * @param portData The value of the port. The value of each pin in the port is represented by a bit. 434 | */ 435 | void FirmataClass::sendDigitalPort(byte portNumber, int portData) 436 | { 437 | FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); 438 | FirmataStream->write((byte)portData % 128); // Tx bits 0-6 (protocol v1 and higher) 439 | FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) 440 | } 441 | 442 | /** 443 | * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes 444 | * (this is not always the case so this function is not always used to send sysex messages). 445 | * @param command The sysex command byte. 446 | * @param bytec The number of data bytes in the message (excludes start, command and end bytes). 447 | * @param bytev A pointer to the array of data bytes to send in the message. 448 | */ 449 | void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) 450 | { 451 | byte i; 452 | startSysex(); 453 | FirmataStream->write(command); 454 | for (i = 0; i < bytec; i++) { 455 | sendValueAsTwo7bitBytes(bytev[i]); 456 | } 457 | endSysex(); 458 | } 459 | 460 | /** 461 | * Send a string to the Firmata host application. 462 | * @param command Must be STRING_DATA 463 | * @param string A pointer to the char string 464 | */ 465 | void FirmataClass::sendString(byte command, const char *string) 466 | { 467 | if (command == STRING_DATA) { 468 | sendSysex(command, strlen(string), (byte *)string); 469 | } 470 | } 471 | 472 | /** 473 | * Send a string to the Firmata host application. 474 | * @param string A pointer to the char string 475 | */ 476 | void FirmataClass::sendString(const char *string) 477 | { 478 | sendString(STRING_DATA, string); 479 | } 480 | 481 | /** 482 | * A wrapper for Stream::available(). 483 | * Write a single byte to the output stream. 484 | * @param c The byte to be written. 485 | */ 486 | void FirmataClass::write(byte c) 487 | { 488 | FirmataStream->write(c); 489 | } 490 | 491 | /** 492 | * Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, 493 | * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). 494 | * @param command The ID of the command to attach a callback function to. 495 | * @param newFunction A reference to the callback function to attach. 496 | */ 497 | void FirmataClass::attach(byte command, callbackFunction newFunction) 498 | { 499 | switch (command) { 500 | case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; 501 | case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; 502 | case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; 503 | case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; 504 | case SET_PIN_MODE: currentPinModeCallback = newFunction; break; 505 | case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; 506 | } 507 | } 508 | 509 | /** 510 | * Attach a callback function for the SYSTEM_RESET command. 511 | * @param command Must be set to SYSTEM_RESET or it will be ignored. 512 | * @param newFunction A reference to the system reset callback function to attach. 513 | */ 514 | void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) 515 | { 516 | switch (command) { 517 | case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; 518 | } 519 | } 520 | 521 | /** 522 | * Attach a callback function for the STRING_DATA command. 523 | * @param command Must be set to STRING_DATA or it will be ignored. 524 | * @param newFunction A reference to the string callback function to attach. 525 | */ 526 | void FirmataClass::attach(byte command, stringCallbackFunction newFunction) 527 | { 528 | switch (command) { 529 | case STRING_DATA: currentStringCallback = newFunction; break; 530 | } 531 | } 532 | 533 | /** 534 | * Attach a generic sysex callback function to sysex command. 535 | * @param command The ID of the command to attach a callback function to. 536 | * @param newFunction A reference to the sysex callback function to attach. 537 | */ 538 | void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) 539 | { 540 | currentSysexCallback = newFunction; 541 | } 542 | 543 | /** 544 | * Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, 545 | * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). 546 | * @param command The ID of the command to detatch the callback function from. 547 | */ 548 | void FirmataClass::detach(byte command) 549 | { 550 | switch (command) { 551 | case SYSTEM_RESET: currentSystemResetCallback = NULL; break; 552 | case STRING_DATA: currentStringCallback = NULL; break; 553 | case START_SYSEX: currentSysexCallback = NULL; break; 554 | default: 555 | attach(command, (callbackFunction)NULL); 556 | } 557 | } 558 | 559 | /** 560 | * @param pin The pin to get the configuration of. 561 | * @return The configuration of the specified pin. 562 | */ 563 | byte FirmataClass::getPinMode(byte pin) 564 | { 565 | return pinConfig[pin]; 566 | } 567 | 568 | /** 569 | * Set the pin mode/configuration. The pin configuration (or mode) in Firmata represents the 570 | * current function of the pin. Examples are digital input or output, analog input, pwm, i2c, 571 | * serial (uart), etc. 572 | * @param pin The pin to configure. 573 | * @param config The configuration value for the specified pin. 574 | */ 575 | void FirmataClass::setPinMode(byte pin, byte config) 576 | { 577 | if (pinConfig[pin] == PIN_MODE_IGNORE) 578 | return; 579 | 580 | pinConfig[pin] = config; 581 | } 582 | 583 | /** 584 | * @param pin The pin to get the state of. 585 | * @return The state of the specified pin. 586 | */ 587 | int FirmataClass::getPinState(byte pin) 588 | { 589 | return pinState[pin]; 590 | } 591 | 592 | /** 593 | * Set the pin state. The pin state of an output pin is the pin value. The state of an 594 | * input pin is 0, unless the pin has it's internal pull up resistor enabled, then the value is 1. 595 | * @param pin The pin to set the state of 596 | * @param state Set the state of the specified pin 597 | */ 598 | void FirmataClass::setPinState(byte pin, int state) 599 | { 600 | pinState[pin] = state; 601 | } 602 | 603 | // sysex callbacks 604 | /* 605 | * this is too complicated for analogReceive, but maybe for Sysex? 606 | void FirmataClass::attachSysex(sysexFunction newFunction) 607 | { 608 | byte i; 609 | byte tmpCount = analogReceiveFunctionCount; 610 | analogReceiveFunction* tmpArray = analogReceiveFunctionArray; 611 | analogReceiveFunctionCount++; 612 | analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction)); 613 | for(i = 0; i < tmpCount; i++) { 614 | analogReceiveFunctionArray[i] = tmpArray[i]; 615 | } 616 | analogReceiveFunctionArray[tmpCount] = newFunction; 617 | free(tmpArray); 618 | } 619 | */ 620 | 621 | //****************************************************************************** 622 | //* Private Methods 623 | //****************************************************************************** 624 | 625 | /** 626 | * Resets the system state upon a SYSTEM_RESET message from the host software. 627 | * @private 628 | */ 629 | void FirmataClass::systemReset(void) 630 | { 631 | byte i; 632 | 633 | waitForData = 0; // this flag says the next serial input will be data 634 | executeMultiByteCommand = 0; // execute this after getting multi-byte data 635 | multiByteChannel = 0; // channel data for multiByteCommands 636 | 637 | for (i = 0; i < MAX_DATA_BYTES; i++) { 638 | storedInputData[i] = 0; 639 | } 640 | 641 | parsingSysex = false; 642 | sysexBytesRead = 0; 643 | 644 | if (currentSystemResetCallback) 645 | (*currentSystemResetCallback)(); 646 | } 647 | 648 | /** 649 | * Flashing the pin for the version number 650 | * @private 651 | * @param pin The pin the LED is attached to. 652 | * @param count The number of times to flash the LED. 653 | * @param onInterval The number of milliseconds for the LED to be ON during each interval. 654 | * @param offInterval The number of milliseconds for the LED to be OFF during each interval. 655 | */ 656 | void FirmataClass::strobeBlinkPin(byte pin, int count, int onInterval, int offInterval) 657 | { 658 | byte i; 659 | for (i = 0; i < count; i++) { 660 | delay(offInterval); 661 | digitalWrite(pin, HIGH); 662 | delay(onInterval); 663 | digitalWrite(pin, LOW); 664 | } 665 | } 666 | 667 | // make one instance for the user to use 668 | FirmataClass Firmata; 669 | -------------------------------------------------------------------------------- /firmware/build/sbs/sbs_firmata/Firmata.h: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.h - Firmata library v2.5.3 - 2016-06-18 3 | Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | See file LICENSE.txt for further informations on licensing terms. 12 | */ 13 | 14 | #ifndef Firmata_h 15 | #define Firmata_h 16 | 17 | #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ 18 | 19 | /* Version numbers for the protocol. The protocol is still changing, so these 20 | * version numbers are important. 21 | * Query using the REPORT_VERSION message. 22 | */ 23 | #define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes 24 | #define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes 25 | #define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases 26 | 27 | /* Version numbers for the Firmata library. 28 | * The firmware version will not always equal the protocol version going forward. 29 | * Query using the REPORT_FIRMWARE message. 30 | */ 31 | #define FIRMATA_FIRMWARE_MAJOR_VERSION 2 32 | #define FIRMATA_FIRMWARE_MINOR_VERSION 5 33 | #define FIRMATA_FIRMWARE_BUGFIX_VERSION 3 34 | 35 | /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for 36 | * the protocol version and the firmware version. 37 | */ 38 | #define FIRMATA_MAJOR_VERSION 2 // same as FIRMATA_PROTOCOL_MAJOR_VERSION 39 | #define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION 40 | #define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION 41 | 42 | #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages 43 | 44 | // Arduino 101 also defines SET_PIN_MODE as a macro in scss_registers.h 45 | #ifdef SET_PIN_MODE 46 | #undef SET_PIN_MODE 47 | #endif 48 | 49 | // message command bytes (128-255/0x80-0xFF) 50 | #define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) 51 | #define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) 52 | #define REPORT_ANALOG 0xC0 // enable analog input by pin # 53 | #define REPORT_DIGITAL 0xD0 // enable digital input by port pair 54 | // 55 | #define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc 56 | #define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin 57 | // 58 | #define REPORT_VERSION 0xF9 // report protocol version 59 | #define SYSTEM_RESET 0xFF // reset from MIDI 60 | // 61 | #define START_SYSEX 0xF0 // start a MIDI Sysex message 62 | #define END_SYSEX 0xF7 // end a MIDI Sysex message 63 | 64 | // extended command set using sysex (0-127/0x00-0x7F) 65 | /* 0x00-0x0F reserved for user-defined commands */ 66 | #define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards 67 | #define ENCODER_DATA 0x61 // reply with encoders current positions 68 | #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq 69 | #define STRING_DATA 0x71 // a string message with 14-bits per char 70 | #define STEPPER_DATA 0x72 // control a stepper motor 71 | #define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request 72 | #define SHIFT_DATA 0x75 // a bitstream to/from a shift register 73 | #define I2C_REQUEST 0x76 // send an I2C read/write request 74 | #define I2C_REPLY 0x77 // a reply to an I2C read request 75 | #define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins 76 | #define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin 77 | #define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value 78 | #define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value 79 | #define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins 80 | #define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution 81 | #define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers 82 | #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info 83 | #define REPORT_FIRMWARE 0x79 // report name and version of the firmware 84 | #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop 85 | #define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler 86 | #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages 87 | #define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages 88 | // these are DEPRECATED to make the naming more consistent 89 | #define FIRMATA_STRING 0x71 // same as STRING_DATA 90 | #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST 91 | #define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY 92 | #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL 93 | 94 | // pin modes 95 | //#define INPUT 0x00 // defined in Arduino.h 96 | //#define OUTPUT 0x01 // defined in Arduino.h 97 | #define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode 98 | #define PIN_MODE_PWM 0x03 // digital pin in PWM output mode 99 | #define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode 100 | #define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode 101 | #define PIN_MODE_I2C 0x06 // pin included in I2C setup 102 | #define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire 103 | #define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor 104 | #define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders 105 | #define PIN_MODE_SERIAL 0x0A // pin configured for serial communication 106 | #define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin 107 | #define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse 108 | #define TOTAL_PIN_MODES 13 109 | // DEPRECATED as of Firmata v2.5 110 | #define ANALOG 0x02 // same as PIN_MODE_ANALOG 111 | #define PWM 0x03 // same as PIN_MODE_PWM 112 | #define SERVO 0x04 // same as PIN_MODE_SERVO 113 | #define SHIFT 0x05 // same as PIN_MODE_SHIFT 114 | #define I2C 0x06 // same as PIN_MODE_I2C 115 | #define ONEWIRE 0x07 // same as PIN_MODE_ONEWIRE 116 | #define STEPPER 0x08 // same as PIN_MODE_STEPPER 117 | #define ENCODER 0x09 // same as PIN_MODE_ENCODER 118 | #define IGNORE 0x7F // same as PIN_MODE_IGNORE 119 | 120 | extern "C" { 121 | // callback function types 122 | typedef void (*callbackFunction)(byte, int); 123 | typedef void (*systemResetCallbackFunction)(void); 124 | typedef void (*stringCallbackFunction)(char *); 125 | typedef void (*sysexCallbackFunction)(byte command, byte argc, byte *argv); 126 | } 127 | 128 | // TODO make it a subclass of a generic Serial/Stream base class 129 | class FirmataClass 130 | { 131 | public: 132 | FirmataClass(); 133 | /* Arduino constructors */ 134 | void begin(); 135 | void begin(long); 136 | void begin(Stream &s); 137 | /* querying functions */ 138 | void printVersion(void); 139 | void blinkVersion(void); 140 | void printFirmwareVersion(void); 141 | //void setFirmwareVersion(byte major, byte minor); // see macro below 142 | void setFirmwareNameAndVersion(const char *name, byte major, byte minor); 143 | void disableBlinkVersion(); 144 | /* serial receive handling */ 145 | int available(void); 146 | void processInput(void); 147 | void parse(unsigned char value); 148 | boolean isParsingMessage(void); 149 | /* serial send handling */ 150 | void sendAnalog(byte pin, int value); 151 | void sendDigital(byte pin, int value); // TODO implement this 152 | void sendDigitalPort(byte portNumber, int portData); 153 | void sendString(const char *string); 154 | void sendString(byte command, const char *string); 155 | void sendSysex(byte command, byte bytec, byte *bytev); 156 | void write(byte c); 157 | /* attach & detach callback functions to messages */ 158 | void attach(byte command, callbackFunction newFunction); 159 | void attach(byte command, systemResetCallbackFunction newFunction); 160 | void attach(byte command, stringCallbackFunction newFunction); 161 | void attach(byte command, sysexCallbackFunction newFunction); 162 | void detach(byte command); 163 | 164 | /* access pin state and config */ 165 | byte getPinMode(byte pin); 166 | void setPinMode(byte pin, byte config); 167 | /* access pin state */ 168 | int getPinState(byte pin); 169 | void setPinState(byte pin, int state); 170 | 171 | /* utility methods */ 172 | void sendValueAsTwo7bitBytes(int value); 173 | void startSysex(void); 174 | void endSysex(void); 175 | 176 | private: 177 | Stream *FirmataStream; 178 | /* firmware name and version */ 179 | byte firmwareVersionCount; 180 | byte *firmwareVersionVector; 181 | /* input message handling */ 182 | byte waitForData; // this flag says the next serial input will be data 183 | byte executeMultiByteCommand; // execute this after getting multi-byte data 184 | byte multiByteChannel; // channel data for multiByteCommands 185 | byte storedInputData[MAX_DATA_BYTES]; // multi-byte data 186 | /* sysex */ 187 | boolean parsingSysex; 188 | int sysexBytesRead; 189 | /* pin configuration */ 190 | byte pinConfig[TOTAL_PINS]; 191 | int pinState[TOTAL_PINS]; 192 | 193 | /* callback functions */ 194 | callbackFunction currentAnalogCallback; 195 | callbackFunction currentDigitalCallback; 196 | callbackFunction currentReportAnalogCallback; 197 | callbackFunction currentReportDigitalCallback; 198 | callbackFunction currentPinModeCallback; 199 | callbackFunction currentPinValueCallback; 200 | systemResetCallbackFunction currentSystemResetCallback; 201 | stringCallbackFunction currentStringCallback; 202 | sysexCallbackFunction currentSysexCallback; 203 | 204 | boolean blinkVersionDisabled = false; 205 | 206 | /* private methods ------------------------------ */ 207 | void processSysexMessage(void); 208 | void systemReset(void); 209 | void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); 210 | }; 211 | 212 | extern FirmataClass Firmata; 213 | 214 | /*============================================================================== 215 | * MACROS 216 | *============================================================================*/ 217 | 218 | /* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the 219 | * firmware name. It needs to be a macro so that __FILE__ is included in the 220 | * firmware source file rather than the library source file. 221 | */ 222 | #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y) 223 | 224 | #endif /* Firmata_h */ 225 | -------------------------------------------------------------------------------- /firmware/build/standard/simplebot_firmata/Firmata.h: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.h - Firmata library v2.5.3 - 2016-06-18 3 | Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | See file LICENSE.txt for further informations on licensing terms. 12 | */ 13 | 14 | #ifndef Firmata_h 15 | #define Firmata_h 16 | 17 | #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ 18 | 19 | /* Version numbers for the protocol. The protocol is still changing, so these 20 | * version numbers are important. 21 | * Query using the REPORT_VERSION message. 22 | */ 23 | #define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes 24 | #define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes 25 | #define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases 26 | 27 | /* Version numbers for the Firmata library. 28 | * The firmware version will not always equal the protocol version going forward. 29 | * Query using the REPORT_FIRMWARE message. 30 | */ 31 | #define FIRMATA_FIRMWARE_MAJOR_VERSION 2 32 | #define FIRMATA_FIRMWARE_MINOR_VERSION 5 33 | #define FIRMATA_FIRMWARE_BUGFIX_VERSION 3 34 | 35 | /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for 36 | * the protocol version and the firmware version. 37 | */ 38 | #define FIRMATA_MAJOR_VERSION 2 // same as FIRMATA_PROTOCOL_MAJOR_VERSION 39 | #define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION 40 | #define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION 41 | 42 | #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages 43 | 44 | // Arduino 101 also defines SET_PIN_MODE as a macro in scss_registers.h 45 | #ifdef SET_PIN_MODE 46 | #undef SET_PIN_MODE 47 | #endif 48 | 49 | // message command bytes (128-255/0x80-0xFF) 50 | #define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) 51 | #define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) 52 | #define REPORT_ANALOG 0xC0 // enable analog input by pin # 53 | #define REPORT_DIGITAL 0xD0 // enable digital input by port pair 54 | // 55 | #define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc 56 | #define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin 57 | // 58 | #define REPORT_VERSION 0xF9 // report protocol version 59 | #define SYSTEM_RESET 0xFF // reset from MIDI 60 | // 61 | #define START_SYSEX 0xF0 // start a MIDI Sysex message 62 | #define END_SYSEX 0xF7 // end a MIDI Sysex message 63 | 64 | // extended command set using sysex (0-127/0x00-0x7F) 65 | /* 0x00-0x0F reserved for user-defined commands */ 66 | #define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards 67 | #define ENCODER_DATA 0x61 // reply with encoders current positions 68 | #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq 69 | #define STRING_DATA 0x71 // a string message with 14-bits per char 70 | #define STEPPER_DATA 0x72 // control a stepper motor 71 | #define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request 72 | #define SHIFT_DATA 0x75 // a bitstream to/from a shift register 73 | #define I2C_REQUEST 0x76 // send an I2C read/write request 74 | #define I2C_REPLY 0x77 // a reply to an I2C read request 75 | #define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins 76 | #define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin 77 | #define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value 78 | #define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value 79 | #define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins 80 | #define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution 81 | #define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers 82 | #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info 83 | #define REPORT_FIRMWARE 0x79 // report name and version of the firmware 84 | #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop 85 | #define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler 86 | #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages 87 | #define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages 88 | // these are DEPRECATED to make the naming more consistent 89 | #define FIRMATA_STRING 0x71 // same as STRING_DATA 90 | #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST 91 | #define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY 92 | #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL 93 | 94 | // pin modes 95 | //#define INPUT 0x00 // defined in Arduino.h 96 | //#define OUTPUT 0x01 // defined in Arduino.h 97 | #define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode 98 | #define PIN_MODE_PWM 0x03 // digital pin in PWM output mode 99 | #define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode 100 | #define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode 101 | #define PIN_MODE_I2C 0x06 // pin included in I2C setup 102 | #define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire 103 | #define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor 104 | #define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders 105 | #define PIN_MODE_SERIAL 0x0A // pin configured for serial communication 106 | #define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin 107 | #define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse 108 | #define TOTAL_PIN_MODES 13 109 | // DEPRECATED as of Firmata v2.5 110 | #define ANALOG 0x02 // same as PIN_MODE_ANALOG 111 | #define PWM 0x03 // same as PIN_MODE_PWM 112 | #define SERVO 0x04 // same as PIN_MODE_SERVO 113 | #define SHIFT 0x05 // same as PIN_MODE_SHIFT 114 | #define I2C 0x06 // same as PIN_MODE_I2C 115 | #define ONEWIRE 0x07 // same as PIN_MODE_ONEWIRE 116 | #define STEPPER 0x08 // same as PIN_MODE_STEPPER 117 | #define ENCODER 0x09 // same as PIN_MODE_ENCODER 118 | #define IGNORE 0x7F // same as PIN_MODE_IGNORE 119 | 120 | extern "C" { 121 | // callback function types 122 | typedef void (*callbackFunction)(byte, int); 123 | typedef void (*systemResetCallbackFunction)(void); 124 | typedef void (*stringCallbackFunction)(char *); 125 | typedef void (*sysexCallbackFunction)(byte command, byte argc, byte *argv); 126 | } 127 | 128 | // TODO make it a subclass of a generic Serial/Stream base class 129 | class FirmataClass 130 | { 131 | public: 132 | FirmataClass(); 133 | /* Arduino constructors */ 134 | void begin(); 135 | void begin(long); 136 | void begin(Stream &s); 137 | /* querying functions */ 138 | void printVersion(void); 139 | void blinkVersion(void); 140 | void printFirmwareVersion(void); 141 | //void setFirmwareVersion(byte major, byte minor); // see macro below 142 | void setFirmwareNameAndVersion(const char *name, byte major, byte minor); 143 | void disableBlinkVersion(); 144 | /* serial receive handling */ 145 | int available(void); 146 | void processInput(void); 147 | void parse(unsigned char value); 148 | boolean isParsingMessage(void); 149 | /* serial send handling */ 150 | void sendAnalog(byte pin, int value); 151 | void sendDigital(byte pin, int value); // TODO implement this 152 | void sendDigitalPort(byte portNumber, int portData); 153 | void sendString(const char *string); 154 | void sendString(byte command, const char *string); 155 | void sendSysex(byte command, byte bytec, byte *bytev); 156 | void write(byte c); 157 | /* attach & detach callback functions to messages */ 158 | void attach(byte command, callbackFunction newFunction); 159 | void attach(byte command, systemResetCallbackFunction newFunction); 160 | void attach(byte command, stringCallbackFunction newFunction); 161 | void attach(byte command, sysexCallbackFunction newFunction); 162 | void detach(byte command); 163 | 164 | /* access pin state and config */ 165 | byte getPinMode(byte pin); 166 | void setPinMode(byte pin, byte config); 167 | /* access pin state */ 168 | int getPinState(byte pin); 169 | void setPinState(byte pin, int state); 170 | 171 | /* utility methods */ 172 | void sendValueAsTwo7bitBytes(int value); 173 | void startSysex(void); 174 | void endSysex(void); 175 | 176 | private: 177 | Stream *FirmataStream; 178 | /* firmware name and version */ 179 | byte firmwareVersionCount; 180 | byte *firmwareVersionVector; 181 | /* input message handling */ 182 | byte waitForData; // this flag says the next serial input will be data 183 | byte executeMultiByteCommand; // execute this after getting multi-byte data 184 | byte multiByteChannel; // channel data for multiByteCommands 185 | byte storedInputData[MAX_DATA_BYTES]; // multi-byte data 186 | /* sysex */ 187 | boolean parsingSysex; 188 | int sysexBytesRead; 189 | /* pin configuration */ 190 | byte pinConfig[TOTAL_PINS]; 191 | int pinState[TOTAL_PINS]; 192 | 193 | /* callback functions */ 194 | callbackFunction currentAnalogCallback; 195 | callbackFunction currentDigitalCallback; 196 | callbackFunction currentReportAnalogCallback; 197 | callbackFunction currentReportDigitalCallback; 198 | callbackFunction currentPinModeCallback; 199 | callbackFunction currentPinValueCallback; 200 | systemResetCallbackFunction currentSystemResetCallback; 201 | stringCallbackFunction currentStringCallback; 202 | sysexCallbackFunction currentSysexCallback; 203 | 204 | boolean blinkVersionDisabled = false; 205 | 206 | /* private methods ------------------------------ */ 207 | void processSysexMessage(void); 208 | void systemReset(void); 209 | void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); 210 | }; 211 | 212 | extern FirmataClass Firmata; 213 | 214 | /*============================================================================== 215 | * MACROS 216 | *============================================================================*/ 217 | 218 | /* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the 219 | * firmware name. It needs to be a macro so that __FILE__ is included in the 220 | * firmware source file rather than the library source file. 221 | */ 222 | #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y) 223 | 224 | #endif /* Firmata_h */ 225 | -------------------------------------------------------------------------------- /firmware/src/libs/firmata/Firmata.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.cpp - Firmata library v2.5.3 - 2016-06-18 3 | Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | See file LICENSE.txt for further informations on licensing terms. 12 | */ 13 | 14 | //****************************************************************************** 15 | //* Includes 16 | //****************************************************************************** 17 | 18 | #include "Firmata.h" 19 | #include "HardwareSerial.h" 20 | 21 | extern "C" { 22 | #include 23 | #include 24 | } 25 | 26 | //****************************************************************************** 27 | //* Support Functions 28 | //****************************************************************************** 29 | 30 | /** 31 | * Split a 16-bit byte into two 7-bit values and write each value. 32 | * @param value The 16-bit value to be split and written separately. 33 | */ 34 | void FirmataClass::sendValueAsTwo7bitBytes(int value) 35 | { 36 | FirmataStream->write(value & 0x7F); // LSB 37 | FirmataStream->write(value >> 7 & 0x7F); // MSB 38 | } 39 | 40 | /** 41 | * A helper method to write the beginning of a Sysex message transmission. 42 | */ 43 | void FirmataClass::startSysex(void) 44 | { 45 | FirmataStream->write(START_SYSEX); 46 | } 47 | 48 | /** 49 | * A helper method to write the end of a Sysex message transmission. 50 | */ 51 | void FirmataClass::endSysex(void) 52 | { 53 | FirmataStream->write(END_SYSEX); 54 | } 55 | 56 | //****************************************************************************** 57 | //* Constructors 58 | //****************************************************************************** 59 | 60 | /** 61 | * The Firmata class. 62 | * An instance named "Firmata" is created automatically for the user. 63 | */ 64 | FirmataClass::FirmataClass() 65 | { 66 | firmwareVersionCount = 0; 67 | firmwareVersionVector = 0; 68 | systemReset(); 69 | } 70 | 71 | //****************************************************************************** 72 | //* Public Methods 73 | //****************************************************************************** 74 | 75 | /** 76 | * Initialize the default Serial transport at the default baud of 57600. 77 | */ 78 | void FirmataClass::begin(void) 79 | { 80 | begin(57600); 81 | } 82 | 83 | /** 84 | * Initialize the default Serial transport and override the default baud. 85 | * Sends the protocol version to the host application followed by the firmware version and name. 86 | * blinkVersion is also called. To skip the call to blinkVersion, call Firmata.disableBlinkVersion() 87 | * before calling Firmata.begin(baud). 88 | * @param speed The baud to use. 57600 baud is the default value. 89 | */ 90 | void FirmataClass::begin(long speed) 91 | { 92 | Serial.begin(speed); 93 | FirmataStream = &Serial; 94 | blinkVersion(); 95 | printVersion(); // send the protocol version 96 | printFirmwareVersion(); // send the firmware name and version 97 | } 98 | 99 | /** 100 | * Reassign the Firmata stream transport. 101 | * @param s A reference to the Stream transport object. This can be any type of 102 | * transport that implements the Stream interface. Some examples include Ethernet, WiFi 103 | * and other UARTs on the board (Serial1, Serial2, etc). 104 | */ 105 | void FirmataClass::begin(Stream &s) 106 | { 107 | FirmataStream = &s; 108 | // do not call blinkVersion() here because some hardware such as the 109 | // Ethernet shield use pin 13 110 | printVersion(); 111 | printFirmwareVersion(); 112 | } 113 | 114 | /** 115 | * Send the Firmata protocol version to the Firmata host application. 116 | */ 117 | void FirmataClass::printVersion(void) 118 | { 119 | FirmataStream->write(REPORT_VERSION); 120 | FirmataStream->write(FIRMATA_PROTOCOL_MAJOR_VERSION); 121 | FirmataStream->write(FIRMATA_PROTOCOL_MINOR_VERSION); 122 | } 123 | 124 | /** 125 | * Blink the Firmata protocol version to the onboard LEDs (if the board has an onboard LED). 126 | * If VERSION_BLINK_PIN is not defined in Boards.h for a particular board, then this method 127 | * does nothing. 128 | * The first series of flashes indicates the firmware major version (2 flashes = 2). 129 | * The second series of flashes indicates the firmware minor version (5 flashes = 5). 130 | */ 131 | void FirmataClass::blinkVersion(void) 132 | { 133 | #if defined(VERSION_BLINK_PIN) 134 | if (blinkVersionDisabled) return; 135 | // flash the pin with the protocol version 136 | pinMode(VERSION_BLINK_PIN, OUTPUT); 137 | strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MAJOR_VERSION, 40, 210); 138 | delay(250); 139 | strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MINOR_VERSION, 40, 210); 140 | delay(125); 141 | #endif 142 | } 143 | 144 | /** 145 | * Provides a means to disable the version blink sequence on the onboard LED, trimming startup 146 | * time by a couple of seconds. 147 | * Call this before Firmata.begin(). It only applies when using the default Serial transport. 148 | */ 149 | void FirmataClass::disableBlinkVersion() 150 | { 151 | blinkVersionDisabled = true; 152 | } 153 | 154 | /** 155 | * Sends the firmware name and version to the Firmata host application. The major and minor version 156 | * numbers are the first 2 bytes in the message. The following bytes are the characters of the 157 | * firmware name. 158 | */ 159 | void FirmataClass::printFirmwareVersion(void) 160 | { 161 | byte i; 162 | 163 | if (firmwareVersionCount) { // make sure that the name has been set before reporting 164 | startSysex(); 165 | FirmataStream->write(REPORT_FIRMWARE); 166 | FirmataStream->write(firmwareVersionVector[0]); // major version number 167 | FirmataStream->write(firmwareVersionVector[1]); // minor version number 168 | for (i = 2; i < firmwareVersionCount; ++i) { 169 | sendValueAsTwo7bitBytes(firmwareVersionVector[i]); 170 | } 171 | endSysex(); 172 | } 173 | } 174 | 175 | /** 176 | * Sets the name and version of the firmware. This is not the same version as the Firmata protocol 177 | * (although at times the firmware version and protocol version may be the same number). 178 | * @param name A pointer to the name char array 179 | * @param major The major version number 180 | * @param minor The minor version number 181 | */ 182 | void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) 183 | { 184 | const char *firmwareName; 185 | const char *extension; 186 | 187 | // parse out ".cpp" and "applet/" that comes from using __FILE__ 188 | extension = strstr(name, ".cpp"); 189 | firmwareName = strrchr(name, '/'); 190 | 191 | if (!firmwareName) { 192 | // windows 193 | firmwareName = strrchr(name, '\\'); 194 | } 195 | if (!firmwareName) { 196 | // user passed firmware name 197 | firmwareName = name; 198 | } else { 199 | firmwareName ++; 200 | } 201 | 202 | if (!extension) { 203 | firmwareVersionCount = strlen(firmwareName) + 2; 204 | } else { 205 | firmwareVersionCount = extension - firmwareName + 2; 206 | } 207 | 208 | // in case anyone calls setFirmwareNameAndVersion more than once 209 | free(firmwareVersionVector); 210 | 211 | firmwareVersionVector = (byte *) malloc(firmwareVersionCount + 1); 212 | firmwareVersionVector[firmwareVersionCount] = 0; 213 | firmwareVersionVector[0] = major; 214 | firmwareVersionVector[1] = minor; 215 | strncpy((char *)firmwareVersionVector + 2, firmwareName, firmwareVersionCount - 2); 216 | } 217 | 218 | //------------------------------------------------------------------------------ 219 | // Serial Receive Handling 220 | 221 | /** 222 | * A wrapper for Stream::available() 223 | * @return The number of bytes remaining in the input stream buffer. 224 | */ 225 | int FirmataClass::available(void) 226 | { 227 | return FirmataStream->available(); 228 | } 229 | 230 | /** 231 | * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. 232 | * Calls callback function for STRING_DATA and all other sysex messages. 233 | * @private 234 | */ 235 | void FirmataClass::processSysexMessage(void) 236 | { 237 | switch (storedInputData[0]) { //first byte in buffer is command 238 | case REPORT_FIRMWARE: 239 | printFirmwareVersion(); 240 | break; 241 | case STRING_DATA: 242 | if (currentStringCallback) { 243 | byte bufferLength = (sysexBytesRead - 1) / 2; 244 | byte i = 1; 245 | byte j = 0; 246 | while (j < bufferLength) { 247 | // The string length will only be at most half the size of the 248 | // stored input buffer so we can decode the string within the buffer. 249 | storedInputData[j] = storedInputData[i]; 250 | i++; 251 | storedInputData[j] += (storedInputData[i] << 7); 252 | i++; 253 | j++; 254 | } 255 | // Make sure string is null terminated. This may be the case for data 256 | // coming from client libraries in languages that don't null terminate 257 | // strings. 258 | if (storedInputData[j - 1] != '\0') { 259 | storedInputData[j] = '\0'; 260 | } 261 | (*currentStringCallback)((char *)&storedInputData[0]); 262 | } 263 | break; 264 | default: 265 | if (currentSysexCallback) 266 | (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); 267 | } 268 | } 269 | 270 | /** 271 | * Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte) 272 | */ 273 | void FirmataClass::processInput(void) 274 | { 275 | int inputData = FirmataStream->read(); // this is 'int' to handle -1 when no data 276 | if (inputData != -1) { 277 | parse(inputData); 278 | } 279 | } 280 | 281 | /** 282 | * Parse data from the input stream. 283 | * @param inputData A single byte to be added to the parser. 284 | */ 285 | void FirmataClass::parse(byte inputData) 286 | { 287 | int command; 288 | 289 | if (parsingSysex) { 290 | if (inputData == END_SYSEX) { 291 | //stop sysex byte 292 | parsingSysex = false; 293 | //fire off handler function 294 | processSysexMessage(); 295 | } else { 296 | //normal data byte - add to buffer 297 | storedInputData[sysexBytesRead] = inputData; 298 | sysexBytesRead++; 299 | } 300 | } else if ( (waitForData > 0) && (inputData < 128) ) { 301 | waitForData--; 302 | storedInputData[waitForData] = inputData; 303 | if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message 304 | switch (executeMultiByteCommand) { 305 | case ANALOG_MESSAGE: 306 | if (currentAnalogCallback) { 307 | (*currentAnalogCallback)(multiByteChannel, 308 | (storedInputData[0] << 7) 309 | + storedInputData[1]); 310 | } 311 | break; 312 | case DIGITAL_MESSAGE: 313 | if (currentDigitalCallback) { 314 | (*currentDigitalCallback)(multiByteChannel, 315 | (storedInputData[0] << 7) 316 | + storedInputData[1]); 317 | } 318 | break; 319 | case SET_PIN_MODE: 320 | if (currentPinModeCallback) 321 | (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); 322 | break; 323 | case SET_DIGITAL_PIN_VALUE: 324 | if (currentPinValueCallback) 325 | (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); 326 | break; 327 | case REPORT_ANALOG: 328 | if (currentReportAnalogCallback) 329 | (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); 330 | break; 331 | case REPORT_DIGITAL: 332 | if (currentReportDigitalCallback) 333 | (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); 334 | break; 335 | } 336 | executeMultiByteCommand = 0; 337 | } 338 | } else { 339 | // remove channel info from command byte if less than 0xF0 340 | if (inputData < 0xF0) { 341 | command = inputData & 0xF0; 342 | multiByteChannel = inputData & 0x0F; 343 | } else { 344 | command = inputData; 345 | // commands in the 0xF* range don't use channel data 346 | } 347 | switch (command) { 348 | case ANALOG_MESSAGE: 349 | case DIGITAL_MESSAGE: 350 | case SET_PIN_MODE: 351 | case SET_DIGITAL_PIN_VALUE: 352 | waitForData = 2; // two data bytes needed 353 | executeMultiByteCommand = command; 354 | break; 355 | case REPORT_ANALOG: 356 | case REPORT_DIGITAL: 357 | waitForData = 1; // one data byte needed 358 | executeMultiByteCommand = command; 359 | break; 360 | case START_SYSEX: 361 | parsingSysex = true; 362 | sysexBytesRead = 0; 363 | break; 364 | case SYSTEM_RESET: 365 | systemReset(); 366 | break; 367 | case REPORT_VERSION: 368 | Firmata.printVersion(); 369 | break; 370 | } 371 | } 372 | } 373 | 374 | /** 375 | * @return Returns true if the parser is actively parsing data. 376 | */ 377 | boolean FirmataClass::isParsingMessage(void) 378 | { 379 | return (waitForData > 0 || parsingSysex); 380 | } 381 | 382 | //------------------------------------------------------------------------------ 383 | // Output Stream Handling 384 | 385 | /** 386 | * Send an analog message to the Firmata host application. The range of pins is limited to [0..15] 387 | * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits 388 | * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG 389 | * message. 390 | * @param pin The analog pin to send the value of (limited to pins 0 - 15). 391 | * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). 392 | * The maximum value is 14-bits (16384). 393 | */ 394 | void FirmataClass::sendAnalog(byte pin, int value) 395 | { 396 | // pin can only be 0-15, so chop higher bits 397 | FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); 398 | sendValueAsTwo7bitBytes(value); 399 | } 400 | 401 | /* (intentionally left out asterix here) 402 | * STUB - NOT IMPLEMENTED 403 | * Send a single digital pin value to the Firmata host application. 404 | * @param pin The digital pin to send the value of. 405 | * @param value The value of the pin. 406 | */ 407 | void FirmataClass::sendDigital(byte pin, int value) 408 | { 409 | /* TODO add single pin digital messages to the protocol, this needs to 410 | * track the last digital data sent so that it can be sure to change just 411 | * one bit in the packet. This is complicated by the fact that the 412 | * numbering of the pins will probably differ on Arduino, Wiring, and 413 | * other boards. 414 | */ 415 | 416 | // TODO: the digital message should not be sent on the serial port every 417 | // time sendDigital() is called. Instead, it should add it to an int 418 | // which will be sent on a schedule. If a pin changes more than once 419 | // before the digital message is sent on the serial port, it should send a 420 | // digital message for each change. 421 | 422 | // if(value == 0) 423 | // sendDigitalPortPair(); 424 | } 425 | 426 | 427 | /** 428 | * Send an 8-bit port in a single digital message (protocol v2 and later). 429 | * Send 14-bits in a single digital message (protocol v1). 430 | * @param portNumber The port number to send. Note that this is not the same as a "port" on the 431 | * physical microcontroller. Ports are defined in order per every 8 pins in ascending order 432 | * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. 433 | * @param portData The value of the port. The value of each pin in the port is represented by a bit. 434 | */ 435 | void FirmataClass::sendDigitalPort(byte portNumber, int portData) 436 | { 437 | FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); 438 | FirmataStream->write((byte)portData % 128); // Tx bits 0-6 (protocol v1 and higher) 439 | FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) 440 | } 441 | 442 | /** 443 | * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes 444 | * (this is not always the case so this function is not always used to send sysex messages). 445 | * @param command The sysex command byte. 446 | * @param bytec The number of data bytes in the message (excludes start, command and end bytes). 447 | * @param bytev A pointer to the array of data bytes to send in the message. 448 | */ 449 | void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) 450 | { 451 | byte i; 452 | startSysex(); 453 | FirmataStream->write(command); 454 | for (i = 0; i < bytec; i++) { 455 | sendValueAsTwo7bitBytes(bytev[i]); 456 | } 457 | endSysex(); 458 | } 459 | 460 | /** 461 | * Send a string to the Firmata host application. 462 | * @param command Must be STRING_DATA 463 | * @param string A pointer to the char string 464 | */ 465 | void FirmataClass::sendString(byte command, const char *string) 466 | { 467 | if (command == STRING_DATA) { 468 | sendSysex(command, strlen(string), (byte *)string); 469 | } 470 | } 471 | 472 | /** 473 | * Send a string to the Firmata host application. 474 | * @param string A pointer to the char string 475 | */ 476 | void FirmataClass::sendString(const char *string) 477 | { 478 | sendString(STRING_DATA, string); 479 | } 480 | 481 | /** 482 | * A wrapper for Stream::available(). 483 | * Write a single byte to the output stream. 484 | * @param c The byte to be written. 485 | */ 486 | void FirmataClass::write(byte c) 487 | { 488 | FirmataStream->write(c); 489 | } 490 | 491 | /** 492 | * Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, 493 | * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). 494 | * @param command The ID of the command to attach a callback function to. 495 | * @param newFunction A reference to the callback function to attach. 496 | */ 497 | void FirmataClass::attach(byte command, callbackFunction newFunction) 498 | { 499 | switch (command) { 500 | case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; 501 | case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; 502 | case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; 503 | case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; 504 | case SET_PIN_MODE: currentPinModeCallback = newFunction; break; 505 | case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; 506 | } 507 | } 508 | 509 | /** 510 | * Attach a callback function for the SYSTEM_RESET command. 511 | * @param command Must be set to SYSTEM_RESET or it will be ignored. 512 | * @param newFunction A reference to the system reset callback function to attach. 513 | */ 514 | void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) 515 | { 516 | switch (command) { 517 | case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; 518 | } 519 | } 520 | 521 | /** 522 | * Attach a callback function for the STRING_DATA command. 523 | * @param command Must be set to STRING_DATA or it will be ignored. 524 | * @param newFunction A reference to the string callback function to attach. 525 | */ 526 | void FirmataClass::attach(byte command, stringCallbackFunction newFunction) 527 | { 528 | switch (command) { 529 | case STRING_DATA: currentStringCallback = newFunction; break; 530 | } 531 | } 532 | 533 | /** 534 | * Attach a generic sysex callback function to sysex command. 535 | * @param command The ID of the command to attach a callback function to. 536 | * @param newFunction A reference to the sysex callback function to attach. 537 | */ 538 | void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) 539 | { 540 | currentSysexCallback = newFunction; 541 | } 542 | 543 | /** 544 | * Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, 545 | * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). 546 | * @param command The ID of the command to detatch the callback function from. 547 | */ 548 | void FirmataClass::detach(byte command) 549 | { 550 | switch (command) { 551 | case SYSTEM_RESET: currentSystemResetCallback = NULL; break; 552 | case STRING_DATA: currentStringCallback = NULL; break; 553 | case START_SYSEX: currentSysexCallback = NULL; break; 554 | default: 555 | attach(command, (callbackFunction)NULL); 556 | } 557 | } 558 | 559 | /** 560 | * @param pin The pin to get the configuration of. 561 | * @return The configuration of the specified pin. 562 | */ 563 | byte FirmataClass::getPinMode(byte pin) 564 | { 565 | return pinConfig[pin]; 566 | } 567 | 568 | /** 569 | * Set the pin mode/configuration. The pin configuration (or mode) in Firmata represents the 570 | * current function of the pin. Examples are digital input or output, analog input, pwm, i2c, 571 | * serial (uart), etc. 572 | * @param pin The pin to configure. 573 | * @param config The configuration value for the specified pin. 574 | */ 575 | void FirmataClass::setPinMode(byte pin, byte config) 576 | { 577 | if (pinConfig[pin] == PIN_MODE_IGNORE) 578 | return; 579 | 580 | pinConfig[pin] = config; 581 | } 582 | 583 | /** 584 | * @param pin The pin to get the state of. 585 | * @return The state of the specified pin. 586 | */ 587 | int FirmataClass::getPinState(byte pin) 588 | { 589 | return pinState[pin]; 590 | } 591 | 592 | /** 593 | * Set the pin state. The pin state of an output pin is the pin value. The state of an 594 | * input pin is 0, unless the pin has it's internal pull up resistor enabled, then the value is 1. 595 | * @param pin The pin to set the state of 596 | * @param state Set the state of the specified pin 597 | */ 598 | void FirmataClass::setPinState(byte pin, int state) 599 | { 600 | pinState[pin] = state; 601 | } 602 | 603 | // sysex callbacks 604 | /* 605 | * this is too complicated for analogReceive, but maybe for Sysex? 606 | void FirmataClass::attachSysex(sysexFunction newFunction) 607 | { 608 | byte i; 609 | byte tmpCount = analogReceiveFunctionCount; 610 | analogReceiveFunction* tmpArray = analogReceiveFunctionArray; 611 | analogReceiveFunctionCount++; 612 | analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction)); 613 | for(i = 0; i < tmpCount; i++) { 614 | analogReceiveFunctionArray[i] = tmpArray[i]; 615 | } 616 | analogReceiveFunctionArray[tmpCount] = newFunction; 617 | free(tmpArray); 618 | } 619 | */ 620 | 621 | //****************************************************************************** 622 | //* Private Methods 623 | //****************************************************************************** 624 | 625 | /** 626 | * Resets the system state upon a SYSTEM_RESET message from the host software. 627 | * @private 628 | */ 629 | void FirmataClass::systemReset(void) 630 | { 631 | byte i; 632 | 633 | waitForData = 0; // this flag says the next serial input will be data 634 | executeMultiByteCommand = 0; // execute this after getting multi-byte data 635 | multiByteChannel = 0; // channel data for multiByteCommands 636 | 637 | for (i = 0; i < MAX_DATA_BYTES; i++) { 638 | storedInputData[i] = 0; 639 | } 640 | 641 | parsingSysex = false; 642 | sysexBytesRead = 0; 643 | 644 | if (currentSystemResetCallback) 645 | (*currentSystemResetCallback)(); 646 | } 647 | 648 | /** 649 | * Flashing the pin for the version number 650 | * @private 651 | * @param pin The pin the LED is attached to. 652 | * @param count The number of times to flash the LED. 653 | * @param onInterval The number of milliseconds for the LED to be ON during each interval. 654 | * @param offInterval The number of milliseconds for the LED to be OFF during each interval. 655 | */ 656 | void FirmataClass::strobeBlinkPin(byte pin, int count, int onInterval, int offInterval) 657 | { 658 | byte i; 659 | for (i = 0; i < count; i++) { 660 | delay(offInterval); 661 | digitalWrite(pin, HIGH); 662 | delay(onInterval); 663 | digitalWrite(pin, LOW); 664 | } 665 | } 666 | 667 | // make one instance for the user to use 668 | FirmataClass Firmata; 669 | -------------------------------------------------------------------------------- /firmware/src/libs/firmata/Firmata.h: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.h - Firmata library v2.5.3 - 2016-06-18 3 | Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | See file LICENSE.txt for further informations on licensing terms. 12 | */ 13 | 14 | #ifndef Firmata_h 15 | #define Firmata_h 16 | 17 | #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ 18 | 19 | /* Version numbers for the protocol. The protocol is still changing, so these 20 | * version numbers are important. 21 | * Query using the REPORT_VERSION message. 22 | */ 23 | #define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes 24 | #define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes 25 | #define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases 26 | 27 | /* Version numbers for the Firmata library. 28 | * The firmware version will not always equal the protocol version going forward. 29 | * Query using the REPORT_FIRMWARE message. 30 | */ 31 | #define FIRMATA_FIRMWARE_MAJOR_VERSION 2 32 | #define FIRMATA_FIRMWARE_MINOR_VERSION 5 33 | #define FIRMATA_FIRMWARE_BUGFIX_VERSION 3 34 | 35 | /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for 36 | * the protocol version and the firmware version. 37 | */ 38 | #define FIRMATA_MAJOR_VERSION 2 // same as FIRMATA_PROTOCOL_MAJOR_VERSION 39 | #define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION 40 | #define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION 41 | 42 | #define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages 43 | 44 | // Arduino 101 also defines SET_PIN_MODE as a macro in scss_registers.h 45 | #ifdef SET_PIN_MODE 46 | #undef SET_PIN_MODE 47 | #endif 48 | 49 | // message command bytes (128-255/0x80-0xFF) 50 | #define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) 51 | #define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) 52 | #define REPORT_ANALOG 0xC0 // enable analog input by pin # 53 | #define REPORT_DIGITAL 0xD0 // enable digital input by port pair 54 | // 55 | #define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc 56 | #define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin 57 | // 58 | #define REPORT_VERSION 0xF9 // report protocol version 59 | #define SYSTEM_RESET 0xFF // reset from MIDI 60 | // 61 | #define START_SYSEX 0xF0 // start a MIDI Sysex message 62 | #define END_SYSEX 0xF7 // end a MIDI Sysex message 63 | 64 | // extended command set using sysex (0-127/0x00-0x7F) 65 | /* 0x00-0x0F reserved for user-defined commands */ 66 | #define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards 67 | #define ENCODER_DATA 0x61 // reply with encoders current positions 68 | #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq 69 | #define STRING_DATA 0x71 // a string message with 14-bits per char 70 | #define STEPPER_DATA 0x72 // control a stepper motor 71 | #define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request 72 | #define SHIFT_DATA 0x75 // a bitstream to/from a shift register 73 | #define I2C_REQUEST 0x76 // send an I2C read/write request 74 | #define I2C_REPLY 0x77 // a reply to an I2C read request 75 | #define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins 76 | #define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin 77 | #define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value 78 | #define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value 79 | #define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins 80 | #define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution 81 | #define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers 82 | #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info 83 | #define REPORT_FIRMWARE 0x79 // report name and version of the firmware 84 | #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop 85 | #define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler 86 | #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages 87 | #define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages 88 | // these are DEPRECATED to make the naming more consistent 89 | #define FIRMATA_STRING 0x71 // same as STRING_DATA 90 | #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST 91 | #define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY 92 | #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL 93 | 94 | // pin modes 95 | //#define INPUT 0x00 // defined in Arduino.h 96 | //#define OUTPUT 0x01 // defined in Arduino.h 97 | #define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode 98 | #define PIN_MODE_PWM 0x03 // digital pin in PWM output mode 99 | #define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode 100 | #define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode 101 | #define PIN_MODE_I2C 0x06 // pin included in I2C setup 102 | #define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire 103 | #define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor 104 | #define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders 105 | #define PIN_MODE_SERIAL 0x0A // pin configured for serial communication 106 | #define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin 107 | #define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse 108 | #define TOTAL_PIN_MODES 13 109 | // DEPRECATED as of Firmata v2.5 110 | #define ANALOG 0x02 // same as PIN_MODE_ANALOG 111 | #define PWM 0x03 // same as PIN_MODE_PWM 112 | #define SERVO 0x04 // same as PIN_MODE_SERVO 113 | #define SHIFT 0x05 // same as PIN_MODE_SHIFT 114 | #define I2C 0x06 // same as PIN_MODE_I2C 115 | #define ONEWIRE 0x07 // same as PIN_MODE_ONEWIRE 116 | #define STEPPER 0x08 // same as PIN_MODE_STEPPER 117 | #define ENCODER 0x09 // same as PIN_MODE_ENCODER 118 | #define IGNORE 0x7F // same as PIN_MODE_IGNORE 119 | 120 | extern "C" { 121 | // callback function types 122 | typedef void (*callbackFunction)(byte, int); 123 | typedef void (*systemResetCallbackFunction)(void); 124 | typedef void (*stringCallbackFunction)(char *); 125 | typedef void (*sysexCallbackFunction)(byte command, byte argc, byte *argv); 126 | } 127 | 128 | // TODO make it a subclass of a generic Serial/Stream base class 129 | class FirmataClass 130 | { 131 | public: 132 | FirmataClass(); 133 | /* Arduino constructors */ 134 | void begin(); 135 | void begin(long); 136 | void begin(Stream &s); 137 | /* querying functions */ 138 | void printVersion(void); 139 | void blinkVersion(void); 140 | void printFirmwareVersion(void); 141 | //void setFirmwareVersion(byte major, byte minor); // see macro below 142 | void setFirmwareNameAndVersion(const char *name, byte major, byte minor); 143 | void disableBlinkVersion(); 144 | /* serial receive handling */ 145 | int available(void); 146 | void processInput(void); 147 | void parse(unsigned char value); 148 | boolean isParsingMessage(void); 149 | /* serial send handling */ 150 | void sendAnalog(byte pin, int value); 151 | void sendDigital(byte pin, int value); // TODO implement this 152 | void sendDigitalPort(byte portNumber, int portData); 153 | void sendString(const char *string); 154 | void sendString(byte command, const char *string); 155 | void sendSysex(byte command, byte bytec, byte *bytev); 156 | void write(byte c); 157 | /* attach & detach callback functions to messages */ 158 | void attach(byte command, callbackFunction newFunction); 159 | void attach(byte command, systemResetCallbackFunction newFunction); 160 | void attach(byte command, stringCallbackFunction newFunction); 161 | void attach(byte command, sysexCallbackFunction newFunction); 162 | void detach(byte command); 163 | 164 | /* access pin state and config */ 165 | byte getPinMode(byte pin); 166 | void setPinMode(byte pin, byte config); 167 | /* access pin state */ 168 | int getPinState(byte pin); 169 | void setPinState(byte pin, int state); 170 | 171 | /* utility methods */ 172 | void sendValueAsTwo7bitBytes(int value); 173 | void startSysex(void); 174 | void endSysex(void); 175 | 176 | private: 177 | Stream *FirmataStream; 178 | /* firmware name and version */ 179 | byte firmwareVersionCount; 180 | byte *firmwareVersionVector; 181 | /* input message handling */ 182 | byte waitForData; // this flag says the next serial input will be data 183 | byte executeMultiByteCommand; // execute this after getting multi-byte data 184 | byte multiByteChannel; // channel data for multiByteCommands 185 | byte storedInputData[MAX_DATA_BYTES]; // multi-byte data 186 | /* sysex */ 187 | boolean parsingSysex; 188 | int sysexBytesRead; 189 | /* pin configuration */ 190 | byte pinConfig[TOTAL_PINS]; 191 | int pinState[TOTAL_PINS]; 192 | 193 | /* callback functions */ 194 | callbackFunction currentAnalogCallback; 195 | callbackFunction currentDigitalCallback; 196 | callbackFunction currentReportAnalogCallback; 197 | callbackFunction currentReportDigitalCallback; 198 | callbackFunction currentPinModeCallback; 199 | callbackFunction currentPinValueCallback; 200 | systemResetCallbackFunction currentSystemResetCallback; 201 | stringCallbackFunction currentStringCallback; 202 | sysexCallbackFunction currentSysexCallback; 203 | 204 | boolean blinkVersionDisabled = false; 205 | 206 | /* private methods ------------------------------ */ 207 | void processSysexMessage(void); 208 | void systemReset(void); 209 | void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); 210 | }; 211 | 212 | extern FirmataClass Firmata; 213 | 214 | /*============================================================================== 215 | * MACROS 216 | *============================================================================*/ 217 | 218 | /* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the 219 | * firmware name. It needs to be a macro so that __FILE__ is included in the 220 | * firmware source file rather than the library source file. 221 | */ 222 | #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y) 223 | 224 | #endif /* Firmata_h */ 225 | -------------------------------------------------------------------------------- /lib/kb_controller.js: -------------------------------------------------------------------------------- 1 | // sets up a simple controller using a keyboard interface to drive 2 | // the simplebot. Assumes two servos passed in as a left and right wheel 3 | // 4 | var keypress = require('keypress'); 5 | 6 | var Controller = function(opts) { 7 | 8 | // assume opts is a left and right wheel object. 9 | if (opts == undefined) { 10 | throw "No opts provided"; 11 | } 12 | 13 | // get the servos 14 | this.left = opts.left || null; 15 | this.right = opts.right || null; 16 | 17 | // set the stop values if needed 18 | this.LSTOPVAL = opts.lstop || 90; 19 | this.RSTOPVAL = opts.rstop || 90; 20 | 21 | if (this.left == null || this.right == null) { 22 | throw "Both servos must be supplied" 23 | } 24 | 25 | keypress(process.stdin); 26 | 27 | process.stdin.resume(); 28 | process.stdin.setEncoding('utf8'); 29 | process.stdin.setRawMode(true); 30 | 31 | console.log("Control the bot with the arrow keys, SPACE to stop, Q to quit."); 32 | 33 | process.stdin.on('keypress', function (ch, key) { 34 | 35 | if ( !key ) return; 36 | 37 | if ( key.name == 'q' ) { 38 | console.log('Quitting'); 39 | process.exit(); 40 | } else if ( key.name == 'up' ) { 41 | console.log('Forward'); 42 | this.left.cw(); 43 | this.right.ccw(); 44 | } else if ( key.name == 'down' ) { 45 | console.log('Backward'); 46 | this.left.ccw(); 47 | this.right.cw(); 48 | } else if ( key.name == 'left' ) { 49 | console.log('Left'); 50 | this.left.ccw(); 51 | this.right.ccw(); 52 | } else if ( key.name == 'right' ) { 53 | console.log('Right'); 54 | this.left.cw(); 55 | this.right.cw(); 56 | } else if ( key.name == 'space' ) { 57 | console.log('Stopping'); 58 | this.left.to(this.LSTOPVAL); 59 | this.right.to(this.RSTOPVAL); 60 | } 61 | }.bind(this) ); 62 | 63 | }; 64 | 65 | module.exports = Controller; 66 | 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplebot", 3 | "version": "0.5.2", 4 | "description": "A simple robotics platform designed to be used and built on a NodeBots Day event", 5 | "main": "examples/simplebot.js", 6 | "scripts": { 7 | "test": "echo \"No test currently specified\" && exit 0" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/nodebotsau/simplebot" 12 | }, 13 | "keywords": [ 14 | "nodebots", 15 | "johnny-five", 16 | "simplebot", 17 | "robots" 18 | ], 19 | "author": "Andrew Fisher", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/nodebotsau/simplebot/issues" 23 | }, 24 | "dependencies": { 25 | "color-string": "^1.2.0", 26 | "es6-collections": "^0.5.2", 27 | "johnny-five": "^1.0.0", 28 | "keypress": "^0.2.1", 29 | "temporal": "^0.7.0" 30 | }, 31 | "optionalDependencies": { 32 | "ble-io": "^0.1.0", 33 | "bleno": "^0.5.0", 34 | "nodebots-interchange": "^2.0.0", 35 | "udp-serial": "^0.2.0" 36 | }, 37 | "devDependencies": { 38 | "grunt": "^1.0.1", 39 | "grunt-cli": "^1.2.0", 40 | "grunt-contrib-clean": "^2.0.0", 41 | "grunt-contrib-copy": "^1.0.0", 42 | "grunt-exec": "^3.0.0", 43 | "grunt-string-replace": "^1.2.1" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /physical/layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nodebotsau/simplebot/19777ad49238954329ca9f42d58de3670f1851e8/physical/layout.png -------------------------------------------------------------------------------- /physical/plates-sbpi.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 48 | 61 | 62 | 64 | 66 | 67 | 69 | image/svg+xml 70 | 72 | 73 | 74 | 75 | 76 | 82 | 84 | 91 | 98 | 105 | 112 | 119 | 126 | 133 | 140 | 147 | 154 | 161 | 168 | 175 | 185 | 195 | 205 | 215 | 216 | 217 | 222 | 228 | 229 | 234 | 239 | 244 | 249 | 254 | 255 | 314 | 315 | -------------------------------------------------------------------------------- /utils/env_template.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # this is a template for setting the environment variables you need for things 4 | # like building etc so grunt can do what it needs to do if needed. 5 | 6 | export ARDUINO_PATH=~/Downloads/arduino.app/Contents/MacOS/Arduino 7 | 8 | --------------------------------------------------------------------------------