Rube Goldberg Project
The idea for the project is setting up a Rube Goldberg machine across all the tables in the CoderDojo. I can certainly imagine how we can set up a marble run that at the end trips a switch, that pushes a minecart in a Minecraft world, that triggers a servo to push another marble down another run into a different Minecraft world and so on. Throw into that mix clever things that the Raspberry Pi table can do, arduino hacks, and a scratch-to-physical world interface triggering an animated Rube Goldeberg machine, and we have a whole heap of awesomeness.
Session #2 Machine Running Order
In session #2 (8th June 2014) we're hoping to get a bigger machine plugged together. You can see a video about the plan here on YouTube.
This is the proposed order:
- Button press/bell rope triggers the Big Trak to start going
- Big Trak hits button to trigger Minecraft #1
- End of Minecraft #1 sends Twilio message to phone on vibrate mode on see-saw
- See-saw triggers physical interaction #1
- The end of physical interaction #1 triggers a Scratch animation
- The end of the Scratch animation triggers Minecraft #2
- The end of Minecraft #2 triggers the laptop CD-drawer to open (possibly using a http request to a web server running on the laptop)
- The CD-drawer opening triggers physical interactions #2
- The physical interaction #2 ends with the water level in the jug of water being raised completing the circuit being monitored on the ardunio
- The ardunio circuit closing kicks of Minecraft #3
- End of Minecraft #3 trigger the physical system to trigger the Sharp project doors opening
Rube Goldberg Machine Controller
Controlling the interactions on the Rube Goldberg machine will be a Raspberry Pi running some custom written software to link the real-world and virtual-world elements together. Below are some details about the controller software.
The GitHub project https://github.com/davegoopot/rube-mc-pi is the python source code that will run the Raspberry Pi to control all of the Rube Goldberg machine parts.
To run the code, checkout the code from GitHub, edit the config.json file to match your required configuration, then with Python 2.7 run...
The design of the code is to match "source" objects to "target" objects. The source represents something being monitored for state changes. The target object represents something that will have its state updated in response to changes in the linked source object. The state is represented as being a Minecraft Block object as defined in the mcpi.Block class. In non-Minecraft settings the Block object can be thought of as simply a python object with two attributes "id" and "data". Both objects are expected to be unsigned 8-bit integers. The id attribute is mandatory. The data attribute is optional and should be defaulted to 0 if not intended to be used.
The different input and output sources for the Rube Goldberg machine (minecraft, GPIO, scratch, arduino, etc.) need to have their interface implemented as plugins to be used by the controller. Plugins must obey the following interface specification:
Each plugin should be implemented in its own python module. For a plugin called "dave" the module should be "dave.py". Within the module the plugin should implement a source and a target class. These classes must be called "DaveSource" and "DaveTarget" respectively
(2) Class Construction
The source class must inherit from rube.Source. The source class must implement a constructor that accepts a dictionary of attributes. These attributes will have been passed from the JSON config file. Finally the constructor must call the constructor of the super class before carrying out its own initialisation. So for our example the start of the the class DaveSource looks like this:
class DaveSource(rube.Source): def __init__(self, attribs): super(DaveSource, self).__init__() #code to set up the DaveSource object goes here
The target class follows the same pattern, this time inheriting from rube.Target. The example DaveTarget class would start like this:
class DaveTarget(rube.Target): def __init__(self, attribs): super(DaveTarget, self).__init__() #code to set up the DaveTarget object goes here
(3) Source object poll_state()
The source object must implement the poll_state(self) method that returns an object following the mcpi.Block interface of having id and data attributes.
(4) Target update_state()
The target object must implement the update_state(self, block) method to set the state of the target object in response to the source having just changed state to that represented by the block object. Again the block object must implement the mcpi.Block id and data attributes.
Take a look at the "mock2.py" class for a really simple example of a plugin. See https://github.com/davegoopot/rube-mc-pi/blob/master/mock2.py