> [TOC] # **Introdução Teórica** **O que é Máquinas de Estados?** Máquina de Estados é um modelo matemático usado para representar programas de computadores ou circuitos lógicos. O conceito é concebido como uma máquina abstrata que deve estar em um estado de um número finito de estados. Máquinas de estado são utilizadas para descrever circuitos sequenciais. Diferentemente de um contador que em geral conta eventos, uma máquina de estado costuma ser usada para controlar o evento. **Conceitos importantes** A máquina está em apenas um estado por vez, este estado é chamado de **estado atual**. Um estado armazena informações sobre o passado, isto é, ele reflete as mudanças desde a entrada num estado, no início do sistema, até o momento presente. O **estado inicial** é o estado por onde se começa a leitura de um diagrama de estado e o **estado final** é o estado que representa o fim de uma máquina. Os estados inicial e final são obrigatórios em toda máquina de estados A **transição** é um conjunto de ações a serem executadas quando uma condição for cumprida ou quando um evento é recebido. Uma transição indica uma mudança de estado e é descrita por uma condição que precisa ser realizada para que a transição ocorra. Uma **condição** é causa necessária para que haja a transição de estado. Decorre da ocorrência de um evento ou circunstância que propicia a transição de estado. Um estado descreve um **nó** de comportamento do sistema quando está à espera de uma condição para executar uma transição. Normalmente, um estado é introduzido quando o sistema não reage da mesma forma para uma mesma condição. No exemplo de um sistema de rádio de carro, quando se está ouvindo uma estação de rádio, o estímulo "próximo" significa ir para a próxima estação. Mas quando o sistema está no estado de CD, o estímulo "próximo" significa ir para a próxima faixa. Uma **ação** é a descrição de uma atividade que deve ser realizada num determinado momento. No exemplo anterior o mesmo estímulo desencadeia ações diferentes, dependendo do estado atual. Em algumas representações de máquinas de estado, também é possível associar ações a um estado: - Ação de entrada: o que é realizado ao entrar no estado. - Ação de saída: o que é executado ao sair do estado. **Diagrama de Estados** O Diagrama de Máquina de Estados é uma representação do estado ou situação em que um objeto pode se encontrar no decorrer da execução de processos de um sistema. Com isso, o objeto pode passar de um estado inicial para um estado final através de uma transição. Um exemplo simples seria um semáforo (sinal de trânsito). Cada estado corresponde a uma situação que ocorrerá. Quando verde, os carros podem prosseguir na via. Passado um tempo, é acionada a tarefa de mudar para amarelo. Então o semáforo passa de verde para amarelo. Aqui os carros ficam em estado de atenção e já aguardam a próxima transição. O próximo passo é passar para vermelho. Nesse estado, os carros estão parados na via. De vermelho, o próximo estado somente será verde, assim, os carros podem voltar a trafegar na via. ![](https://i.imgur.com/4Ck42yC.png) Outro exemplo seria as estações do ano. Novamente cada estado corresponde a uma situação que ocorrerá. Em dezembro inicia-se o verão, onde o tempo é quente, chove muito e tem enchente. Em meados de abril, ocorre a transição para o estado outono, quando, do nada, as chuvas param, ficando seco, mas com névoa pelas manhãs. Quando chega junho, ocorre a transição para o estado inverno, quando as pessoas alérgicas se ferram muito pois além de seco, é frio (pra mim abaixo de 25 °C já é frio). Quando chega setembro, ocorre a transição para o estado primavera, que é quando volta o calor infernal e as enchentes, não passa de um verão sem carnaval. Quando chega dezembro ocorre a transição para o estado verão e assm sucessivamente. ![](https://i.imgur.com/u0yeyde.png) Além da vizualização no formato de diagrama, é muito comum a utilização da **tabela de transição de estados** para vizualizar como se comportará seu código. Através do uso das tabelas podemos representar uma máquina de estados que contenha informações completas sobre as ações. No exemplo abaixo a combinação do estado atual (ex: B) com uma condição (ex: Y) determina o próximo estado (ex: C). ![](https://i.imgur.com/qhNphbK.png) **Por que usar Máquinas de Estados em seu projeto?** Nosso robô é um agente. Um agente é algo que percebe o ambiente dele através de sensores e atua sobre o ambiente dele através de atuadores. E o que nós queremos do nosso agente? Ele é um robô de sumô. O que queremos é que ele evite sair do dojo e empurre o oponente para fora. Assim, não é aceitável que ele se mova de qualquer forma. Nós queremos que ele se comporte de forma racional. Isso é encargo da programação: comandar os atuadores, os motores, de forma racional. Se depender de nós, podemos dizer como o robô deve se movimentar de forma a se comportar racionalmente. Se ele estiver de frente para o oponente, deveria partir para cima em linha reta. Se estiver na borda, tem de recuar e mudar de direção. No entanto, o robô tem que tomar essas decisões sozinho. Portanto, o problema, agora, é: como codificar essa lógica? Como podemos formalizar ela de forma que um computador consiga executá-la? É aqui que introduzimos a ideia de máquinas de estados. Queremos que o robô tome decisões de locomoção com base no que os sensores observam e também com base em sua memória de eventos passados. Podemos modelar isso como uma máquina de estados: a memória é representada pelos estados. Observações produzem eventos que resultam em transições de estado e ações a serem executadas. # **Criando um projeto** **Criando o projeto no VSCODE pela PlatformIO** 1. Clique no ícone do PlatformIO no lado esquerdo do seu VSCODE 2. Open 3. New Project 4. Dê o nome ao seu projeto 5. Selecione a placa que irá usar em seu projeto **Biblioteca SML** A biblioteca SML é a responsável por todo o modo de funcionamento da máquina de estados. Para adicionar a biblioteca SML no seu VSCODE, basta baixá-la através deste [site](https://boost-ext.github.io/sml/) e seguir os passos: 1. Abrir a pasta da biblioteca "sml-1.1.3" 2. Abrir a pasta "include" 3. Copiar a pasta "boost" 4. Colá-la na "lib" de seu projeto criado na PlatformIO > Você também pode colar a pasta "boost" na pasta "lib" através do seu computador. > [color=#d61908] E pronto! Você já terá adicionado a biblioteca. # **Configurando a PlatformIO** As configurações do PlatformIO podem ser editadas através do "plarformio.ini". Nela você terá as especificações, que foram determinadas quando seu projeto foi criado. **Ambientes de comunicação** Caso queira ter mais de um ambiente de compilação, com diferentes plataformas e placas, é necessário especificar no "platformio.ini" modificando-as de acordo com o que desejar. Como exemplo: ``` [env:Projeto1] platform = atmelavr board = nanoatmega328 framework = arduino [env:Projeto2] platform = atmelavr board = uno framework = arduino ``` Neste caso, há o "Projeto1" que usa placa Arduino MEGA 328 e o "Projeto2" que usa o Arduino UNO. O PlatformIO irá perguntar a você qual ambiente gostará de trabalhar, porém, pode ser definido usando o comando `default_envs`. Desta forma, ele irá priorizar o uso de um específico ambiente somente. Como exemplo: ``` default_envs = Projeto1 ``` > `env` : significa "environment", ou seja, o ambiente no qual estará trabalhando. **Portas de comunicação** PlatformIO detecta automaticamente a porta de upload por padrão. Mas, você pode configurar uma porta personalizada usando a opção `upload_port`. Como exemplo: ``` upload_port = COMxx ``` Esta porta é uma comunicação que o seu sistema operacional cria para você. Lembrando que o nome desta porta varia de acordo com o sistema usado(Windowns, Linux, MAC...). Mesmo que o PlatformIO detecte a porta para você, é de bom costume que se defina a porta. Caso não saiba qual está sendo usada, basta: 1. Abrir a IDE do Arduino 2. Ferramentas 3. Portas E ver qual porta tem um dispositivo conectado. # **Código** ## **1) Incluindo a biblioteca SML:** ``` #include <sml.hpp> ``` > Como a biblioteca do Arduino foi incluída, pode-se usar livremente a sintaxe de programação deste. > [color=#d61908] Para se obster de erros, é de bom hábito que se inclua primeiro a biblioteca SML, e conseguinte a do Arduino, desta forma: ``` #include <sml.hpp> #include <Arduino.h> ``` ## **2) Criando eventos** A forma mais simples de se criar um evento, é usando`struct`, que é uma variável especial que contém diversas outras variáveis normalmente de tipos diferentes. [Clique aqui](https://http://linguagemc.com.br/struct-em-c/) para mais informações sobre `struct`. Entao, é através de uma `struct` que você vai determinar quais eventos farão a transição dos estados. Exemplo: ``` struct NomeDoEvento {}; ``` > `NomeDoEvento` representa uma classe > A struct pode ser vazia {}; ou não {x; y; z;}; > [color=#d61908] ## **3) Criando a máquina de estados** Para se criar uma máquina, também se usa uma `struct`, que irá conter a máquina de estado e para tal fato, deve-se usar a função`auto operator()(){}`. >`auto operator` irá definir a máquina de estados. > [color=#d61908] Passo a passo: 1. Dizer que está usando a biblioteca, que no caso, é a sml, ou seja: `using boost::sml` 2. Adicionar uma tabela de transição, ou seja: `return make_transition_table();` > `transition_table();` é um função que está dentro da biblioteca SML. Ela é responsável por criar a tabela de transição de estados. > Sintaxe: `make_transition_table(transições);` > [color=#d61908] - Resumo: ``` struct NomeDaMaquinaDeEstados{ auto operator()(){ using boost::sml; return make_transition_table( transições ); } }; ``` ## **4) Informando que é um estado** Ao iniciar a criação dos estados, para que eles sejam reconhecidos como tal, é necessário acrescentar `_s` no final. Exemplo: ``` "NomeDoEstado"_s ``` ## **5) Estado inicial** Toda máquina deve ter o estado inicial, que é definido pelo operador `*`, podendo ser nomeado entre `""` da forma que quiser, então exemplo: ``` *"estopim" ``` Uma vez que você tenha definido seu estado inicial, basta acrescentar o `_s`, para oficialmente ele ser um estado. Logo: ``` *"estopim"_s` ``` ## **6) Transitando de um estado para o outro** Ao entrar no estado, em algum momento você sairá dele, certo? Então: 1. Para mostrar qual ação irá ser tomada assim que sair de um estado, basta usar: `/` 2. Logo após a passagem de transição deve-se passar uma função lambda: `[] {}` 3. Por fim, deve-se definir qual estado deve ser transitado usando: `= "NomeDoEstado"_s` Exemplo 1 : `*"estopim"_s / []{} = "proximoEstado"_s,` Assim que entrar na máquina de estados, o estado inicial é transitado para o proximoEstado, sem nenhuma causalidade. > A função lambda representa a ação de transição do estado. Exemplo 2: > `*"estopim"_s / []{digitalWrite(ledBranco,HIGH);} = "proximoEstado"_s,` [color=#d61908] > > Do estado inicial `"estopim"`, a transição para o `proximoEstado` causa a ação de ligar o led branco. ## **7) Causando uma condição de transição através de um evento** No exemplo acima, não existe nenhuma causa para que o estado inicial seja transitado para o `proximoEstado`. Mas, caso queira que exista esta causalidade, ela pode ser gerada por algum evento. Para definir que um estado irá transitar para outro, somente se um evento acontecer, basta adicionar:`+ event<NomeDoEvento>`, antes da transição (`/`) acontecer. Exemplo: ``` *"estopim"_s + event<evento1> / []{} = "proximoEstado"_s, ``` Então, o estado inicial `"estopim"` irá transitar para o `proximoEstado` , somente se o `evento1` acontecer. Para se obter uma transição automática, ou seja, sem nenhuma causalidade do evento, você pode usar:`+ on_entry<_>` antes da transição ocorrer. Exemplo: ``` *"estopim"_s + on_entry<_> / []{} = "proximoEstado"_s, ``` ## **8) Instanciando uma máquina de estados** Para instanciar uma máquina de estados, usa-se uma função da biblioteca SML, que trás a classe em que sua máquina foi definida e gera um objeto a ela. Esta função é a `sm`(state machine). Veja o exemplo: `sml::sm<NomeDaClasseDaMáquina> NomeDoObjetoDaMáquina;` Desta forma você emite os eventos criados para a máquina. Lebrando que `NomeDaClasseDaMáquina` é uma struct, definida no tópico 3). ## **9) Instanciando um evento** Instanciar um evento, significa que você estará processando o evento dentro da máquina. Para isso, usa-se a função `process_event`. Exemplo exemplo: `NomeDoObjetoDaMáquina.process_event(NomeDoEvento {});` Lembrando que `NomeDoEvento`, é uma struct, definida no tópico 2), que vai se referir ao evento que você deseja que seja processado, ou seja, o evento de transição. ![](https://i.imgur.com/ZvZFvkV.png) NEM ACREDITO QUE TERMINAMO ;-;