• Conversation about Help for Newbie. LED lights for game board by @ser96445 (@user96449) made me dig up the Neopixles that I got as part of the Espruino PICO Kickstarter reward and some other scraps and make a prototype show the status of a reaction game. So fare I did not neopixel yet (from 'to neopixel'). The perfect opportunity to put these forgotten 4-legged 5mm round neopixel LEDs finally to work has just come.

    A clip shows you the last - 4th - race step of the last - 3rd - race of a game. These are the events:

    1. both users' horses have already won two races,
    2. horses are in 3rd and 4th of the total 5 positions
    3. game host starts race step by pushing game control button
    4. flickering for the step goes on and stops
    5. user 0 - top lane / left button - is 1st to press button and horse wins step
    6. horse's next race position lights up with previous position still lit
    7. race win AND game win is detected and game's race wins only show
    8. game host starts new game (showing different colors)
    9. horses are back in start positions of first race in new (next) game
    10. game host starts race step
    11. user 1 - bottom lane / right button - user's horse wins step and advances

    If event 7 would have been race win only, briefly only last LED for position and LED for wins would have been lit and game would have resumed with event 9: players' horses back in start position of next race.

    A user pressing too early the button is shamed with lane fully lit. Race step is repeated.


    3 Attachments

  • Some more details about the setup:

    Choice of Espruino board: see Espruino-WiFi - is a nice, fully featured board with integrated Wifi connectivity thru espressif's ESP8266 ESP-12, mounted on the bottom of Espruino-Wifi board, prewired, and with blue LED3 on top showing Wifi status/activities. Can work as connecting station and also as ACCESS station that can be connected to. Espruino can run Web client AND/OR http Web server on http(s) protocol level and on socket level. (Wifi could be used to implement Web Server for publishing game status or playing distributed game over the Web. :O....... 21 GPIO 5V tolerant pins are plenty for a lot to do... Further on board: red LED1 and green LED2 and Btn/Btn1 for application. Power supply is thru USB or Bat_in pin (3.3..5V) and onboard w/ LDO 3.3V voltage regulator. --- Any other Espruiono board would do well as well... even Espruino Puck.js... ...with some soldering to get enough pins connected.

    Neopixel are individual, 4-lead, 5mm round, diffused LEDs w/ red, green and blue LEDs and electronic built in:

    1. longer lead - Data Out - DO
    2. longer lead - Ground - GND
    3. shorter lead - 5V - VDD
    4. shorter lead - Data In - DI

    Neopixels are daisy chained in zig-zag pattern: even lanes - counting from 0 - (top lane) runs from left to right, odd lanes (bottom lane) run from right to left. I intentionally made it this way to develop the software for the prewired string on the market. Top lane is fed with 2*5*3 bytes representing the RGB colors for each of the neopixels.

    Buttons are connected in "pull pin to Ground" manner to one pin of Espruino-Wifi set in "input_pullup" pin mode, pulled up by mc chip internal 30..40k resistor. Some buttons are watched directly and individually and some only summarily and indirectly and and only read together.

    The game host's button is at times watched with rising flank detection to initiate race step and a new game. The user buttons are not watched, but a or-logic with diodes creates a combined signal for a watched pin with falling flank detection to trigger prematurely or timely read of all user inputs at once - (virtually) at the very same time by value = digitalInput(<arrayOfPins>); ( @Gordon would know the ns between the reads, if there are... I'm sure not relevant for the game... lest the precision of the buttons... or their tolerances).

    Neopixel signal time precision is crucial because Neopixel LEDs are picky... and it is noticeable, especially when running rainbow wave through the LEDs before each game: sometimes some LEDs show messed up or no color at all... The 'fat' capacitor helped, but there are still some glitches.

    Below is The Code. To be upfront: I'm not a game developer... this is about the 2nd or 3rd game in my career - so not much treasure to find. Nor is the code structured to my desire or performance optimized: so far it is a big pile of functions - close to a treason to my screen name (sure, I was thinking in objects, but the functions have to still find their 'class' home... and some have to split for that). The code came together as I went and explored aspect by aspect. For certain things a nice oo-refactoring with consideration of performance is advised - especially when thinking of driving large(r) boards. On the other hand I'm pleased by t as a prototype. It works as originally intended... and even ended up as a simpler implementation then I had anticipated, especially in regard of game control and game status communication. BUT: UX's writing is already on the wall: allow users to pick their lane color... and let them keep it across games...

    // derby9.js
    // derby race board w/ neopixels:
    // - shows in bright current race pos
    // - shows in low race wins
    // game is a reaction game where users have to press button
    // when flickering of two LEDs stops; first pressing player
    // advances one step in race; if pressed too early, user is
    // 'blamed' (but not punished yet) and race step is repeated;
    // race steps are started by game host w/ game control button;
    // number of users, lanes, positions, races per game are all
    // configurable, and so are the times for the game states,
    // mainly times for displaying a particular game state.
    
    // dev stuff - lgo = logging on
    var lgo = false; // set to false before upload for saving
    function log() { console.log.apply(console,arguments); }
    
    // get hold of neopixel string handler
    var npxs = require("neopixel");
    
    // --- wireings setup externalized to easy adjust to board in use
    // Espruino-Wifi wireings for board
    var npxp            = B15  // neopixel feed pin
      , gameControlBtn  =  A0  // game flow control
    // Espruino-Wifi wireings for game
      , flickerLED1P    = LED1 // pin flickering LED 1
      , flickerLED2P    = LED2 // pin flickering LED 2
      , playerInputSumP =  A1  // any player input ('or' irq by diodes)
      , playerInputP0   =  A4  // 1st player input direct
      , playerInputP1   =  A5  // 2nd player input direct
      , playerInputPs   =      // all player inputs (LSB last)...
        [ playerInputP1        // ...to capture all at once when...
        , playerInputP0        // ...any player input watch fires
        ]
      ;
    // --- some declarations to make it flexible
    var maxPos    =  5 // reaching this position means win
      , maxLanes  =  2 // number of horses / lanes
      , playerCnt =  maxLanes // for now, later can be less
      ;
    
    // --- player data
    var players; // array of players w/ details - see raceInit()
    
    // --- game parameters
    var racesToWin  =    3 // win this races to win game
      , flickerFix  =  500 // flicker fix for this ms with additional 
      , flickerVary = 5000 // 0..this ms random range variably
      , flickerLEDV =  300 // flicker individual LED random range
      , blameTime   = 3000 // show/blame players pressed too ealry ms
      , stepWinTime = 2000 // show step win for ms
      , raceWinTime = 4000 // show race win incl step win for ms
      ;
    
    // --- setup neopixel data buffers (3 bytes per pixle)
    var npxb = new Uint8ClampedArray(maxLanes*maxPos*3)
    // --- overlay buffer and control
      , ovrb = new Uint8ClampedArray(maxLanes*maxPos*3)
      , ovrc = new Uint8ClampedArray(maxLanes*maxPos)
      ;
    
    // --- 256 colors from wheel for effects / other things
    //     3 bytes for each color, which means 768 bytes total
    //     colors / bytes picked by index (0..255*3) +0, ..+1, ..+2
    var clrs = new Uint8ClampedArray(256*3)
      , dimd = 0.05 // dimmed
      ;
    
    var raceCnt;
    function initGame() {
      flickerStop();
      if (gameCntrlWId) gameCntrlWId=clearWatch(gameCntrlWId);
      if (playerWId   ) playerWId   =clearWatch(playerWId   );  
      raceCnt = 0;
      players = []; 
      for (var pdx=0;pdx<playerCnt;pdx++) {
        var b = Math.floor(Math.random()*256);
        players.push(  // Player detail:
          {idx:pdx     // - player index 0...playerCnt-1
          ,racePos:-1  // - pos in current race 0..maxPos-1
          ,winCnt:0    // - race wins
          ,negPoints:0 // - sum of negative points / not used yet
          ,rClrs:[clrs[b],clrs[b+1],clrs[b+2]] // - race pos clrs
          ,gClrs:[dim(clrs[b])   // - game clrs (dimmed pos clrs)
                 ,dim(clrs[b+1]) //   show race wins (winCnt)
                 ,dim(clrs[b+2])
                 ]
          }); }
      initRace();
    }
    
    function initRace() {
      raceCnt++;
      for (var pdx=0;pdx<playerCnt;pdx++) {
        var player = players[pdx];
        player.racePos = 0;
      }
      setBoard();
      gameCtrl(raceStep);
    }
    
    // raceStep consists of activating player input and - for this
    // reactin game - stimulate the user for quick pressing after 
    // flickering of LED! and LED2 stop.
    function raceStep() {
      flicker();     // start flickering for a random time
      watchPlayers(); // start watching player inputs
    }
    
    // player(s) pressed too early - indicate players, then raceStep
    // for now no punishing of the player, just blaming publicly...
    function pressedTooEarly(playerIdxs) {
      if (lgo) log("tooEarly",playerIdxs);
      clear(ovrb); // prep blame buffer: all pixls in raceClrs
      playerIdxs.forEach(function(playerIdx) {
        var player = players[playerIdx];
        for (var pos=0;pos<maxPos;pos++)
          setPos(ovrb,playerIdx,pos,player.rClrs);­
      });
      pixle(ovrb,function(){
          pixle(); // restore board display
          gameCtrl(raceStep); // about next raceStep
      },blameTime);
    }
    
    // player(s) pressed right
    function pressedRight(playerIdxs) {
      if (lgo) log("right",playerIdxs);
      var raceWin = false;
      var gameOver = false;
      copyClrs(npxb,0,ovrb,0,maxLanes*maxPos);­ // copy board
      playerIdxs.forEach(function(pdx) { // update player / board copy
        var p = players[pdx]; // get player
        if (++p.racePos >= maxPos-1) { // race win?
          raceWin = true; // update win count indicator pixel:
          if (p.winCnt>0) setPos(ovrb,pdx,p.winCnt-1); // clear old
          gameOver |= (++p.winCnt >= racesToWin); // game over?
        }
        if (p.winCnt) // set new winCnt if it was new else set...
          setPos(ovrb,pdx,p.winCnt-1,p.gClrs); // existing again
        setPos(ovrb,pdx,p.racePos-1,p.rClrs); // set old n new...
        setPos(ovrb,pdx,p.racePos  ,p.rClrs); // ...race pos pixel
      });
      pixle(ovrb,function(){
          if        (gameOver) {
            setBoard(true); // skip show
            players.forEach(function(p){
              setPos(null,p.idx,p.racePos);
              if (p.winCnt) setPos(null,p.idx,p.winCnt-1,p.gClrs);
            });
            pixle(); // show win counts
            gameCtrl(function(){ rainbow(500,6,0,32,16,initGame); });
          } else if (raceWin) {
            initRace();
          } else { // just next race step
            setBoard(); // ...w/ new settings
            gameCtrl(raceStep); // about next raceStep
          }
        }, (raceWin) ? raceWinTime : stepWinTime );
    }
    
    // --- set board w/ current player information and diplay it
    function setBoard(skipShow) {
      clear();
      for (var pdx=0;pdx<playerCnt;pdx++) {
        var p = players[pdx];
        if (p.winCnt) setPos(null,pdx,p.winCnt-1,p.gClrs);
        setPos(null,pdx,p.racePos,p.rClrs);
      }
      if ( ! skipShow) pixle();
    }
    // --- flicker two LEDs irregularerly for a randim time
    var flickerTId  = null;
    var flicker1TId = null;
    var flicker2TId = null;
    // start flickering irregularely 2 LEDs. One is always on.
    // if one is about to turn off and the other one is not on,
    // the other one is turned on so that always one is on.
    function flicker() {
      flickerTId = setTimeout(flickerStop // stop flickering
        , flickerFix + Math.floor(Math.random()*flickerVary));
      flicker1(); flicker2();
    }
    function flickerStop() {
      if (flickerTId ) flickerTId  = clearTimeout(flickerTId );
      if (flicker1TId) flicker1TId = clearTimeout(flicker1TId);
      if (flicker2TId) flicker2TId = clearTimeout(flicker2TId);
      flickerLED1P.reset(); flickerLED2P.reset();
    }
    function flicker1() {
      flicker1TId = null;
      if (digitalRead(flickerLED1P)) {
        if (!digitalRead(flickerLED2P)) flickerLED2P.set();
        flickerLED1P.reset();
      } else {
        flickerLED1P.set();
      } 
      flicker1TId = setTimeout(flicker1,Math.floor(Math.rand­om()*flickerLEDV));
    }
    function flicker2() {
      flicker2TId = null;
      if (digitalRead(flickerLED2P)) {
        if (!digitalRead(flickerLED1P)) flickerLED1P.set();
        flickerLED2P.reset();
      } else {
        flickerLED2P.set();
      } 
      flicker2TId = setTimeout(flicker2,Math.floor(Math.rand­om()*flickerLEDV));
    }
    
    // watch players by watching playerInputSum
    // on press calls pressedXXX w/ XXX=TooEarly or Right w/ playerIdxs
    var playerWId = null;
    function watchPlayers() {
      playerWId = setWatch(function(watchEvent){ playerWId = null;
          var playerInputs = digitalRead(playerInputPs) // capture all input
            , playerIdxs = [], playerBit = 1; // start w/ LSB for player 0
          for (var pdx=0;pdx<playerCnt;pdx++) { // collect players' presses
            if ( ! (playerInputs & playerBit)) playerIdxs.push(pdx);
            playerBit <<= 1;
          }
          if (flickerTId) { pressedTooEarly(playerIdxs); 
          } else          { pressedRight(playerIdxs)   ; }
        },playerInputSumP,{repeat:false, edge:"falling"});
    }
    
    // gameCtrl awaits press and release of gameControlBtn to fire action
    var gameCntrlWId = null;
    function gameCtrl(action) {
      gameCntrlWId = setWatch(function(){
        gameCntrlWId = null;
        action();
      },gameControlBtn,{repeat:false, edge:"rising"});
    }
    
    // set player pos in passed or default neopixel buffer from
    // prepped colors buffer if passed, else clear
    function setPos(buf, playerIdx, pos, pClrs) {
      buf = (buf) ? buf : npxb;
      pClrs = (pClrs) ? pClrs : [0,0,0];
      var cPos = (playerIdx * maxPos + pos)*3;
      if (playerIdx%2 === 1) cPos += (maxPos - 2*pos - 1)*3;
      copyClrs(pClrs,0,buf,cPos);
    }
    
    // utility to dim a color (so-la-la... not strictly :/ )
    function dim(val) {
      if (val>0) val = Math.max(1,Math.floor(val*dimd));
      return val;
    }
    
    // utility to copy colors from one array/buffer to other one
    // for pixles. If pixles undefined, it is 1 (3 bytes);
    function copyClrs(fromB,fromBdx,toB,toBdx,pixels)­ {
      var bMax = (pixels===undefined) ? 3 : pixels * 3;
      for (var b=0;b<bMax;b++) toB[toBdx++] = fromB[fromBdx++];
    }
    
    // clear passed or default neopixel buffer (set all off)
    function clear(buf) {
      buf = (buf) ? buf : npxb;
      buf.fill(0,0);
    }
    
    // initialize 256 rainbow colors for later use
    function initClrs() {
      // from Nick Gammon, AU - http://www.gammon.com.au/forum/?id=13357­
      var x=-1, w; // index in buffer, wheel position, r>g>b>r
      for (var c=0; c<256; c++) { w=c;
        if        (w< 85) {         clrs[++x]=255-w*3; clrs[++x]=w*3    ; clrs[++x]=0;
        } else if (w<170) { w-= 85; clrs[++x]=0      ; clrs[++x]=255-w*3; clrs[++x]=w*3;
        } else            { w-=170; clrs[++x]=w*3    ; clrs[++x]=0      ; clrs[++x]=255-w*3;
        }
      }
    }
    function dumpClrs() { x=-1;
      while(++x<768) log(Math.floor(x/3),clrs[x],clrs[++x],cl­rs[++x]);
    }
    
    var rainbowOn = false;
    // displaying rainbow, changing every ms, for count times
    // (0=indefinite until rainbowOn set false), starting w/
    // color startClr (0..255), clrGrade (>0 colors to next LED),
    // avancing clrSpeed (>0) colors for each display, and after
    // rainbowk, do next (callback) if next defined.
    function rainbow(every,count,startClr,clrGrade,cl­rSpeed,next) {
      rainbowOn = true;
      rainbow0(every,count,startClr,clrGrade,c­lrSpeed,next);
    }
    function rainbow0(iv,cnt,sClr,cGrade,cSpeed,nx) {
      var sc = sClr*3, xm=ovrb.length, x=-1, b=3; // pre rainbow load
      while (++x<xm) { ovrb[x]=clrs[sc]; sc++; // load buf w/ rainbow
        if (--b===0) { b=3; sc=(sc+cGrade*3)%768; } }
      pixle(ovrb); // display rainbow
      if ((cnt === 1) || ! rainbowOn) { // check last / end indefinite
        rainbowOn = false; // after counted down to 1
        if (nx) setTimeout(nx,iv); // do next
      } else { // keep current rainbow shown until next one or end
        setTimeout(rainbow0,iv,iv,(cnt)?--cnt:0,­(sClr+cSpeed)%256,cGrade,cSpeed,nx);
      }
    }
    
    function pixle(buf,next,after) { // pixle it - write to neopixs 
      // with opitonal next action; if defined, invoke it after ms
      buf = (buf) ? buf : npxb;
      npxs.write(npxp,buf);
      if (next) setTimeout(next,after);
    }
    
    function dump(buf) { // dump buf to console for debug
      buf = (buf) ? buf : npxb;
      var x = -1, plr;
      for (var i=0;i<maxLanes;i++) { plr = players[i];
        console.log("--- player ",i," -",plr.racePos,"(",plr.winCnt,"):");
        for (var j=0;j<maxPos;j++) {
          console.log(j,"-",buf[++x],buf[++x],buf[­++x]);
        }
      }
    }
    
    function onInit() {
      // seed randmom
      var r = Math.abs(Math.floor(E.hwRand()/1000000))­; while (--r>0) Math.random();
      // board GPIO pins - set mode
      pinMode(npxp,"output");
      pinMode(gameControlBtn,"input_pullup"); // for game host to start race
      // game GPIO pins - set mode
      pinMode(flickerLED1P,"output"); // set to output so on/off can be read
      pinMode(flickerLED2P,"output"); // set to output so on/off can be read
      pinMode(playerInputSumP,"input_pullup");­ // watched to read playerInputs[]
      playerInputPs.forEach(function(p){ pinMode(p,"input_pullup"); });
      // init sequence and start to get ready for first race
      clear();
      pixle();
      initClrs();
      rainbow(500,6,0,32,16,initGame);
    }
    
    setTimeout(onInit,500); // comment before upload for saving
    

    Shot below shows blaming of to lane user because of prematurely pressing the button!


    1 Attachment

    • topLaneUserBlamingWhileStillFlickering.jpg
  • Runtime detail that goes together with the clip in first post (see still of it attached below):

    The dump of the board lane by lane into the console, before player 0 (yellow) wins the 3rd race and wins the game, from the boards perspective (<-- comments added). It shows the neopixel buffer as sent out - 30 bytes - byte by byte (3 bytes per line defining the R G B components for the LEDs). The bytes are sent in reverse order: the last bytes - bytes for the last LED in the string - are sent first, and the first bytes - bytes for the first LED - are sent last. Last 3 bytes - as sent first - are passed thru all but last LED from one LED to the next one. First 3 bytes - as sent last - are never passed on, they stay within first LED.

    >dump()
    --- player  0  - 3 ( 2 ): <-- race position ( races won ) - *** zig ***
    0 - 0 0 0                 <-- pos 0 of even lane 0, bytes 0,1,2...
    1 - 8 4 0                 <-- races-won (2) positional indicator
    2 - 0 0 0
    3 - 174 81 0              <-- race position (3) indicator
    4 - 0 0 0                 <-- pos 4 of even lane 0, ...,12,13,14 for top lane 0
    --- player  1  - 2 ( 2 ): <-- race position ( races won ) - *** zag ***
    0 - 0 0 0                 <-- pos 4 of odd lane 1 (bytes 15,16,17...)
    1 - 0 0 0
    2 - 237 0 15              <-- race position (2) indicator
    3 - 11 0 1                <-- races-won (2) positional indicator 
    4 - 0 0 0                 <-- pos 0 of odd lane 1 (...27,28,29 for bottom lane 1)
    =undefined
    

    This is the matching players (variable) information (with some additional formatting):

    >players
    =[
      { idx: 0, racePos: 3, winCnt: 2, negPoints: 0,
        rClrs: [ 174, 81, 0 ],
        gClrs: [   8,  4, 0 ]
       },
      { idx: 1, racePos: 2, winCnt: 2, negPoints: 0,
        rClrs: [ 237, 0, 15 ],
        gClrs: [  11, 0,  1 ]
       }
     ]
    >
    

    Property negPoints not used (yet). Can be used to collect sub-par information relative to the winners in order to have more granular ranking across the races for a game or even beyond to indicate "better or worse losses / fare from or close to winning"...


    1 Attachment

    • aboutToWinGameWithWinOfThirdRace.png
  • @user96449, you mention in post #9 of above referenced conversation

    Wow, you make it sound so easy...

    Yes, it is so easy... while the thing is running, you need no special tools or skills to inspect and influence things on the micro controller, as I just did in the previous post: you just invoke a function in the console by name - dump() - and its return result is right printed. Or you enter the name of a variable that references a plain scalar, simple or complex object or structure - players - , it is right away dumped into the console. players is an array of objects, of which some properties are arrays of numbers. Without adding anything, the information is display with structure visible in the console. And if you want to change a value, for example player 1's race pos, you just assign it with an JavaScript expression / statement in the console: players[1].reacePos = 4;. And for sure, also updating the board works and goes like this: setBoard()... and this is just the tip of the ice berg of easy ness. Espruino has also a built-in single step debug function that allows you to go step by step thru the code and inspect and set/change what you want to change.

    Why and how does it work: The Espruino board does all the heavy lifting with its JavaScript interpreter. The console in the IDE is only a terminal to the micro controller. Any thing you enter is consumed by the JavaScript interpreter, and if it is a valid expression / statement, it is executed.

    You can even add code. For example to get which player is leading in the race, you enter - in one or on multiple lines:
    function raceLeader(){ return players.reduce(function(r,p){
    return (r===null) ? p : (r.racePos>=p.racePos)? r : p; },null); }
    Then you can use the raceLeader() function. Changing code goes the same way...

    As you see, Espruino gives you a lot for what you wan to do....

  • This is really cool. Sorry I haven't seen this earlier. I've been sick and then started teaching the new semester yesterday. Busy.

    I have enlisted the help of students at a local university (Louisiana Tech) to help with the coding but it looks like you have done that. This is really great but I have no idea what I'm looking at (well, maybe a little)! Here are some questions:

    I just want the game to operate for one time and it resets all over again. It stays off till I turn it on so no penalty for an early start.
    It shouldn't keep track of the winner over and over. If I'm reading all this correctly, it seems that it is remembering who won and how many times they have won. Is that correct?

    How many Espruino boards would this game require? One, two, 16? One board would be great as would one long string of 500 lights but should I have multiple strings instead - one string of 30/50 LEDs for each player?

    How would the lights know when the ball passes over a rollover switch? I don't know how I would wire the switches to the lights. Do I need to find an electrical engineer to make the connections?

    While I have help, students are probably not going to understand the switch to the LEDs part. They work in CS /IT, not electrical engineering. I think the university can help with that too but it would help to know if you know how to do this.

    I know this seems like a lot, but this is a very important memory that I'd like to relive with my kids and grandkids (seven children, 15 grandchildren - yeah, there's a lot of them) and because this game no longer exists. the last complete 1940's arcade game was parted out to people wanting antique collectibles. Reconstructing this preserves the overall game for history plus it's just a lot of fun, anyone, no matter what age, can play. And I'd have the only one like it.

    I'm going to have the pinball half remade like the original. Silkscreened board with the company logo, and all. The only difference is the electronics are made to last for 100 years (hopefully). Your help has and will bring a lot of happiness to an old man (me) for a long time to come.

    I can build the cabinets, the wallboard and the like but I just don't understand the electronics enough to make it happen. (I put weather sensors on my RPi and they worked but it took weeks to do it and a lot of frustration - still, I succeeded). I haven't said thank you to everyone so far but I really want to do that now before I get crazy busy and forget. Thanks for the help.

    Mike

  • If one race should win the game, set racesToWin = 1; - in line 46.

    Since I did not have a pin ball machine at hand, I 'invented' and integrated this reaction game with the flickering. With this game all players play at the same time for each game step. No turns have to be taken by the players.

    For a pinball machine, this looks different: 1 player plays at 1 time and players take turns. Is that assumption correct?

    If this assumption is correct, game control has to be bit different. To have a clear game control / flow, the player's turn has to be shown on the board.

    You can take this code and modify it. First, you have to rip out the flicker stuff and the too early and just right functions. Game control has to trigger the indication which players turn it is and just enable 3 pins to read the roll over switches or whiskers - like I used the 2 reaction buttons. Two springy wires are good enough for one whisker switch: one wire is connected to ground and the other to the pin, and when the metal ball runs 'between' them is a momentary switch. If you have a rollover switch, that works as well.

    For programming just think of the lights as memory entities: 3 bytes reflect one position, and since they are daisy chained, it is just pushing the memory into the sting. One Espruino should be good for quite many positions. It all depends how many players or lanes (horses) you want, and how many steps or positions the race should have.

    To understand the pinball machine part a bit better, you may need to describe a bit more what is going on in it.

    From the initial description it looked like that you only count where the ball exits: path 1, 2, or 3, and each of these give that many points or advance the player so many steps on the board: 1, 2, 3.

    If the machine works more like a pin ball machine where the ball can bounce like crazy between positions and each bounce advances the horse on the board, then it may look a bit different. The cool part would be multiple pin ball machines so players can play simultaneously...

  • Wed 2019.01.09

    Mike,
    By chance are you @user96445 @user96449 and now @user96792 Is it possible that a different email addr is being used to access the forum on each edit? It would be of great benefit if there were consistency here, to allow us to easily follow along.


    "Do I need to find an electrical engineer to make the connections?"

    Good gracious no, I don't think so. This is basic week one electronics.

    See these examples for switch input:

    https://www.espruino.com/Pico+Wire+Loop+­Game

    https://www.espruino.com/Pico+Buttons


    "students are probably not going to understand the switch to the LEDs part"

    The process will be done in software.

    Think of each wire end in wire loop game being attached to one of the poles on the switch diagram provided in:

    http://forum.espruino.com/comments/14567­358/ This is the rollover switch I'll be using

    The LED part:

    https://www.espruino.com/WS2811


    Consider a strip of neopixels to cut down on the amount of wiring. Just three wires for a strip. I am running a meter of 60 neos with approximate spacing of 5/8" Very flexible. Would a strip fit the player lane from #1: http://forum.espruino.com/conversations/­329107/

    https://www.aliexpress.com/item/DC5V-WS2­812B-1m-5m-30-60-144-pixels-leds-m-Smart­-led-pixel-strip-Black-White/32905393129­.html?spm=a2g0s.9042311.0.0.342d4c4daOFy­K1

    You will however need a microcontroller to turn these on, as they are not a simple resistor and LED.

    Many examples here and a few, including myself that can assist with the nitty-gritty.

    Schematic - Mike, do you by chance have the electronics schematic of the original game, most likely relay logic? This would assist in determining what game logic each of the six rollover switches would control.




    Mike, have you made a firm decision to complete this project using an Espruino device?

    @allObjects has burned up a considerable amount of time producing a near finished project, and I would hate to see his efforts evaporate, should you be considering the Arduino (ref #4 conv 329107) instead.

    One Espruino Pico (has 3 SPI) should do the job for stand alone if one continuous strand of neopixels are used. I've not tested the total count limit, although I've read five meter x 60 = 300 is possible.

    https://www.espruino.com/Pico

    See #3 above for image compliments of allObjects of an Espruino WiFi that is powering two lanes of five LEDs each. Complexity of game play, along with which LED wiring, time and money will make the decision on which and how many.

    Maybe the Espruino WiFi as allObjects suggests to have a web page in a browser control the panel wirelessly?

    https://www.espruino.com/WiFi

    As an enhancement, have you considered using the Espruino MDBT42Q for Bluetooth connectivity to run this game from your phone perhaps?

    https://www.espruino.com/MDBT42Q

    Several options and a great group here on the forums. I'd like to see you succeed and taking a few pictures to post in the Projects forum would be fun to follow along to project creation.



    May we may welcome you aboard and join us in the Espruino adventure?

  • I think when I log in from my phone, it's grabbing my different email addresses from FB or something. I noticed that I had different user numbers too. The first two are me, I thought I corrected it the last time but alas, I now have a third user... sheesh🤔 I have to figure out why I'm logging in with different emails when it should populate using the original when I set up my registration. Today, I'm going to work on this issue.

    No schematics. The last remaining game was parted out and nothing exists. I wish. I haven't checked one place, the US Patent Office. I'm adding that to my must do's list today. Maybe I'll get lucky.

    I am going to use Espruino. The students helping me know Java Script well. They didn't know about the Espruino board but I doubt it is a problem. In fact, I copied everything everyone in this forum, including @allObjects has created and forwarded to them to the students. I thought it would benefit the large number of CS students at Louisiana Tech University more and intro the Espruino board to them as well. Spread the wealth.

    For me, I'm going to handle this like I'm a project manager and connect everything and everyone, then learn how this all works once this works. I'm a hands on learner. The students are being paid for their help and they can educate me on the build and coding. I think getting out of the way and letting them build it is better than me micromanaging. I'll also learn all of this and may be able to contribute back to others on this forum when possible. In the meantime, I'm learning a lot now which wasn't possible without the great people on this forum.

    The hardest part? Getting it up and running. I can't wait!

    Thank you to everyone for sticking by my side. A dream is going to become a reality. I have a plan and help, materials and students that seem more excited than I am to complete this. Kids and pinball type games are still a great combo. A tiny part of the good old days still exists. That's just cool.

  • Hello! Before answering questions, I must thank you from deep in my heart. Your efforts have blown me away.

    Exactly, players are simultaneously playing.

    Unlike a pinball machine with only a single player, everyone plays at the same time until there is a winner.

    Game operation:
    So, the handle is pulled and shoots the ball up, it bounces on rubber bumpers but the bumpers do nothing.

    Think of them like the bumper rails on a pool table.

    Gravity takes over and the ball drops into one of two lanes. One lane has two rollover switches, the other lane has three.

    The ball rolls over each switch and the light advances.

    Question:
    Since the lights are programmable, (remember I really don't know much about all this so if it sounds dumb, sorry) couldn't one switch be used to advance the lights two or three lights depending on which of 2 switchs is activated instead of using 5 switches?

    Less parts to buy, less to wear out.

    As the lights advance, they reach the "Final Stretch".

    Question, can the lights in the final stretch be programmed to advance one light using the same switches instead of two or three lights? Basically slowing down the leaders so others can catch up?

    Next question:
    Do I need to cut the string (or can I cut it?) or is it one long string zig zagging back and forth?

    It seems to me that the lights then have to be coded backwards for every other player. Is it more efficient to cut the string, add three lengths of long wire to start the string for those players at the start instead of backwards coding them? It seems simpler for the coding? Am I perceiving this correctly?

    Next question: after enlarging the picture of the board, I discovered there are 30 lights for each player to light. 24 lights during the race and then six lights for the Final Stretch.

    If I reproduce the game exactly like the picture, there are 18 players. I'm reproducing something that no longer exists. I may donate this to an arcade museum after I leave this world, that means all 18 players for a faithful reproduction. How much power will this take?

    Can the Espruino handle that many players?

    If not, what is the number of players that can play on one board and what power supply should I purchase to run all of it?

    Can I use a power supply like those used for a pc upgrade with a powerful graphics card. I think this is a compatible solution but I'm guesstimating here.

    Do you have a way I can call or you can call me. I think verbally communicating might help on the game operation. Everything for the coding and building should stay here on the forum.

    As I'm on my cell, I can't see the pictures Robin posted. My eyes are old and its hard to watch them. The pc at home is much easier to see.

    I may add more comments this afternoon when I get home. A real keyboard and big screen.

    Again thanks

  • Fri 2019.01.11

    Hi Mike, it appears you @matencio have solved the login issue. Great!!


    "the large number of CS students at Louisiana Tech University more and intro the Espruino board to them as well. Spread the wealth."

    Welcome to the Espruino community Louisiana Tech students, and I'm sure @Gordon will be thankful also!


    "Unlike a pinball machine with only a single player, everyone plays at the same"

    To clarify, does this mean there is a separate two lane pinball like frame for each player? (yes?)

    If yes, a problematic issue exists. How to multiplex the switches (18 x 2 = 36) and decode them at the microcontroller. If three SPI ports are used, there are around four available pins remaining.


    "couldn't one switch be used to advance the lights two or three lights depending on which of 2 switches is activated instead of using 5 switches?"

    Yes. Array element index offset


    "can the lights in the final stretch be programmed to advance one light using the same switches"

    Yes


    "Is it more efficient to cut the string, add three lengths of long wire to start the string for those players at the start instead of backwards coding them?"

    This would be my recommendation, although I haven't tried this myself. It might be that the data line will have to be shielded, but only if the length causes an issue. More in later posts.


    "Can the Espruino handle that many players?" (ref 18)

    Will require lengthy discussion. If all (24 x 18 = 432) sequential Neopixels could be separated into two or three strings, then one Espruino device (Pico or WiFi) with three hardware SPI pins %should% be able to handle sending the data. Memory management and array size will be critical here.


    "Can I use a power supply like . . . ."

    Question: How many lights will be on at the same time? If less than ~40, a simple $5  5V2000ma wall wort/phone charger should work fine.
    I've pushed the limit and have run my meter strip of 60 full on for four hours without smoke! ;-) Kids don't try this at home.
    (40 neos x 60ma ea = 2400ma total, beyond the rating)
    Neopixels did get warm but wall charger surprisingly cool.



    I found this link of a carnival game that is similar to what I remember from fifty years ago, but

    https://hanfordsentinel.com/features/nos­talgic-carnival-game-makes-one-final-app­earance/article_f1a2a497-669e-51c7-86eb-­bce1393bd6e1.html

    had mechnical horses rather than a light board similar to this:

    https://www.pinterest.com/pin/1543890934­53558191/

    Brings back a memory of when my brother and I, around age 10-12 were at a carnival (IN) watching one of these in action. Both of us were in back looking at all the clicking relays and advancing horse mechanism, fascinated instead of watching the players shoot the ball and who would win. Interestingly, both of us started careers in Electronics, then on to Software. It was around thirty years ago, I saw (WI) the last of the mechanical but did see a lit board like the one you possess.

  • The image of the game is the actual game. There weren't any mechanical horses though. Awesome pic because that is the guy that ran it back in the day. That is the actual game I'm reproducing. Very cool. I don't have the board unfortunately. I have to build it too. Still, well worth the effort. I love that second game with mechanical horses but never played. I'd love to build that too but wouldn't know where to start.
    Now to answer questions.

    Yes, each player is separate. If 18 is too many, for now, can I do 12 instead? It will be more practical that way. Easier to manage too. That's enough for the family get togethers. That should resolve the board issue too, I hope.

    Shielding the cable. Isn't there a cable wrap to shied the wire? I have used tin foil in the past...lol don't know if that was okay but it worked.

  • Some of the answers repeat @robin, some are different...

    • number of rollover switches: you need only one per lane where the ball passes. - In the 'old' electromechanical days, there was no software that did the job: it was stepping relays https://tuukan.fliput.net/emfix_en.html for a score wheel, or, when using horse thinghy with lights, you would (ab-)use a phone switch relays with 10 steps... or a plain rotary stepping switch... https://www.surplussales.com/Switches/SW­Ledex-1.html - and they needed the pulse(s)... ;-)

    • slow down game in end stretch: no problem, you just program it the way that after no matter what lane the ball exits, only one step is advanced... this is though not really working when you do not have a lane - or more than one - that does give no points what so ever!

    • cut and have wires instead of zig-zag and reverse programming: no point there! no efficiency what so ever... actually worse... because depending on length of the wires going back and the electro smog, the timing could get off... so no point there. @Gordon implemented the zig zag just for that this is not needed (not only for neopixel displays, but for others as well that are feed with a serially with a stream of bytes...). Therefore: zig-zag is the answer. - There may be a thing or two to consider though, such as how close he lanes are. To do the zig and the zag, you may cut and insert a short wires... I would though just go for 'ignoring' a pixel, since you have anyway plenty of them... and you loose only one per lane... and this is again just a matter of coding... (btw read up about the signal timing re-conditioning that each neopixel does for the next one!)

    • Espruino handling the number of players and lights - 18 x 30: Adding 2 more for the indication of the player at/for the ball and one for handling the zig zag without cutting: 30x20x3 bytes = 1800 bytes... 1.8KB ... and the rest is for the code... way manageable... I did not make a test of the memory consumption in the prototype... but I made the calc the very first time you came up with the game idea... it is not even worth to save a few bytes / cut out the pixels... it is just more work. Think of mapping and the algorithm that does it... exactly as the zig zag does it. Also the speed that things can happen: Espruino has a event queue and while a new 'board pattern' is pushed out. AIR, data is pushed out with something around 400KHz - it would take a string of 16K - 16,666 - sixteenthousandsixhundredandsixtysix (in check writing) - lights to eat up a second! - your 600 lights keep your Espruino exactly / about 36 ms busy... (I hope my math adds up...)

    • Power Supply: As with everything in Engineering, the answer is always: ...it all depends. Assuming that there are max 3 pixels lit per player and they would light all up - worst case - fully and white, this makes 3 (pixels) x 3 (LEDs - R, G and B each) x 18 (players) x 20ma (each LED) = 3x3x18x20 ma = 3240 ma = 3.240 A. Since not all LEDs in the Pixel are fully up at the same time because you want to have different colors, therefore you can go for half of that current. In other words, you a 5 volt power supply w/ 1.8..2A for the LEDs and paralleling feed lines. Feed lines are similar like done on overheads for tramways/trolley/trains along their route. Espruino drives only the first pixel's signal input. You just connect the Espruino board to that same 5 volt supply when running with both, 5V and Ground. At development, you run Espruino from USB, BUT you keepGROUNDs of Espruino and the pixel string connected. If you do not connect the GROUNDs, the control signal has no reference and is floating, and you lights go northern... --------- As said: it all depends. When you want to do some splashing with your board - and with 18x30 lights you really can put some text and light shows on - you need to severely rethink your power supply setup: 600x60ma = 36000ma = 36A... (@5V: 180W). Some old PC power supply or supplies joined - if joinable - may do that (Just checked: AT/ATX max Amps on 5 V is about 15A, not exactly enough for what you are looking for). For reliable results, go for something like 5V 40A, for example, https://www.jameco.com/z/RSP-200-5-MEAN-­WELL-200-Watt-Single-Output-Power-Supply­-with-PFC-Function-5-Volts-40-Amps_21739­33.html (I have no shares; I was just a googling for 5V 20A 200W single output power supply). NOTE: There are 5V and 12V versions of these 5050 or LED-like Neopixel strings. With 12 Volt, a bit less Amps / less thick line feed wires are required, but the Wattage stays the same. WS2812B - 5V - come in strings of 5M w/ 150 or 300 pixels (30 or 60 /m). You can also get wired ones, but they are much pricier.

    Challenge your students for alternative solution(s) in the software implementation (I'll dm u abt it).

    What I still do not properly understand is

    players are simultaneously playing

    Does that mean you have 18 pin ball machines?

    With 18 boards, you end up w/ 36..54 exit sensors. Thehe Original Espruino board has 44 GPIOs that you can use as inputs. Alternative, you can use my interrupt enabling code for Porte Expanders (which would actually be a motivation to finish that as a module. It is an enhanced version of the code of the existing one; see Exploring adding setWatch/clearWatch (inerrupt handling) to MCP23017 (MCP2308) Portexpander Ports. Two of those chips can handle 32 inputs effortlessly, and need eat up only a few GPIOs of the Espruino, and offload a lot of work as well - as is described in related conversations (scanning key board / button entry matrix / switches / etc).

  • Sat 2018.01.12

    Thanks @allObjects for the links to the stepper relays. I searched but didn't find suitable images. Boy do those bring back memories.


    'Does that mean you have 18 pin ball machines?'

    Look closely at the bottom edge of the image, then click the right arrow button (upper right of image) and advance to the third slide

    https://hanfordsentinel.com/features/nos­talgic-carnival-game-makes-one-final-app­earance/article_f1a2a497-669e-51c7-86eb-­bce1393bd6e1.html



    Looking over the MCP23017 for lane switch decoding

    http://ww1.microchip.com/downloads/en/De­viceDoc/20001952C.pdf

  • Sat 2019.01.12

    Mike @matencio,

    Just stumbled across this image of a flexible Neopixel strip wired to a Pico as an example of what your project might require. There is some discussion and some basic code snippets that would assist in coding understanding.

    http://forum.espruino.com/conversations/­324269/#comment14375745

  • @Robin, so my conclusion about the number of (simplified) pinball machines is it has to be equal or more the number of simultaneously playing players. That's quite some work to get done... and it will also be a challenge to make all machines behave the same way in order to not let always the same one win (even though also such inconvenience could be taken care of by the software).

  • Sat 2019.01.12

    'the number . . . . has to be equal or more the number . . . .'

    Yes, I agree.

    From the images in #1

    http://forum.espruino.com/conversations/­329107/

    what isn't shown is whether the individual lane tables were with the lightboard shown, or were they being built from scratch.

    I was thinking easy such as an 8 input encoder multiplexer. See p7 on combining to make 16 or 32

    http://www.ti.com/lit/ds/symlink/sn74hc1­48.pdf

    complete 74HCxx series

    https://www.creatroninc.com/upload/Logic­%20IC%20List.pdf

    then use another as a 'bank' selector and do the decoding in a software table. Maybe this is the same/similar to the port expander you mentioned.



    'it will also be a challenge . . . have to . . . in order to not let always the same win'

    Ahhhh, but that was the lure of the carnie experience, to attempt to queue up to get the better lane. I remember five lane tables on the game I saw years ago. @matencio mentions two in this thread and three in the original post.

    I also agree with you, that if the tilt of each table is not easily adjustable to allow the ball to fall through the gates at the same rate, a small usec delay could be added in software.

  • Using cascaded/chained/extended 74XX148 8-to-3 decoders give some relieve in numbers of lines to watch, but at the same time pose a timing challenge because there is no registers that store the information - signal change - and Espruino may not be fast enough to catch who was really first, because the chip is a priority encoder. A lower priority may trigger but when reading a higher one may have chipped in and messed it all up. Furthermore, a detection of s'simultaneously in the same - very small - time window is not possible. The prototype I built in the reaction game can have this issue as well if something else runs next to the game, such as scanning / charlieplexing (when using something else than neopixels w/ storage info (which the prototype does not do).

  • Sun 2019.01.13

    'A lower priority may trigger . . . . have chipped in and messed it all up'

    I can't imagine this was of much concern the the design using relays back in the 50's

    Just the time element in closing the relay contacts would be far worse (a fair guess) than a microcontroller polling the input.

    Even as a child I remember what appeared to be 'glitches' in the way the (now lights) mechanical horses advanced. It sometimes seemed a random group of three advanced, when two of the three still had a ball waiting to enter a lane. I wonder if this is how they got around that timing issue, by creating a diversion, perhaps?

  • ...yeah, but the issue here is that the higher wins and is the only one detected, and all the others are not detected and loose completely out. Therefore, timing in regard who comes first among the 'simultaneous ones' is not the actual issue. The real issue is that only one is noticed. This makes me think that each line would have to have a latch (RS flip-flop), just as the mechanical horses had their own dedicated wire and stepping relays - and having adjustable end switches for winner detection can be pretty precise and accurate. This makes me think to have a latch for each of the pin ball machine exit lanes in order to make sure that no scores are lost. The time between two balls is ample to handle the 'signal'/event.

  • 'but the issue here is that the higher wins and is the only one detected'

    May agree on the exit latch flip-flop, but not on 'only one detected' in above statement.

    As the ball rolls through the lane, tripping it's lane switch, another player lane might have a ball roll through a half second later, and a third a second after that. The other nine would be in the process of launching the ball. So polling these switches is nothing in processor time and accurate event monitoring could take place.


    'The real issue is that only one is noticed'

    If a flip-flop is used, that might block/lock the other near simultaneous ball pass through reads. What about a simple R-C circuit that briefly charges a cap, then discharges it after a read. In that way, say polling ten times a second, would allow for %all% detections, even on close races, as the time to reload and fire might be three or more seconds away.

    48 hrs have elapsed. Put an A.P.B. out for Mike, hope we haven't scared him away . . . .

  • ...looks like we are sailing different boats...

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

Retro Horse Derby Game Board with Neopixels showing Reaction Game Status

Posted by Avatar for allObjects @allObjects

Actions