Multi-puck Game Howto?

Posted on
  • Hi @Gordon,

    one of the things I liked in the Kickstarter video (or was it some other Puck video?) was the multi-puck game where 4 Pucks were shown and you had to press on the one which was illuminated. I plan to do something similar, but the question is how was that done? So one master connecting to all the peripheral pucks? I am not 100% sure about how many connections the Puck can handle. Would that work? Or any other advise how it was done?

    Another question also interesting with the game: you write the power usage if BLE is advertising but the Puck is idle otherwise is 20 uA. So I would like the Pucks to be idle all the time until the button is pressed in which case it would start looking for other Pucks. If you do a setWatch is that still counting as idle? Or does it involve more power consumption. Measuring is a little bit tricky without soldering something to the Puck which I don't wanna do at this point. So maybe you know...


  • Idling is the easy part: It's built in by JavaScript (in the browser) and by @Gordon in the Espruino implementation:

    As opposed to the typical Arduino Loop, Espruino works on events in the hardware layer, which it puts into a queue, and when done with the time critical things in the hardware, it calls the JavaScript interpreter, which picks up the event information in the queue, until all are done, and then goes to (deep) sleep - idle...

    The example below toggles the red LED1 on each button BTN1 press:

    // toggle red LED1 with BTN1
    var isOn = false;
        isOn = ! isOn;
        digitalWrite(LED1, isOn);
      },{ repeat: true, edge: "rising", debounce:50 });

    Q? What does the setBusyIndicator(LED3); do?
    A: It shows you when the processor is busy - literally!

    You will notice that is flickers only very, very briefly, barely noticeable... and that's the time the system is active, otherwise it is in deep sleep - for fast processors it is like bears in winter hibernation...

    If you use the opposite approach - setSleepIndicator(LED2) to show when it is sleeping - your naked eye is still so blinded by the 'night sleep light that it does not notice the very, very, brief off-time while the processor is busy.

    Connecting-Disconnecting may not be what you want in the game, especially if you want a game for reaction between the players. It could provide random eventing / timing, but the time may just be too long...

    With the naked eye is great... because I tried to make a clip of above code upload and run... the red led shows so bright that the camera had just a red glare... and the blue busy indicator LED is not showing. Therefore, I thought first just to write just always 0 to the led, but analogWrite (PWM) comes in handy with 2% duty cycle:

    // toggle red LED1 with BTN1
    var isOn = false;
        isOn = ! isOn;
        analogWrite(LED1, (isOn) ? 0.02 : 0);
       ,{ repeat: true
       , edge: "rising"
       , debounce:50 });

    There are two clips added: red LED1 bright and dim. Both include an upload and two button presses (down-and-up, 4 click sounds - first switches the LED1 on, third switches it off). In both clips the upload activity is noticeable, but in the dim one only the LED1 off switching post activity of releasing the button is visible, which does not even include any JavaScript part...

    3 Attachments

  • Hi @allObjects, thanks for your comments, appreciated! But actually I knew about the sleeping part already. But in other microcontrollers (e.g. Attiny 45) actually waiting for an interrupt to happen on a certain pin will pull some extra current. So basically if you are in deep sleep and you do not wait for anything, it will only pull 0.1 uA. If you are waiting for a pin interrupt or wait for a timer, then you are at about 2 uA. So the question is if the 20 uA mentioned are still the case if a timer is set and a watch on a pin is set.

    About the connecting, disconnecting: I see that connecting to another Puck takes about 2 seconds as in the "controlling another puck" example. But when you stay connected it is very fast. But for a game like shown in the video, building up the connecting for every interaction would be too slow. So the Puck needs to be able to maintain multiple connections, I guess. Or some different method is used. For example I could imagine that the advertisement data is used and changed when something happens. That would not require a connection thus could maybe be fast. Not sure if it would work, just an idea...

  • @Stevie, in deed, by watching a pin, it needs some pull... if it is down, it should not draw any current... and staying in advertising mode, it is 2uA for most of the time, but uses some more for the advertisement, which by config has to happen at least once per 10 seconds according to Nordic's data sheet. With Nordic's tools you can calculate the average consummation which depends on the package size, but is roughly 3..4 uA, more though towards 3 uA - and this is with 4dbM transmission power. For very close range, transmission power can be reduced.

    Running a LED even for very short time though makes this consummation practically irrelevant... Even with running JavaScript, this consummation practically irrelevant... When connected, usage is of course higher, but still a fraction what running JavaScript code and more so what running a LED consumes.

    For the multi-connection, I assume, you can use the master and slave configurations. For standard Bluetooth, a master can be connected to 7 slaves at one time. I do not know about BLE... I see no reason why it should not be the same way...

  • @allObjects, 7 connections to slaves would be perfect. That would mean the game could have 8 players (if I had 8 Pucks :-) ).

    I am interesting in the current when advertising over BLE and listening on the button pin. That would be when the game is not used which could be for months. Then when someone wants to play the game they press the buttons on the Pucks which would be needed for the players (one for each player). They would wakeup, would connect to each other and then the game for be used for a while. Then when the game was finished they would go to sleep again, until next time someone wants to play. So the current in the idle situation is important.

  • As far as I know the current draw when using setWatch is basically the same 20uA as without. I actually test with a strip of flexible double-sided PCB stuck between the battery and the board, so you don't need soldering... You could probably hack something up with 2 bits of tin foil and some sellotape if you desperately wanted.

    In the demo I did for the KickStarter I actually had a Web Bluetooth webpage connected to all 4 Pucks - so in that case it wouldn't have run on its own. Again, that's something I'll try and do a tutorial for soon.

    The nRF52832 in Puck.js can handle multiple outbound connections (possibly only 4 though?), but at the moment you're limited to 1. Having more means you have to reserve more RAM at compile time - so less space for JS code for everyone :(

    However there are other ways of doing this. For example, you could have every Puck advertising whether it had been pressed or not (which doesn't use any noticeable power). One master Puck (or other device) could then be listening for the advertising packets, and could turn the next Puck on (by connecting) when the first one was pressed.

    Only gotcha there is to 'wake up' the game you'd have to tap the 'master' Puck first (since having it listening for advertising packets all the time would drain the battery) - but that's not a huge problem.

  • Hi @Gordon, thanks for the info. So I guess trying the advertisement way is something I will do next. And I will check the tin foil approach, that might be easiest, indeed.

    One thing I don't understand is how to use the Web Bluetooth with multiple Pucks. I did not find a way to connect to more than one from the same web page. Could you elaborate on that a bit?


  • Sure - with Web Bluetooth it's just a matter of calling the requestDevice function again, however with the Puck.js helper you have to use it in a slightly different way:­

    If you do:

    Puck.connect(function(connection) {
        if (!connection) throw "Error!";
        connection.on('data', function(d) { ... });
        connection.on('close', function() { ... });
        connection.write("1+2\n", function() {

    You'll get a 'connection' object (no need to call close on it) - you can then just do that again, and again, to connect to more devices. I think the max allowed might be 6.

    I don't think you can do that all from one function call - so what I did for the demo was I had a 'connect' button on the webpage. Click it once and it connects to a puck and adds it to an array, click it again and then you have 2 pucks in the array, and so on.

    I'll make a note to do a proper tutorial on it :)

  • Thanks, sounds perfect! I will try it out!

  • The nRF52832 in Puck.js can handle multiple outbound connections (possibly only 4 though?), but at the moment you're limited to 1. Having more means you have to reserve more RAM at compile time - so less space for JS code for everyone :(

    how much of a trade off are we talking about? how much code can compile now compared to what is possible with RAM reserved? does that depend on amount of connections?

  • It looks like it's 1200 bytes per connection - so pretty hefty. You have 2250 variables now, and you'd lose roughly 80 per extra connection. I think allowing >1 is definitely possible, but many more than 2 would be hard to justify I think.

    It would also need a few code changes needed to take advantage of it, since certain bits of code assume only one connection.

  • very interesting to me,
    technically 2 is all one needs to create a sort of 'mesh' network and make multi puck implementations.
    we are working with an artist which wants to prototype a toy that displays data structures­design/מאיה-יזרעאלי/
    she is a double major [industrial design and computer science].
    we are trying to make the toy 'smarter' by making each 'data' self aware.
    we really wanted to start exploring this in the Espruino environment but we need to use multiple pucks which can send data between each other.

  • I'd look at maybe using advertising? You don't need an active connection to other Espruinos to transfer data - it could be as simple as:

    NRF.setScan(function(d) {
      if (d.manufacturer!=0x590) return;
      // otherwise use d.manufacturerData

    This would increase power usage, but you could always use NRF.findDevices(..., 500) every few seconds so you're not listening all the time.

    The nice thing about that is there's no limit to the amount of devices you can have.

    There is a Bluetooth Mesh spec that hopefully will get implemented at some point soon, but it actually works in a very similar way to the above code under the hood.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

Multi-puck Game Howto?

Posted by Avatar for Stevie @Stevie