Gratis verzenden in NL & BLG > 25 Euro

Maak Extensies voor mBlock

September 28, 2016 0 Opmerkingen

Create Extensions for mBlock

In this tutorial you will learn:

  • define new blocks for your Arduino-based hardware in mBlock
  • package and import an extension in mBlock

An Anatomy of mBlock's Extension System

The best way to understand an extension is read an example. Using "Extensions/Manage Extensions" menu item, you can click on "View Source" of system built extensions and study how they are written.

Manage-extension-menu-item.png

An extension need to response at lease one to two modes:

  • "online mode”: this means when the blocks are "executed" in mBlock interface, what message the computer should send to your micro-controller board.
  • "offline mode" or "arduino mode": this means what Arduino code the blocks you defined will generate when your program is being "uploaded to Arduino".

This is done by implementing these components:

  • .s2e file: the definition of blocks and what Arduino code will they generate;
  • .h and .cpp files in src/ folder: additional files that will can be included and will be linked in "Arduino mode".
  • Javascript files in js/ folder: defines the behavior of "online mode";

Writing Block Definitions (.s2e file)

Imagine you are writing an extension named "Demo" that will:

  • send digital outputs to Arduino in both "online" and "Arduino" modes;
  • blink Arduino's LED through a custom function

First of all, you need to write an .s2e file (in plain text format) telling the name, description, and block definitions of your extension:

// content of demo.s2e
{  
  // the name of your extension  
  "extensionName": "Demo",    

  // the order the extension will be displayed in mBlock  
  "sort":0,    

  // the path to Javascript file in Online mode  
  "javascriptURL":"js/demo.js",    

  // the networking port used in the extension. 0 for serial port  
  "extensionPort":0,   

  // firmware version for online mode  
  "firmware":"1.0",    

  // a javascript array defining block definitions.  
  "blockSpecs": [    
    ["h","Demo Program","runArduino"],    
    [  
      // block type. "h" for events ("header"),“w” for writing,“r” for synchronous reading; "R" for asychronous reading  
      "w",    

      // text to be displayed in the block,%n for number type,%d.digital will display a dropdown menu, and the menu items are defined in a section below.  
      "digitalWrite( %n , %d.digital )",   
        
      // the javascript function will be executed when the block is run  
      "digitalWrite",   

      // the default value of the first parameter  
      "13",   

      // the default value of the second parameter  
      "HIGH",   

      // this javascript array defines how Arduino code will be generated  
      {      
          // the code to be inserted into Arduino's "setup()" function. This code will be inserted only ones for multiple blocks of the same type  
          "setup":"pinMode({0},OUTPUT); \n",   

          // the code to be inserted to the "include"section. eg. #include <arduino.h>; insert once for multiple blocks  
          "inc":"",  

          // the code used to define additional variables, eg. double _num = 0; insert once for multiple blocks    
          "def":"",   

          // the code which the block will be translated into  
          "work":"digitalWrite({0},{1});\n",   

          // the code that will be inserted (once) in the loop section  
          "loop":""    
      }],  
      [  
          "w",  
          "blink",  
          "blink",  
          {  
              "setup":"",  
              "inc":"#include \"demo.h\"",  
              "def":"DemoClass demo; \n",  
              "work":"demo.blink(); \n",  
               "loop":""  
           }  
        ]  
     ],  

    // defines menu items  
     "menus": {  
        "digital":["HIGH","LOW"]   
     },  

     // translate strings to integers in Arduino code generation  
     "values":{  
          "HIGH":1,   
          "LOW":0  
      },  

     // if you want to translate your block into other languages, definitions are given here (Chinese in example)  
     "translators":{  
         "zh_CN":{    
            "Demo Program":"演示程序",  
            "HIGH":"高电平",  
            "LOW":"低电平",  
            "digitalWrite( %n , %d.digital )":"数字口输出( %n ,%d.digital )",  
            "blink":"闪烁"  
         }  
      }  
}  
</arduino.h>

Include additional files for Arduino Compiling

You may create a src/ folder in your extension to store additional .h and .cpp files for Arduino compiling. They will be automatically copied to the destination folder when compiling the mBlock generated Arduino code.

Write Javascript Files for Online Execution

If you want your blocks to be executed in mBlock's environment, you need to write this part. It is written in plain Javascript.

The core part of the code is implementing the functions corresponding to the blocks you defined.
You may use device.send to send an array of integers as bytes to the device.

ext.runArduino = function(){        
};

ext.digitalWrite = function(pin,level) {
        device.send([pin, levels[level]]);
};

ext.blink = function(){
    device.send([0x22, 0x23]);
}

When the serial port receives bytes, this function will be called:

function processData(bytes) {
        // Do something with the bytes received
}

You need to write an Arduino program and upload it to Arduino boards in order to process the communication between your board and the computer.

Here is the full list of the boilerplate code:

(function(ext) {
    var device = null;

    var levels = {
        HIGH:1,
        LOW:0
    };

    ext.resetAll = function(){};

    ext.runArduino = function(){

    };
    ext.digitalWrite = function(pin,level) {
        device.send([pin, levels[level]])
    };
    ext.blink = function(){
        device.send([0x22, 0x23])
    }

    function processData(bytes) {
        // Do something with the bytes received
    }

    // Extension API interactions
    var potentialDevices = [];
    ext._deviceConnected = function(dev) {
        potentialDevices.push(dev);

        if (!device) {
            tryNextDevice();
        }
    }

    function tryNextDevice() {
        // If potentialDevices is empty, device will be undefined.
        // That will get us back here next time a device is connected.
        device = potentialDevices.shift();
        if (device) {
            device.open({ stopBits: 0, bitRate: 115200, ctsFlowControl: 0 }, deviceOpened);
        }
    }

    function deviceOpened(dev) {
        if (!dev) {
            tryNextDevice();
            return;
        }
        device.set_receive_handler('demo',function(data) {
            processData(data);
        });
    };

    ext._deviceRemoved = function(dev) {
        if(device != dev) return;
        device = null;
    };

    ext._shutdown = function() {
        if(device) device.close();
        device = null;
    };

    ext._getStatus = function() {
        if(!device) return {status: 1, msg: 'demo disconnected'};
        return {status: 2, msg: 'demo connected'};
    }

    var descriptor = {};

    // Register the extension to Scratch Extension System.
    ScratchExtensions.register('demo', descriptor, ext, {type: 'serial'});
})({});

Package and load an extension

The full example mentioned above can be downloaded here.
After finishing your extension, you can simply compress it in a .zip file and distribute it as you wish.

To load an extension into mBlock, simply select "Extensions/Manage Extensions" menu item, click "Add Extension", and find the .zip file you wish to load into the system. Then you can see the blocks you designed listed in the "Robots" section.

Extension Manager

Loading



Bestel je cadeau's op tijd !

Makeblock Shop - Educational STEM and STEAM Open-Source Robots with Arduino and Scratch. Maker of mBot, Starter Robot, mBot Ranger, Ultimate Robot, Airblock, Neuron and LaserBot.