|« Announcing the Mcuplace Store! (and some new projects to come)||Intro to finite state machines (FSM) »|
I play Dungeons and Dragons, and like any geek who plays DND i felt like making electronic dice (how clever and original?) with a catch, it has to be ultra portable and has to last at least the length of a standard gaming session on a single charge, it also has to be relatively cheap. I started this build last year around April time, and finished around May last year, i haven't really had much time to write lately so i've been putting off this post. Finally got some free time today, so here it is, my D20 Roller.
One resource i took well advantage of was Dorkbot's PCB service. After three separate revisions i settled on my final design, essentially its a micro (pic18f13k50) 22 SMD LEDs, two push buttons, and a super cap with all the appropriate passives on a 2x1" PCB.
So for this design i wanted to try and make everything as small as possible, which meant surface mount... everything. Personally, i prefer soldering surface mount, once you get used to is its pretty easy, just sucks when you lose stuff under the bench.
Laying things out when using surface mount is pretty trivial, put the stuff that's important for operation on one side, the junk that runs the show on the other side. Making it portable on the other hand, well that's another story. If you want portability, whats the most obvious choice for power? Battery of course, well aa's and aaa's are bulky and don't provide enough voltage for our LEDs, we could add a boost converter or some sort of power system, but that adds cost and space. We could also use coin cell batteries, these too however can be bulky and the holders can take quite a bit of space. My solution was to use a 1F 5.5v super capacitor.
The biggest advantage is they require no charge circuitry (a current limit resistor is plenty sufficient) They hold whatever voltage they're charged to (in this case 5 volts) and they pack plenty of juice to run a micro and some LEDs for a few hours (if you manage your power well). I provide a mini-usb b type receptacle for plugging into a USB port and siphoning off 5V, a current limit resistor limits the current so smart sources (like a PC) don't freak out when there's this huge current draw on the USB port. A smarter design would of been to add a LDO regulator, since then you can accept a wider range of voltages, this adds costs and takes up space.
Now, as for the actual operation of the die roller itself; there are two thing i'd like the roller to accomplish:
Firstly, you need to be able to tell it when to roll a die, so we need a button for rolling dice. Secondly, we would like to be able to select the die type we would like to roll, this is our second button. Operation is simple, hit select until the the die type you want is highlighted, hit roll and you'll get a value within the range of what you want. Simple, and effective.
A note about random numbers:
Well first off, there is absolutely nothing random about this die roller, it is completely synchronous, if you could time yourself perfectly, you'll get the same value every time. But, if you do the statistics (i have) with this roller and an actual d20, you'll find they both have the same statistical distribution. So how do I do it?
1) Humans are slow and all push-buttons suck.
That is the key to this algorithm, in the background of the program I have timer0 cycling as fast as possible. When a random number is requested, I multiply timer0 with the range, i take the higher byte of the result and that is the "random" value which gets displayed.
The trick is timer0 is a 8 bit counter, with a range of 0-255, at 1MHz it overflows approximately 3900 times a second. The fastest human reaction time is around ~100 milliseconds, average is about 200. So before you can even react to your brain saying "hey i wanna push that button, timer0 has already cycled a few hundred times.
In essence you cant time yourself to get the same value twice, its humanly impossible, the error to your reaction time is much greater than the refresh rate of the timer.
Secondly buttons suck. Anyone who has used a pushbutton knows about a problem called switch de-bouncing. When a switches mechanical contacts come together, they dont make a perfect connection, they bounce against each other untill actually settling into a set state. If you have a scope, set it to single trigger and hook it across a switch, you'll notice have many times the switch "bounces" until it settles into a value. This article explains switch debouncing better than I could:
The result of this, even if you could perfectly time yourself down to the microsecond, the time it takes the switch to settle, is random. This is actually the source for many random number generators, but I mostly use the first phenomenon, my switch denouncing algorithm is rather simple, I just kill some time before looking at the switch again, its simple and it works!
So yea, my algorithm is't truly random, but it's incredibly efficient (takes 4 instructions) and it generates results indistinguishable from a real die.
Dice in action
The software is pretty simple, and it's mostly incomplete. For the final iteration i wanted to run a finite state machine and work hard on implementing sleep features, but i never got around to it. The current code is pretty basic, but it works pretty well. Here is the state diagram for how i wanted to implement the code :P
Below i've attached a few things, the source code, the schematic, and a sample excel file where I've done some stats.
If anyone is interested in buying one to play with, I have plenty that need a good home and i'd love to have some funding for a better revision!
You can contact me by email at: firstname.lastname@example.org
I've written a brief manual that those who bought either a kit or the dice themselves will find useful!
Also, I've written another firmware revision, which i will be updating and i'm in the process of writing one more!
Finally, i have another revision of the board, which i am getting printed, i will have these available as kits and assembled versions.
I have two new firmware revisions:
First up is version 4 of the firmware, if i remember correctly, this version puts the display as interrupts making the display a little cleaner and smoother.
This revision focuses on power saving and improving how inputs are handled. Inputs are now handled by interrupts and the main routine is completely freed up. Sleep is enabled and clock speed is reduced to 500khz.
Any questions! Email me!
This is really cool! If it was me, I would use a humidity sensor on the back to get a real environmental random number for doing the calculations, obviously its not very necessary but I like to nerd out hard lol :P
I had about 12042993490 different ideas for generating random numbers, although this a psudo-random algorithm, the data doesn’t lie, its a fairly random routine. I like the idea of amplifying white noise and using that as a bit stream as a seed >.> You can use the on board comparator on two analog pins and it should be fairly random, doesn’t require and extra hardware.
This is pretty neat! Would it be possible to release the eagle source files instead of/in addition to the PDF schematic?
Once i get another revision out(soon), i have no problem releasing the board files!
good project! looking at the schematic I think you have to put resistors between the bases of the transistors and the controller, for example between T1 and RB4; 10k or so will be ok
That IS true….
IF… they were BJTs,
They’re not in this case, they’re actually NMOS mosfets, eagle doesn’t have a good SOT-23 mosfet package, so i use a NPN SOT-23 because i’m lazy. However, you are correct, you ALWAYS want a base resistor when using NPNs
nice project. how long does it take to charge the supercap running off the usb?
|<< <||> >>|