diff --git a/README.md b/README.md index efdc4e4..d906654 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,17 @@ This was developed for a workshop for Makerland Conference. If I was smarter, I `npm start` - to run the electron version `npm run webserver` - to run the web version `npm run dev` - to run the web version with nodemon and asset recompilation + +## Blocks currently supported + +These blocks directly map to Johnny-Five components: + +* Button +* Led +* Led.RGB +* Motor +* Sensor +* Servo +* Thermometer + +Additional robotnik blocks which are diff --git a/lib/codeRunner.js b/lib/codeRunner.js index c4b11f9..057b4f9 100644 --- a/lib/codeRunner.js +++ b/lib/codeRunner.js @@ -18,12 +18,25 @@ CodeRunner.prototype = { this.child = childProcess.fork('./lib/codeRunnerContainer'); this.send( 'code', code ); - this.child.on('message', function(data) { + this.child.on('message', (data) => { // we use this to grab the message from the child process - this.emit("consoledata", { - data: stripAnsi(data) - }); - }.bind(this)); + if (typeof data.context != 'undefined') { + // regardless it's an uncaught error so kill the process. + + this.stop(); + + if (data.context.class == 'Device or Firmware Error') { + // this is an issue with the connection. Reset. + this.emit('consoledata', { + data: 'firmwareConnectionError' + }); + } + } else { + this.emit("consoledata", { + data: stripAnsi(data) + }); + } + }); }, @@ -43,7 +56,14 @@ CodeRunner.prototype = { * @param {string} state - either 'up' or 'down' */ controlEvent: function( button, state ) { - this.child.send({ button: button, state: state }); + if (this.child) { + if (button == 'stop' && state == 'fired') { + console.log("Process stop"); + this.stop(); + } else { + this.child.send({ button: button, state: state }); + } + } }, @@ -55,7 +75,9 @@ CodeRunner.prototype = { */ send: function(type, data) { // TODO : Check to see if child is running - this.child.send({ type: type, data: data }); + if (this.child) { + this.child.send({ type: type, data: data }); + } } }; diff --git a/lib/codeRunnerContainer.js b/lib/codeRunnerContainer.js index dfbbb4c..434eaf9 100644 --- a/lib/codeRunnerContainer.js +++ b/lib/codeRunnerContainer.js @@ -25,3 +25,7 @@ process.on('message', function(message) { } }); +process.on('uncaughtException', (err) => { + process.send(err); +}); + diff --git a/package.json b/package.json index 4298e69..f0f8143 100644 --- a/package.json +++ b/package.json @@ -55,14 +55,14 @@ "express": "^4.13.4", "font-awesome": "^4.5.0", "intercept-stdout": "^0.1.2", - "johnny-five": "^0.9.38", + "johnny-five": "^0.10.6", "jquery": "^2.1.4", "js-beautify": "^1.5.5", "lodash": "^4.11.1", "pouchdb": "^3.4.0", "pouchdb-find": "^0.3.4", "serialport": "^2.1.0", - "socket.io": "^1.4.5", + "socket.io": "^1.7.3", "strip-ansi": "^3.0.1" }, "devDependencies": { diff --git a/static/js/src/components/exercise/exercise.html b/static/js/src/components/exercise/exercise.html index 2531f46..897e540 100644 --- a/static/js/src/components/exercise/exercise.html +++ b/static/js/src/components/exercise/exercise.html @@ -13,5 +13,11 @@

{{vm.exercise.description}}

- + + +
+ +

+ See full exercise notes +

diff --git a/static/js/src/components/running-controls/running-controls.js b/static/js/src/components/running-controls/running-controls.js index 888d942..a427874 100644 --- a/static/js/src/components/running-controls/running-controls.js +++ b/static/js/src/components/running-controls/running-controls.js @@ -45,6 +45,21 @@ export default function(commands) { this.runningStatus = "Now running"; $scope.$apply(); } + + if (consolestr.search("firmwareConnectionError") >= 0) { + this.runningStatus = "Firmware timeout. Stop, check, run code again"; + var msg = "The connection to the firmware has timed out. "; + msg += "Please check the following:\n\n"; + msg += " - If using USB, check the cable is plugged in\n"; + msg += " - If using bluetooth, check TX/RX is correct\n"; + msg += " - If using bluetooth, make sure you're not also using USB\n"; + msg += "\n"; + msg += "Intermittent connections may also occur with Bluetooth in noisy environs.\n\n"; + msg += "Check the above then hit the 'stop' button, check your code and try to 'Run' again."; + window.alert(msg); + + $scope.$apply(); + } console.log(consolestr); } }.bind(this)); @@ -105,8 +120,9 @@ export default function(commands) { function stop(scope) { return function() { scope.show = false; + console.log("Sending a control stop"); this.runningStatus = "Waiting for connection..."; - commands.send( 'control', 'stop' ); + commands.send( 'control', ['stop', 'fired'] ); } } } diff --git a/static/js/src/components/workshop/workshop.js b/static/js/src/components/workshop/workshop.js index 20729fc..7a50803 100644 --- a/static/js/src/components/workshop/workshop.js +++ b/static/js/src/components/workshop/workshop.js @@ -23,14 +23,14 @@ export default function($timeout, $stateParams, code, blockly, Workspaces) { function selectBlocks() { this.selected = 'blocks'; // trigger a redraw to get everything to render again properly - Blockly.fireUiEvent(window, 'resize'); + window.dispatchEvent(new Event('resize')); } function selectCode() { this.selected = 'code'; this.code = code.generate(); // trigger a redraw to get everything to render again properly. - Blockly.fireUiEvent(window, 'resize'); + window.dispatchEvent(new Event('resize')); } function restoreWorkspace(workshopId) { diff --git a/static/js/src/services/blockly.js b/static/js/src/services/blockly.js index c764cc6..5a9efc6 100644 --- a/static/js/src/services/blockly.js +++ b/static/js/src/services/blockly.js @@ -41,11 +41,13 @@ export default function(Workspaces) { robotnikGenerator.init(); robotnikBlocks.init(); + Blockly.inject(canvas, { path: './vendor/blockly/', toolbox: toolbox.xml, trashcan: true }); + } function code() { diff --git a/workshops/mkw.json b/workshops/mbot.json similarity index 94% rename from workshops/mkw.json rename to workshops/mbot.json index 33d9dfa..f3b6d4f 100644 --- a/workshops/mkw.json +++ b/workshops/mbot.json @@ -1,7 +1,7 @@ { - "_id": "mkw", - "title": "Melbourne Knowledge Week 2016, NodeBots workshop", - "description": "This is the workshop for programming mBots", + "_id": "mbot", + "title": "Programming a makeblock mBot", + "description": "Program an mBot using Robotnik", "board": "uno", "board_opts": "", "components": [ @@ -81,9 +81,6 @@ { "name": "Blink an LED", "description": "First, try to make the little Blue LED (an actuator) blink when you push a button. Can you change the speed of the blinking? Can you stop it when you release the button?", - "board_opts": { - "port": "/dev/cu.wchusbserial1410" - }, "components": [ "led13" ] diff --git a/workshops/sciencekit.json b/workshops/sciencekit.json new file mode 100644 index 0000000..bf21cf9 --- /dev/null +++ b/workshops/sciencekit.json @@ -0,0 +1,176 @@ +{ + "_id": "sciencekit", + "title": "Arduino Scientist Kit", + "description": "Learn how various electronics components work", + "board": "uno", + "board_opts": "", + "components": [ + { + "name": "lightSensor", + "class": "Sensor", + "config": { + "pin": "A0", + "freq": 200 + } + }, + { + "name": "thermometer", + "class": "Thermometer", + "config": { + "pin": "A1", + "freq": 200, + "controller": "LM35" + } + }, + { + "name": "button", + "class": "Button", + "config": { + "pin": "2" + } + }, + { + "name": "servo", + "class": "Servo", + "config": { + "pin": "4", + "type": "standard" + } + }, + { + "name": "RGBLED", + "class": "Led.RGB", + "config": { + "pins": { + "red": 3, + "green": 5, + "blue": 6 + } + } + }, + { + "name": "led09", + "class": "Led", + "config": { + "pin": "9" + } + }, + { + "name": "led10", + "class": "Led", + "config": { + "pin": "10" + } + }, + { + "name": "led11", + "class": "Led", + "config": { + "pin": "11" + } + } + ], + "workshop_blocks": [ + { + "name": "while_button", + "category": "controller" + }, + { + "name": "console_log_value", + "category": "value" + }, + { + "name": "math_number", + "category": "value" + }, + { + "name": "text", + "category": "value" + } + ], + "exercises": [ + { + "name": "Blink an LED", + "description": "Make the LED connected to pin 11 (an actuator) turn on and off when you press the button on the screen. Once you have this working, can you make it fade in and out?", + "components": [ + "led11" + ], + "diagram": "https://raw.githubusercontent.com/ajfisher/robotnik-workshop/master/exercises/images/led_bb.png", + "link": "https://github.com/ajfisher/robotnik-workshop/blob/master/exercises/led.md" + }, + { + "name": "Move a servo", + "description": "Make the servo (an actuator) attached to pin 4 change position as you press and release the green button?", + "components": [ + "servo" + ], + "diagram": "https://raw.githubusercontent.com/ajfisher/robotnik-workshop/master/exercises/images/servo_bb.png", + "link": "https://github.com/ajfisher/robotnik-workshop/blob/master/exercises/servo.md" + }, + { + "name": "Read the light level", + "description": "Take a reading from the light sensor (a sensor) and write the value out to the console. You'll have to watch the code console to see the data. What happens when you put your fingers over the sensor and remove it?", + "components": [ + "lightSensor", "led11" + ], + "exercise_blocks": [ + { + "name": "controls_if", + "category": "logic" + }, + { + "name": "logic_compare", + "category": "logic" + } + ], + "diagram": "https://raw.githubusercontent.com/ajfisher/robotnik-workshop/master/exercises/images/photoresistor_bb.png", + "link": "https://github.com/ajfisher/robotnik-workshop/blob/master/exercises/photoresistor.md" + }, + { + "name": "Temperature light", + "description": "Take a reading from the temperature sensor and then use the temperature reading to set the RGB LED to blue if it's cold, orange if warm and red if hot.", + "components": [ + "RGBLED", "thermometer" + ], + "exercise_blocks": [ + { + "name": "controls_if", + "category": "logic" + }, + { + "name": "logic_compare", + "category": "logic" + } + ], + "diagram": "https://raw.githubusercontent.com/ajfisher/robotnik-workshop/master/exercises/images/temperature-lm35_bb.png", + "link": "https://github.com/ajfisher/robotnik-workshop/blob/master/exercises/temperature.md" + }, + { + "name": "Light switch", + "description": "Take a reading from a button (a sensor) and then make that turn the LED on pin 11 on or off. ", + "components": [ + "button", "led11" + ], + "diagram": "https://raw.githubusercontent.com/ajfisher/robotnik-workshop/master/exercises/images/button_bb.png", + "link": "https://github.com/ajfisher/robotnik-workshop/blob/master/exercises/button.md" + }, + { + "name": "Free play", + "description": "You can use all of the components now to come up with something", + "components": [ + "button", "thermometer", "led09", "led10", "led11", "RGBLED", "lightSensor", "servo" + ], + "exercise_blocks": [ + { + "name": "controls_if", + "category": "logic" + }, + { + "name": "logic_compare", + "category": "logic" + } + ] + } + ] +} +