Close

Blockly - Activities

A project log for 8BitRobots Module

A common hardware, software and 3D printed module to enable fun, educational robots anyone can print and program.

tim-wilkinsonTim Wilkinson 05/09/2018 at 05:450 Comments

Although I've chosen Blockly as the visual programming language for 8BitRobots, I've been toying with various application styles for writing code. The Arduino style is very appealing; set stuff up then run continually until the power goes away. In Blockly this looks something like this:

Above we have two Activites each with a setup and then an activity. Neither here has a setup, but any blocks would be run once before any activity loops starts. The activity loops continually, but unlikes an Arduino program, only run when changes in the system are detected. To eliminate timing issues and races, the observed state of the system is constant during the execution of each activity loop, and to keep things optimal, the activities only run when relevant changes are detected (ie. if the code doesn't read the output of the IMU, then it won't run when it changes).

Code generation is a little more complex than traditional Blockly with the visual program being split into a set of Javascript configuration and activity pieces.  Additionally, because writing to hardware services is an inherently asynchronous operation (the hardware may be physically separate from where the code runs), the code makes use of the Javascript async/await/promise mechanisms (Node 7+). Ultimately this is all hidden from the Blockly developer.

VM.runInNewContext(
 code,
 {
  App:
  {
   registerActivity: (activity) => { this._registerActivity(activity); },
   registerConfiguration: (configuration) => { this._registerConfiguration(configuration); },
   run: () => { this._runApp(); },
   get: (topicName, key) => { return this._getTopicValue(topicName, key); },
   subscribe: (topicName) => { this._subscribeToTopic(topicName); },
   sync: (id, status) => { return this._syncTopicUpdates(id, status); },
   status: () => { return this._status; },
   call: (serviceName, arg) => { return this._callService(serviceName, arg); },
   part: (partName, arg) => { return this._callPart(partName, arg); },
   print: (msg) => { this._debugMessage(msg); }
  }
 }
);

The compiled Blockly code is run inside a VM context which exposes a limited API to the main system. In the above sync() is what an activity calls to wait for system changes, call() is used to make changes to the hardware services, and get() reads the system state. These three calls are probably 99.9% of what a Blockly app calls. For more information see the GitHub repository (https://github.com/aanon4/8bitrobots).

Discussions