quarta-feira, 4 de abril de 2018

Arduino - Brincando com números aleatórios - Usando as funções random() e randomSeed()



Existem vários casos em que um projeto precisa de uma sequência de números gerados de forma aleatória, por exemplo, para fazer um sorteio, criar um número de identificação ou fornecer uma senha token e o Arduino, mais uma vez, mostra-se ser uma ferramenta poderosa nos possibilitando realizar essa tarefa. Nesse artigo iremos aprender sobre a função random() e utilizá-la para gerar uma sequência de números aleatórios com o Arduino. Também iremos fazer um exemplo de “dado de 6 lados” eletrônico.


Gerar números aleatórios com um Arduino não se resume a implementar uma função ao código, no caso, a função random(). Na verdade é impossível gerar números verdadeiramente aleatórios com o Arduino, o melhor que podemos fazer é embaralhar uma  sequência pré definida dando-nos a impressão de aleatoriedade.

A função random(), toda vez que chamada, nos dá um número pseudo aleatório que esteja dentro de uma faixa de possíveis valores. Por exemplo, se escrevermos a função da seguinte forma:

random(100);

Teremos como retorno qualquer valor entre 0 e 99, ou seja, o número que vai entre os parênteses define o valor máximo que poderá ser retornado, porém, ele é excluído dos possíveis valores, restando apenas máximo - 1 (máximo menos um) como maior valor.

Se quisermos definir uma faixa de valores com o valor mínimo diferente de 0 (zero) precisamos escrever a função assim:

random(mínimo (inclusivo), máximo (exclusivo));

Isto significa que o valor mínimo estabelecido entrará entre os possíveis números retornados, mas o maior valor continuará sendo máximo - 1 (máximo menos um). Por exemplo:

random(5, 11);

Poderá nos retornar qualquer um desses valores: 5, 6, 7, 8, 9, 10, mas não retornará o 11!

Ok, mas por que os números retornados são pseudo aleatórios?

Imagine que vários números estão passando em sua frente e você tem que escolher um. Você simplesmente pensa no momento de parar a apresentação dos números e dessa forma escolhe algum, veja bem, você tomou uma decisão. O Arduíno por ser um computador com um sistema operacional simples não possui a capacidade de tomar decisões, para isso ele teria que ser dotado de algum tipo de inteligência artificial! E é por conta disso que ele possui um mecanismo que gera sempre a mesma sequência de números fora de ordem e toda vez que você reiniciar o Arduino ele fará uso da mesma sequência pra te apresentar valores “aleatórios”.

Para resolver isso fazemos uso de outra função, a randomSeed(). Essa função nos permite, de certa forma, modificar o mecanismo que gera a sequência de números fora de ordem. Essa modificação se dá pela inserção de um valor qualquer no argumento da função randomSeed(), por exemplo: randomSeed(10) forçará a função random() a gerar uma sequência totalmente diferente do que se escolhêssemos randomSeed(qualquer número diferente de 10).

Mas calma aí, o problema ainda não está resolvido... Acho que ninguém pretende ficar inserindo valores manualmente no Arduino, então, o que pode ser feito?

Se efetuarmos a leitura de uma porta analógica que não esteja ligada a nada, perceberemos valores aleatórios que podem variar de 0 a 1023, esses números aparecem por que a porta está em um estado de “flutuação”, sujeita a interferências eletrostáticas do ambiente (leia esse artigo para entender mais). Se juntarmos essa leitura aleatória de uma porta analógica com a função randomSeed() teremos a solução para o nosso problema, e isso é feito da seguinte forma:

randomSeed(analogRead(porta analógica qualquer));

Com isso estaremos permitindo que a “flutuação” da porta analógica insira novos valores no argumento da função randomSeed() toda vez que ela for solicitada.

Fazendo um “dado de seis lados” com Arduino


Já sabemos como usar a função random(), juntamente com a randomSeed(), agora está na hora de aplicarmos isso. Uma maneira simples de mostrar o resultado da execução dessas funções é fazendo um código que gere números aleatórios de 1 até 6, fazendo com que uma quantidade de leds acenda de acordo ao valor sorteado. Os leds serão apenas para efeito de visualização.  O código para esse exemplo está a seguir, logo após, explicaremos o funcionamento dele:

int bot = 2;
int analog = A0;
int led1=8; int led2=9; int led3=10; int led4=11; int led5=12; int led6=13;
int valor;

void setup() {
 
  pinMode(bot, INPUT_PULLUP);
  pinMode(analog, INPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(led5, OUTPUT);
  pinMode(led6, OUTPUT);

  Serial.begin(9600);
  randomSeed(analogRead(analog));

}

void jogar(){
  for(int cont=1;cont<=3;cont++){
      digitalWrite(led1, HIGH);
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      digitalWrite(led4, HIGH);
      digitalWrite(led5, HIGH);
      digitalWrite(led6, HIGH);
      delay(200);
      digitalWrite(led1, LOW);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      digitalWrite(led4, LOW);
      digitalWrite(led5, LOW);
      digitalWrite(led6, LOW);
      delay(200);     
    }
  }

void loop() {

  if(digitalRead(bot)== LOW){
      Serial.println("O dado foi jogado");
      jogar();
      valor = random(1,7);
      Serial.println(valor);
    }
  if(valor==1){
    digitalWrite(led1, HIGH);
    }else{
      if(valor==2){
        digitalWrite(led1, HIGH);
        digitalWrite(led2, HIGH);
        }else{
          if(valor==3){
            digitalWrite(led1, HIGH);
            digitalWrite(led2, HIGH);
            digitalWrite(led3, HIGH);
            }else{
              if(valor==4){
                digitalWrite(led1, HIGH);
                digitalWrite(led2, HIGH);
                digitalWrite(led3, HIGH);
                digitalWrite(led4, HIGH);
                }else{
                  if(valor==5){
                    digitalWrite(led1, HIGH);
                    digitalWrite(led2, HIGH);
                    digitalWrite(led3, HIGH);
                    digitalWrite(led4, HIGH);
                    digitalWrite(led5, HIGH);
                    }else{
                      if(valor==6){
                        digitalWrite(led1, HIGH);
                        digitalWrite(led2, HIGH);
                        digitalWrite(led3, HIGH);
                        digitalWrite(led4, HIGH);
                        digitalWrite(led5, HIGH);
                        digitalWrite(led6, HIGH);
                        }
                      }
                  }
              }
          }
      }
delay(500);
}

Nas primeiras linhas do código temos a declaração das variáveis globais que serão usadas. A variável “bot” representa o botão e recebe o valor inteiro 2, que será o número da porta digital em que estará conectado. Em seguida temos “analog” que recebe ‘A0’, essa será a porta analógica lida para fornecer a flutuação usada na função randomSeed(). Logo após, vem a declaração de 6 leds. A última variável declarada é “valor” e ela será responsável por armazenar o número sorteado.

Em “void setup()” teremos a definição de cada porta, se ela será de entrada (IMPUT) ou saída (OUTPUT), perceba que em “bot” foi usada a sintaxe “IMPUT_PULLUP” isso foi feito para ativar o resistor de pull up interno referente a aquela porta (saiba mais aqui). Em seguida teremos a inicialização da serial e por último a implementação da função randomSeed(), no argumento dessa função foi colocada a leitura analógica da porta “A0” que  foi nomeada “analog”. É importante que a randomSeed() seja iniciada em “void setup()” para sua correta execução.

O próximo bloco em nosso código é uma unção criada chama “void jogar()” ela serve para fazer os leds piscarem 3 vezes antes de aparecer o valor sorteado, ela não tem nenhuma importância real, serve apenas para causar um efeito visual.

O último bloco é o “void loop()”, o bloco de repetição, ele ficará rodando o código contido nele até que o botão seja pressionado, quando isso acontecer o estado lógico da porta ligada ao botão passará a ser “LOW” fazendo com que a execução entre no “if”, isso fará com que a função “void jogar()” seja chamada, e como já foi dito, ela fará os leds piscarem e retornará para a execução normal, mas antes disso, será impresso no monitor serial o seguinte: “O dado foi jogado”. É agora que a mágica acontece, a variável “valor” irá receber o número aleatório fornecido pela função random(), esse valor será impresso no monitor serial e logo após virá uma sequência de “if” e “else” aninhados para determinar qual foi o dígito sorteado e, consequentemente, acender a quantidade de leds necessários para nos mostrar o resultado. No final desse bloco temos um delay() de meio segundo para dar uma pausa entre as leituras do botão.

O circuito para fazer esse exemplo dar certo é bem simples, é o seguinte:



Esse circuito conecta os leds nas portas digitais do Arduino e ao ground do mesmo. O botão estabelece uma conexão entre a porta digital 2 e o ground. A porta analógica A0 não vai ligada a nada.

Considerações finais

A função random() por si só não é capaz de fornecer uma sequência de números aleatórios, mas, junta com a função randomSeed() e outro artifício conseguimos obter o resultado desejado. O tamanho máximo do número que pode ser gerado poderá ter até 10 dígitos (é muito grande), mas para isso a variável que receberá o valor deverá ser do tipo “long int”. Assista o vídeo a seguir para ver o exemplo feito aqui:


Um comentário:

  1. Queria fazer uma roleta quando apertasse o botão giraria os 6 leds tocando uma música e depois parasse em um led de forma aleatório piscado 3 vezes tocando outra música e depois apagando pra jogar novamente,teria como me ajudar nesse projeto.Acho que daria pra fazer usando dfplayer

    ResponderExcluir