Help with two dice Arduino

I built dual dice program and display for Arduino. Works great but it is NOT random. I can't figure out why. Maybe I must re-do using the rnd function.

/*
Two Dice
 Die layout:
 1   4
 2 7 5
 3   6
 After power up, dice count through all 36 values, one increment per time1 (1/2 sec).
 Push button and dice increment and display as fast as op=possible.
 Release button and current value is frozen for five seconds, then resume counting every .5 sec.

 counting with dice:
 1 - 7
 2 - (1+6)
 3 - (1+6)+7
 4 - (1+6)+(3+4)
 5 - (1+6)+(3+4)+7
 6 - (1+6)+(3+4)+(2+5)
 The circuit:
 pins for Units die:
 1 = 7     U7
 2 = 1+6   U1and6
 3 = 3+4   U3and4
 4 = 2+5   U2and5
 Pins for Tens die:
 5 = 7     T7
 6 = 1+6   T1and6
 7 = 3+4   T3and4
 8 = 2+5   T2and5
 */
   
const int U7pin =      2;    // LEDs connected to digital pin 2-9
const int U16pin =  3;
const int U34pin =  4;
const int U25pin =  5;
const int T7pin =      6;
const int T16pin =  7;
const int T34pin =  8;
const int T25pin =  9;
int time1 = 500;
const int buttonPin = 10;     // the number of the pushbutton pin
int buttonstate = HIGH;          // button history

// The setup() method runs once, when the sketch starts

void setup()   {                
  // initialize the digital pin as an output:
  pinMode(U7pin,OUTPUT);  
  pinMode(U16pin,OUTPUT);
  pinMode(U34pin,OUTPUT);
  pinMode(U25pin,OUTPUT);
  pinMode(T7pin,OUTPUT);
  pinMode(T16pin,OUTPUT);
  pinMode(T34pin,OUTPUT);
  pinMode(T25pin,OUTPUT);       
}

// the loop() method runs over and over again,
// as long as the Arduino has power

void loop()                     
{
  digitalWrite(T7pin, HIGH);   // TEN
  digitalWrite(T16pin, LOW);
  digitalWrite(T34pin, LOW);
  digitalWrite(T25pin, LOW);
  rollunits();    
  digitalWrite(T7pin,  LOW);   // TWENTY
  digitalWrite(T16pin,HIGH);
  digitalWrite(T34pin, LOW);
  digitalWrite(T25pin, LOW);
  rollunits(); 
  digitalWrite(T7pin, HIGH);   // THIRTY
  digitalWrite(T16pin, HIGH);
  digitalWrite(T34pin, LOW);
  digitalWrite(T25pin, LOW);
  rollunits(); 
  digitalWrite(T7pin, LOW);   // FORTY
  digitalWrite(T16pin, HIGH);
  digitalWrite(T34pin, LOW);
  digitalWrite(T25pin, HIGH);
  rollunits(); 
  digitalWrite(T7pin, HIGH);   // FIFTY
  digitalWrite(T16pin, HIGH);
  digitalWrite(T34pin, LOW);
  digitalWrite(T25pin, HIGH);
  rollunits(); 
  digitalWrite(T7pin, LOW);   // SIXTY
  digitalWrite(T16pin, HIGH);
  digitalWrite(T34pin, HIGH);
  digitalWrite(T25pin, HIGH);
  rollunits(); 

}
void rollunits(){
  digitalWrite(U7pin, HIGH);   // ONE
  digitalWrite(U16pin, LOW);
  digitalWrite(U34pin, LOW);
  digitalWrite(U25pin, LOW);
  checkbutton();
  delay(time1);  
  digitalWrite(U7pin,  LOW);   // TWO
  digitalWrite(U16pin,HIGH);
  digitalWrite(U34pin, LOW);
  digitalWrite(U25pin, LOW);
  checkbutton();
  delay(time1);
  digitalWrite(U7pin, HIGH);   // THREE
  digitalWrite(U16pin, HIGH);
  digitalWrite(U34pin, LOW);
  digitalWrite(U25pin, LOW);
  checkbutton();
  delay(time1);
  digitalWrite(U7pin, LOW);   // FOUR
  digitalWrite(U16pin, HIGH);
  digitalWrite(U34pin, LOW);
  digitalWrite(U25pin, HIGH);
  checkbutton();
  delay(time1);
  digitalWrite(U7pin, HIGH);   // FIVE
  digitalWrite(U16pin, HIGH);
  digitalWrite(U34pin, LOW);
  digitalWrite(U25pin, HIGH);
  checkbutton();
  delay(time1);
  digitalWrite(U7pin, LOW);   // SIX
  digitalWrite(U16pin, HIGH);
  digitalWrite(U34pin, HIGH);
  digitalWrite(U25pin, HIGH);
  checkbutton();
  delay(time1);
}
void checkbutton(){

    if ((digitalRead(buttonPin)==HIGH) && buttonstate == LOW) 
    {
      buttonstate = HIGH;
      time1 = 500;
      delay (5000);
    }
    if (digitalRead(buttonPin)==LOW) 
    {
    buttonstate = LOW;
    time1 = 0;
    }
}

Please put “code” tags around your script. It’s the little # symbol. That’s just obnoxious as it is now…

Works great but it is NOT random. I can't figure out why.

How does buttonState get from it's initial value of HIGH to LOW?

Depending on how you have wired the switch, it may be HIGH when not pushed, and LOW when pushed. Can't tell, because you did not describe, or show, that.

The buttonstate variable is used to debounce a switch, so that pressing it (setting it's state HIGH) is not detected twice. Since you are going to pause as soon as the button is pressed, for 5 seconds, it is not necessary to debounce the switch. Get rid of buttonstate altogether, and the second if and digital read in the checkbutton function.

When you are sure that checkbutton is working, remove the explicit call, and uncomment the rest of the code in loop.

Button is initially low. Program sequences through all dice values stepping every half second. When button is pressed, numbers sequence at maximum program speed. When button is released, a five second delay in incrementing occurs. This should display the current count for five seconds. As I have tested for randomness I get as many as 50% of readouts showing the slower digit as four! Sometimes 6 or 8 fours in a row. I can only figure this is something to do with the time at which the switch is read by the Arduino.

Thanks for looking.

Since you want the button press to interrupt what is happening, and you want the button release to interrupt what is happening, perhaps you should look into using interrupts.

In the ISR (interrupt service handler - the code called when the interrupt (button press or release) occurs), set a value, to 0, 1, or 2. 0 would be slow rolling of the digits, 1 would be fast rolling, 2 would be paused.

Then, the loop and rolldigits functions could be implemented using if loops. If slow rolling, do something. If fast rolling, do something else. If paused, do nothing.

Brucesallen,

The only easy way to achieve randomness is to use the only variable part of your system, that is the input from the button.

What I would tend to do is wait till the button is pressed, blank the display and increment an unsigned byte counter until the button is released.

Then use mod 6 on the high nibble and low nibble of the counter to get the 2 required values and then display the result, with a bit of flashiness if you so desire.

I challenge you to press that button for the exact same duration every time ;D

I hope this helps.

Martyn.

Then use mod 6 on the high nibble and low nibble of the counter to get the 2 required values

   Roll     Odds
   ----    ------
     1     3 : 16
     2     3 : 16
     3     3 : 16
     4     3 : 16
     5    [glow] 2 [/glow]: 16
     6    [glow] 2 [/glow]: 16

I believe the phrase I'm looking for is "rigged dice". ;)

Here’s a bit of a demo of the sort of thing I was thinking of.

The output seems random enough to me, but then I’m no statistician.

/*
  Electronic Dice 
 */

int inputPin =  10;    // button connected to digital pin 10

// The setup() method runs once, when the sketch starts

void setup()   {                
  // initialize the digital pin as an input:
  pinMode(inputPin, INPUT);
  
  // initialise serial port for displaying results
  Serial.begin(9600);
}

// the loop() method runs over and over again,
// as long as the Arduino has power

static unsigned char counter = 0;

void loop()                     
{
int hi_nibble, lo_nibble;

  if (!digitalRead(inputPin))
  {
    while (!digitalRead(inputPin))
    {
      counter++;
    }
    lo_nibble = (((counter & 0xf) % 6) + 1);
    hi_nibble = ((((counter >> 4) & 0x0f) % 6) + 1);
    
    Serial.print("low nibble = ");
    Serial.print(lo_nibble );
    Serial.print(", high nibble = ");
    Serial.println(hi_nibble);
  }

Martyn.

What confuses me is why my program does not yield a random result. I just rolled 7 identical pair of dice in a row as 4 and 1. The program is scanning through all digits full speed and should stop as soon as the button is pushed. That should be random.

I also don't know how to make my code display in the forum properly.

I also don’t know how to make my code display in the forum properly

Remove the colon from this…

[code:]

Ah ha! I think I know why your program is not working correctly. Comment-out the calls to delay(time1);. I know the count-feature will no longer work but that can be fixed later.

Remove the colon from this...

Ah ha!  I think I know why your program is not working correctly.  Comment-out the calls to delay(time1);.  I know the count-feature will no longer work but that can be fixed later.
[/quote]
I no longer am allowed to edit my first post.  I'll try it next time.

I commented out all 6 delay(time1) and now the dice hit 4, 1 90% of the time!

I no longer am allowed to edit my first post.

Bummer.

I'll try it next time.

Don't bother. Once Edit disappears it never comes back.

I commented out all 6 delay(time1) and now the dice hit 4, 1 90% of the time!

Huh. Not what I expected but it proves the delay(time1) calls were having an affect.

This is what I know... The parameter passed to delay is the minimum delay not the guaranteed delay. In other words, sometimes delay(0) will return right away and sometimes it will delay for a bit. It depends on where the hardware timer is in the sequence.

This is what I suspect... With the delay(time1) calls in the Sketch, the loop gets into a pattern where there really is a delay while the upper-four is displayed but no delay while the other values are displayed. This would make upper-four much more likely to occur. If this really is a problem, the solution is simple: put if ( time1 > 0 ) in front of the delay calls.

This is what I expected... With the delay(time1) calls removed, I expected a dramatic improvement. There are other potential problems but I didn't think they would be significant.

The other hitch in your git along...

There are two more things that alter the timing of loop and may interfere with the randomness. The first is the actual call to loop. It adds a call, return, and jump between the 6-6 display and the 1-1 display. It's probably 6 clock cycles. But if this was the culprit, I'd expect more 1-1's than anything else.

The second potential problem is the interrupt service routine for millis. It adds dozens of clock cycles at some point in loop. I have a difficult time believing that the interrupt would occur so well synchronized with loop. But, I've seen stranger things.

More confusion... I built the circuit for the low-fast-die using a Teensy. It seems to work fairly well. I'm not seeing anything close to the patterns you're seeing.

I'm willing to continue trying to help in any way I can but it may be time to consider a different approach.

Hi, take a look at my code located on my Blog. I think it's random enough :)

http://www.tuki-tam.net/blog/?p=83

Regards, Peter

Coding Badly: You have given my good insight to the strange internals of the microcontroller hardware and its libraries. I still can't fully understand the actions of my program but I guess I must bite the bullet and use the Random function as has Odisej. I will make sure I name my variable "zrebana", whatever that is.

A further note: when I put timer1 to 5 milliseconds instead of zero in the fast rolling loop, the result, at first look, appears random!

Oh my god, I'm so sory, I forgot to write the variables in english, my bad.

I comented the code posted on my blog so here goes:

variables -> english

pavza -> pause tipka -> button klik -> pin assigned to the button that triggers the program zrebana -> the random number (on dice) chosen by the function

functions (TAB 2): ena() -> "number" one on the dice dve() -> "number" two on the dice ...

/////////////// eeprom=EEPROM.read(0); //lines needed for producing random numbers eeprom+=1; EEPROM.write(0, eeprom); randomSeed(eeprom); /////////////// eeprom is a variable that stores a number. This number is saved in eeprom on position 0. Then you take it and do eeprom+=1 and write a bigger number in the same place. This is done because you have to do randomSeed() around differend value every time you start your arduino to get random numbers. In other words, if you don't do this, random numbers will still be random, but if you write them down, they will be the same EVERY time you start your board. (this is due to the random function. There is no random in mathematics.)

In setup() I do a "circle" with the leds and then shut them down. (see the movie).

In loop() the program reads, if the button is pressed. While the button is pressed you basicly skip the "whole" code right to ELSE and circle the six numbers on the dice and draw next random number with zrebana = random(1,7); and then over and over again, until you release the button. Then you go into the IF and choose the second IF accorting to the number drawn in the previous loop. You do three loops in for() to simulate slowing down and stop at the drawn number. Re-set "pavza" to initial value and "zrebana" to 0 to skip "slowing down" until you press the button down again (this is to maintain system's respons time short and to keep the drawn number "on" the dice).

Hope it makes more sence :)

Regards, Peter

I guess I must bite the bullet and use the Random function

I think you could still get it to work but it would require the use of a timer and dramatically restructuring your code.

A further note: when I put timer1 to 5 milliseconds instead of zero in the fast rolling loop, the result, at first look, appears random!

The 5ms is significantly longer than the other stuff (like the millis interrupt) so they have a much smaller affect on the roll.

Makes sense. Thanks.

O_o While I haven't gotten my arduino yet, I am a pretty good programmer, and I'm wondering why it's hard to get a random number? There is a randomSeed command, and a random command. You set the seed to be different every time, and it will be random. Pretty simple to do... I think anyway. XD Like I said, I haven't gotten my arduino yet, so I can't test.

   randomSeed(micros()) //random based on microseconds

   //remember, there are 1,000,000 microseconds in a second, so the odds 
   //of hitting the same number once is rare,
   //but to hit the same number every single time would just be crazy rare,
   //so this should work great.

   value1 = random(1,6); //random value of 1 through 6 based on new seed

O-o just an idea is all. (I have a dice program I've already wrote in anticipation of my arduino arriving, so I put a little thought into this myself.)

I have the luxury of programming in different languages before coming to arduino, so programming something that's easy for me.

I bet you are a good programmer, but have you ever done this on a microcontroller? Try a simple program, that will only contain: randomSeed(micros()) (in setup() for example) and then to value1 = random(1,6); Serial.println(value1); delay(500); Look and wonder, the numbers will ALWAYS be the same, when you start the microcontroller. Try to look at this this way: microcontroller starts loading bootloader, but it always performs the same routine that always takes the same amount of time (as the clock speed->MIPS are always the same, right) and therefor you always perform a randomSeed with the same number. No matter how you put it, you can predict the first few numbers at least.

Regards, Peter

They will be the same for one reason, the seed will always be 0 the first time through. All you should have to do to fix that is place the randomSeed(micros()) at the beginning of your loop, or every time you press the button. (I would suggest every press of the button, it should yield the same results either way, but doesn't run the needless seed setting every loop.)

Here is what I have for the dice sketch I mocked up:

//cm Roll Dice program

int roll = 1;  //Button to get new roll
int die11 = 3; //led 1 for die 1
int die12 = 4; //led 2 for die 1
int die13 = 5; //led 3 for die 1
int die14 = 6; //led 4 for die 1
int die15 = 7; //led 5 for die 1
int die16 = 8; //led 6 for die 1
int die21 = 9; //led 1 for die 2
int die22 = 10; //led 2 for die 2
int die23 = 11; //led 3 for die 2
int die24 = 12; //led 4 for die 2
int die25 = 13; //led 5 for die 2
int die26 = 14; //led 6 for die 2


//I plan to separate my physical variables (things going to and from physical world objects
//and virtual variables (values only seen by the arduino)
int value1; //die #1
int value2; //die #2

void setup()
{
 pinMode(roll, INPUT);
 pinMode(die11,OUTPUT);
 pinMode(die12,OUTPUT);
 pinMode(die13,OUTPUT);
 pinMode(die14,OUTPUT);
 pinMode(die15,OUTPUT);
 pinMode(die16,OUTPUT);
 pinMode(die21,OUTPUT);
 pinMode(die22,OUTPUT);
 pinMode(die23,OUTPUT);
 pinMode(die24,OUTPUT);
 pinMode(die25,OUTPUT);
 pinMode(die26,OUTPUT);


 Serial.begin(9600);//To delete later, simply for checking results as values
}

void loop()
{
 if(digitalRead(roll) == HIGH)
 {
   randomSeed(micros()); //random based on microseconds
                        //remember, there are 1,000,000 microseconds in a second, so the odds of hitting the same number once is rare,
                        //but to hit the same number every single time would just be crazy rare, so this should work great.
   value1 = random(1,6); //random value of 1 through 6 based on new seed
  
   if(value1 >= 1)
   {
     digitalWrite(die11, HIGH);
   }else{
     digitalWrite(die11, LOW); 
   }
   
   if(value1 >= 2)
   {
     digitalWrite(die12, HIGH);
   }else{
     digitalWrite(die12, LOW); 
   }
   
   if(value1 >= 3)
   {
     digitalWrite(die13, HIGH);
   }else{
     digitalWrite(die13, LOW); 
   }
   
   if(value1 >= 4)
   {
     digitalWrite(die14, HIGH);
   }else{
     digitalWrite(die14, LOW); 
   }
   
   if(value1 >= 5)
   {
     digitalWrite(die15, HIGH);
   }else{
     digitalWrite(die15, LOW); 
   }
   
   if(value1 >= 6)
   {
     digitalWrite(die16, HIGH);
   }else{
     digitalWrite(die16, LOW); 
   }
   
   
   
   randomSeed(micros()); //random based on microseconds
   value2 = random(1,6); //random value of 1 through 6 based on new seed
   
    if(value2 >= 1)
   {
     digitalWrite(die21, HIGH);
   }else{
     digitalWrite(die21, LOW); 
   }
   
   if(value2 >= 2)
   {
     digitalWrite(die22, HIGH);
   }else{
     digitalWrite(die22, LOW); 
   }
   
   if(value2 >= 3)
   {
     digitalWrite(die23, HIGH);
   }else{
     digitalWrite(die23, LOW); 
   }
   
   if(value2 >= 4)
   {
     digitalWrite(die24, HIGH);
   }else{
     digitalWrite(die24, LOW); 
   }
   
   if(value2 >= 5)
   {
     digitalWrite(die25, HIGH);
   }else{
     digitalWrite(die25, LOW); 
   }
   
   if(value2 >= 6)
   {
     digitalWrite(die26, HIGH);
   }else{
     digitalWrite(die26, LOW); 
   }
//   Serial.println("Value1: " + value1 + "         Value2: " + value2);
 }
}

Now, will that work? I don't know. It depends on how the Random works on Arduino. You may have to have a random variable to get a random number, and reset the seed on that every time.

Also, I would test it like you suggest, but as stated originally, my arduino isn't here yet, it's in shipping.... from china XD (someone got it off of ebay for me for christmas)

The purpose for the command random is to generate a random number, so there is a way to get it to produce a random sequence. It shouldn't be too hard. If it couldn't generate a random number, I don't think the creators of the arduino would have built it into the default library.

Here is the random variable form I am talking about. Some things like VB require you to set a random variable, otherwise you get the same number because it only gets the first value of the seed.

random myRand; //random number generator for dice

void loop()
{
 myRand.randomSeed(micros()); //seed from microseconds
 value1 = myRand.random(1,6); //sets value to random number from 1 to 6
}