Projete o seu robô com diagramas de estados

Este artigo é um guia introdutório sobre Diagramas de Estados para robótica, recheado de exemplos. Ele é voltado para estudantes e hobbystas que estão aprendendo programação de sistemas embarcados e querem projetar sistemas um pouco mais complexos

Olá! Você gosta de programar? Que legal! Neste artigo queremos lhe ajudar a programar robôs cada vez mais complexos sem quebrar tanto a cabeça. Ou seja, trazemos um pouquinho do mundo da Engenharia de Software para o mundo da Robótica.

Afinal, programar robôs é difícil! Quem nunca #partiucodar depois de ter uma ideia bacana, e depois se complicou quando o projeto foi crescendo? Como código-fonte é algo muito concreto, acabamos imersos nos detalhes e perdemos a noção do todo.

À medida que nossos robôs ficam maiores e mais complexos, torna-se ainda mais importante recuperarmos a visão do todo. Para isso, podemos trabalhar com alguns diagramas simples que descrevem o comportamento do sistema que estamos construindo, como é o caso dos diagramas de estados, também conhecidos como statecharts ou ainda como diagramas de máquinas de estados.

Veja só, é que programar um robô para fazer apenas uma coisa simples é… razoavelmente simples. Mas programar um robô para fazer várias coisas simples, ou até mesmo algumas coisas complicadas, é uma tarefa complexa! Ler as distâncias com o sonar, andar um pouquinho, calcular a distância percorrida, virar para um lado, virar para o outro, opa! vai bater, é melhor desviar! Ufa, se não tivermos cuidado vamos acabar com um código espaguete, difícil de manter e propenso a erros. Para evitar isso vale a pena parar de programar um pouco e desenhar o nosso robô.

Como assim?! Desenhar? Sim, vamos desenhar o comportamento do robô. Uma das formas mais fáceis de se fazer isso é com diagramas de estados!

Diagramas de Estados 

Vamos começar projetando um sistema com um LED simples que pode ser ligado e desligado através de um único botão (Figura 1). Afinal, qual a graça em fazer um robô se ele não tiver luzinhas?

diagramas de estados
Figura 1 – um LED que liga e desliga quando um botão é apertado

Neste nosso primeiro exemplo os estados em que um LED pode estar são LED LIGADO ou LED DESLIGADO. Esses estados são representados pelas caixas com os cantos arredondados. O círculo preto com uma seta indica o estado inicial; ou seja, o LED já começará ligado. 

As outras setas mostram como o sistema pode entrar ou sair de cada estado. No caso, se o LED estiver ligado e alguém apertar o botão, o LED passará a estar desligado (seta para baixo). Já se o LED estiver desligado e o mesmo evento ocorrer (ou seja, se alguém apertar o mesmo botão), o LED voltará a ficar ligado. 

A mudança de um estado para outro é chamada de transição, e aquilo que provoca a transição é chamado de evento.

Tranquilo até agora? Deu para perceber que é possível desenhar (literalmente) o comportamento de um sistema, sem ser preciso escrever uma linha de código sequer? Claro que esse exemplo não é lá muito complicado, é apenas uma lanterna qualquer que todo mundo conhece. Quanto mais complexo for o seu robô, no entanto, maior será o benefício de se criar diagramas de estados:

  • É mais fácil de escrever e entender, quando comparado com código. Sendo assim, podemos utilizá-los em reuniões para discutir o comportamento desejado do sistema;
  • É mais compacto do que código, então podemos visualizar em uma única folha o equivalente a várias páginas de código;
  • Pode ser simulado, permitindo validar o comportamento do nosso robô antes mesmo de construí-lo;
  • Serve como uma guia para estruturação do seu código, especialmente quando se usa padrões de projetos ou bibliotecas específicas – veja esse artigo sobre como implementar uma máquina de estados;
  • Com a ferramenta adequada, podem ser utilizados para geração automática de código-fonte.

Por outro lado, a criação dos diagramas requer também o esforço para mantê-los atualizados no decorrer do projeto, pois de nada adianta ter um diagrama se ele não está consistente com o código.

Ah, e esses diagramas não são nenhuma bala de prata não. Por exemplo, eles não são muito bons para sistemas de informação, data science, processamento de imagens, ou qualquer outro sistema cujo foco seja o processamento de dados. Eles são mais adequados para sistemas que precisam reagir a eventos, como é o caso do front-end de sistemas web, e também de muitos dos sistemas embarcados, como: robôs, televisões, sistemas automotivos, máquina de lavar roupa, semáforos, etc.

Quando criamos diagramas de estado, podemos descrever, basicamente:

  • Os possíveis estados do sistema;
  • O estado no qual o sistema irá começar;
  • As mudanças de estado (transições) que podem ocorrer;
  • Quando as transições devem ocorrer (eventos e condições);
  • As ações que devem ser executadas. 

Os eventos são qualquer coisa que pode acontecer e provocar transições, fazendo com que o sistema saia de um estado e entre em outro a depender de condições específicas. Por exemplo, quando alguém aperta um botão, ou quando se passou um certo tempo, ou quando algum sensor detecta a presença de uma pessoa.

No restante deste artigo são apresentados, com exemplos, os principais conceitos utilizados em diagramas de estados.

Condições

A Figura 2 mostra um exemplo bem parecido com o exemplo anterior, mas agora o nosso sistema é um pouquinho mais inteligente.

diagramas de estados
Figura 2 – um LED que liga e desliga quando um botão é apertado, mas só desliga se o lugar estiver claro (luminosidade alta)

Neste exemplo os estados em que um LED pode estar continuam a ser LED LIGADO ou LED DESLIGADO. No entanto, acrescentamos uma condição determinando que o LED só pode ser desligado se a luminosidade for maior ou igual a 30 (ou seja, quando estiver claro). Dessa forma, quando o LED estiver ligado e a iluminação for maior ou igual 30, se o evento “apertar_botao” ocorrer teremos uma transição demonstrada pela seta para baixo, passando do estado ligado para desligado. Já se alguém apertar o botão, mas o robô estiver em um lugar escuro (ou seja, se a iluminação não for maior ou igual a 30), não ocorrerá nada – o LED continuará ligado.

Observe que “luminosidade” é uma variável do nosso sistema, cujo valor pode ser obtido de diversas formas: 

  • talvez o robô tenha um teclado que permita que alguém digite o valor da iluminação; 
  • ou então o robô recebe esse valor através de uma API disponibilizada pela Internet; 
  • ou, o que é mais provável, o robô conta com um sensor de luminosidade que atualiza o valor dessa variável periodicamente.

Transições Automáticas

Com o diagrama de estados é possível modelar sistemas que funcionam de forma automática também, reagindo a mudanças no ambiente de acordo com alguma condição, como na Figura 3.

diagramas de estados
Figura 3 – um LED que liga e desliga automaticamente de acordo com a luminosidade

Os estados do LED continuam a ser LED LIGADO ou LED DESLIGADO, no entanto a especificação das transições foi modificada para levar em conta apenas uma condição referente à luminosidade do ambiente. Desta forma sempre (always) que o LED estiver ligado e a luminosidade for maior ou igual a 30 teremos a transição representada pela seta para baixo, passando do estado ligado para desligado, mesmo que ninguém aperte qualquer botão. Assim como antes, as condições são escritas dentro de colchetes. De forma similar, quando o LED estiver desligado e a iluminação for menor que 30, ocorrerá uma transição representada pela seta para cima: o LED passará do estado desligado para ligado.

Neste exemplo usamos always, expressão que pode ser usada quando queremos que uma transição ocorra sem depender da ocorrência de um evento específico, sendo normalmente complementada com uma condição. Neste nosso exemplo as condições são referentes a um valor de iluminação, então o sistema funcionará como aqueles postes de iluminação que apagam durante o dia e acendem automaticamente à noite.

Ao contrário de eventos, as condições podem ser combinadas utilizando operadores lógicos: AND, OR e NOT. Por exemplo, podemos querer acender o LED apenas quando a iluminação for menor que 30 e (AND) a presença de alguma pessoa for detectada.

Observe a complementaridade das condições >= 30 e < 30. Se tivéssemos escrito apenas > 30 e < 30, não saberíamos o que iria acontecer quando a luminosidade fosse exatamente igual a 30.

Eventos Temporais

Podemos também modelar sistemas com eventos automáticos atrelados à passagem de tempo, como no exemplo da Figura 4. 

diagramas de estados
Figura 4 – um sistema bem irritante onde o LED desliga sozinho pouco depois de ser acendido (dois segundos)

Neste exemplo, para não perdermos o costume, os estados em que um LED pode estar são LED LIGADO ou LED DESLIGADO. Dois segundos depois do LED ser ligado ele será automaticamente desligado. Já se o LED estiver desligado e for apertado o botão, o LED passará imediatamente a ficar ligado.  Isso acontece, por exemplo, nas lanternas que se desligam automaticamente após um certo tempo, para poupar bateria.

A Figura 5 mostra mais um exemplo com eventos relacionados à passagem do tempo. A diferença, em comparação ao diagrama da Figura 4, é que agora ambas as transições têm o evento temporal (after 2s). Dessa forma, dois segundos após ser ligado, o LED será desligado (seta para baixo). Por sua vez, dois segundos após ser desligado, o LED será ligado (seta para cima). Ou seja, é um pisca-pisca!

diagramas de estados
Figura 5 – um LED que fica piscando

Transições Alternativas

Cada transição só pode ter um evento, mas isso não impede que tenhamos várias formas diferentes de passar de um estado para outro: basta acrescentar múltiplas transições, como na Figura 6. 

Neste exemplo, os estados são LED LIGADO ou LED DESLIGADO e… brincadeirinha! Você já deve ter se cansado da lanterna, não é mesmo?

Vamos lá, o exemplo agora é um robô móvel sobre rodas, similar a um carro. Esse robô pode estar PARADO ou EM MOVIMENTO. Sempre que ocorrer o evento “acelerar” e o robô estiver parado, ocorrerá a transição representada pela seta para baixo passando do estado PARADO para EM MOVIMENTO. 

diagramas de estados
Figura 6 – um robô móvel que se parece bastante com um carro comum

Note que existem duas setas de baixo para cima, informando que dois eventos diferentes podem disparar a transição de EM MOVIMENTO para PARADO: essa transição ocorrerá ou quando o pedal de freio for acionado ou quando o freio de mão for acionado. Nos diagramas de estados não é possível usar o OR com eventos, então transições alternativas como essas são representadas por duas (ou mais) transições separadas.

Hierarquia de estados

Quando nossos sistemas têm muitas transições, o diagrama pode ficar parecendo uma verdadeira macarronada. Veja na Figura 7 um robô que fica a maior parte do tempo parado (OCIOSO), só se movimentando quando recebe algum comando pela porta serial. Ao receber o comando ele executa o respectivo movimento por apenas 1 segundo, antes de parar novamente. Se detectar algum obstáculo ele também irá interromper sua movimentação.

diagramas de estados
Figura 7 – um robô móvel controlado pela porta serial

Uma solução para reduzir o número de transições repetidas é agrupar os estados semelhantes com um superestado. Na Figura 8, o estado EM MOVIMENTO é o superestado dos quatro (sub)estados localizados dentro dele.

diagramas de estados
Figura 8 – um robô móvel controlado pela porta serial, modelado com um superestado

Como as transições que chegam em OCIOSO estão saindo de EM MOVIMENTO, essas transições podem partir de qualquer um dos seus quatro subestados. Assim, a Figura 8 representa exatamente o mesmo comportamento que a Figura 7, mas utilizando a metade do número de transições.

Múltiplos Componentes

Sistemas complexos costumam ter vários componentes operando ao mesmo tempo. Esses sistemas podem ser modelados com regiões ortogonais, um nome feio que quer dizer que essas regiões funcionam de forma simultânea e independente.

No exemplo do Figura 9 vemos um sistema com duas regiões ortogonais, uma ligada à “Movimentação do robô” e a outra ao seu “Farol” (que, cá entre nós, é um LED…). Ambas as regiões são iniciadas de forma simultânea, mas os seus estados e suas transições são independentes. Enquanto na região “Movimentação do robô” os eventos “frear” e “acelerar” são responsáveis por provocar as transições entre os estados EM MOVIMENTO e PARADO, na região “Farol” o evento “apertar_botao” é responsável por provocar as transições entre os estados “FAROL LIGADO” e “FAROL DESLIGADO”.

image 41
Figura 9 – um robô móvel que não apenas anda, mas também tem um farol que liga e desliga

Quando o botão do farol é apertado, a movimentação do carro não é afetada. Da mesma forma, se o piloto do robô frear ou acelerar, o farol permanecerá no mesmo estado. Ou seja, as regiões são independentes. Em qualquer momento, o robô como um todo estará sempre em dois estados simultaneamente, em alguma dessas combinações: PARADO e FAROL DESLIGADO, PARADO e FAROL LIGADO, EM MOVIMENTO e FAROL DESLIGADO, ou EM MOVIMENTO e FAROL LIGADO.

Você conhece o Mario? O Super Mario? Ele pode ficar pequeno ou grande, certo? Ele também pode estar parado ou se mexendo, pode estar sem Yoshi ou com Yoshi, etc.

O tamanho do Mario não afeta a sua movimentação, nem a sua relação com o Yoshi. Podemos representar esse comportamento com regiões ortogonais: uma para o tamanho, outra para a movimentação, outra para a posse do Yoshi, etc.

Ações

Além de estados e suas transições, se quisermos ser mais detalhistas podemos definir também algumas ações que serão realizadas todas as vezes que uma transição ocorrer. Você pode ver um exemplo disso na seta para cima da Figura 10.

image 42
Figura 10 – um sistema com um LED que liga e desliga e que conta quantas vezes o LED foi ligado

Neste exemplo, o nosso querido LED pode estar em dois estados: LED LIGADO ou LED DESLIGADO. O evento “apertar_botao” é responsável por iniciar uma transição entre os estados LED LIGADO e LED DESLIGADO. No momento em que ocorrer a transição do estado LED DESLIGADO para LED LIGADO (seta para cima) ocorrerá a ação que está escrita após a barra (/): o acréscimo em 1 da variável “contador”, que armazena a quantidade de vezes que o LED foi ligado.

Assim como “luminosidade” na Figura 2, o “contador” da Figura 10 é uma variável do nosso sistema. Neste caso, ela terá o seu valor aumentado a cada vez que o LED for ligado.

Mais Exemplos com Ações

Lembra quando o nosso saudoso LED só apagava quando o dia estava claro, na Figura 2? Para isso utilizamos uma variável chamada “luminosidade”. Bom, o que faltou ali foi dizer quando é que essa variável seria atualizada. Vamos ver a seguir dois exemplos onde essa atualização acontece.

image 43
Figura 11 – atualização periódica da luminosidade

Neste exemplo (Figura 11) definimos uma atualização periódica: a função “atualizarLuminosidade” é invocada a cada 30 segundos (after 30s), mas apenas quando o LED estiver ligado.

Na Figura 12 vemos uma especificação alternativa, em que a luminosidade é atualizada a cada vez que alguém tenta desligar o LED (“apertar_botao”).

image 44
Figura 12 – atualização da luminosidade apenas quando o botão é apertado

O que muda deste exemplo para o anterior não é apenas o diagrama em si, mas também o comportamento do sistema. Ao criar um diagrama de estados precisamos pensar e tomar várias decisões de projeto que irão influenciar o resultado final. Já se compararmos esses dois diagramas com a Figura 2, não dá para dizer qual é o mais correto – o que podemos dizer é que os diagramas das figuras 11 e 12 são mais detalhados do que o diagrama da Figura 2.

Um Exemplo Mais Elaborado

Puxa, mas esses exemplos são muito bobos! Ok então, vamos ver na Figura 13 um exemplo de robô autônomo explorando o solo de Marte, unindo vários dos conceitos já introduzidos neste artigo. A ideia é que o robô ande pelo planeta coletando amostras e, de vez em quando, envie dados de volta para uma base na Terra.

image 45
Figura 13 – robô autônomo em Marte

Neste exemplo, os estados são EM MOVIMENTO, COLETANDO AMOSTRA e ENVIANDO DADOS À TERRA. Inicialmente, o nosso robô estará EM MOVIMENTO. Ao se passarem 30 segundos (after 30s) que o sistema se encontra no estado EM MOVIMENTO, teremos uma transição do estado EM MOVIMENTO para COLETANDO AMOSTRA, momento no qual será executada a ação de somar em 1 a quantidade de amostras coletadas.

Quando terminar de coletar a amostra (evento “amostra_coletada”) o robô irá ou voltar para EM MOVIMENTO ou passar para ENVIANDO DADOS À TERRA, a depender da condição expressa na transição. Essas condições são referentes à quantidade de amostras já coletadas. Apenas se o robô já tiver coletado três amostras ou mais, o sistema sairá do estado COLETANDO AMOSTRA para ENVIANDO DADOS À TERRA. Caso contrário, irá voltar para o estado EM MOVIMENTO.

Ao terminar de enviar os dados (evento “dados_enviados”), o robô voltará para o estado EM MOVIMENTO, e ao realizar essa transição o contador de amostras coletadas será resetado (qtd_amostras = 0). Essa transição também pode ocorrer se houver uma falha de comunicação, mas neste caso a variável qtd_amostras não será resetada e, após a próxima coleta, o robô tentará transmitir os dados novamente.

Nível de Detalhamento

Diagramas de estados podem ser tão detalhados quanto quisermos. O diagrama da Figura 8 mostra o comportamento de um robô controlado por um comando recebido pela porta serial. A Figura 14 mostra o mesmo robô, só que agora com mais detalhes.

image 46
Figura 14 – versão detalhada de um robô controlado remotamente, definindo os valores de variáveis específicas

Por um lado, o diagrama da Figura 8 é mais fácil de entender, por ser mais abstrato. Por outro lado, o diagrama da Figura 14 é mais detalhado, com informações que serão úteis durante a programação do robô. As duas opções têm vantagens e desvantagens, cabendo a nós escolher a opção mais adequada para o nosso projeto.

Outro fator que devemos levar em conta na hora de criar os nossos diagramas é que um sistema pode ter, potencialmente, infinitos estados. Sendo assim, precisamos escolher quais estados realmente devem ser incluídos no sistema. A Figura 15 mostra um conjunto de estados de um robô móvel que desvia de obstáculos. Será mesmo necessário modelar tantos estados quanto temos na Figura 15-A, ou os três estados da Figura 15-B são suficientes? 

Para tomar decisões desse tipo, podemos pensar em como o robô irá se comportar em cada estado – se o robô reagir da mesma forma quando estiver MUITO PERTO, BEM PERTO, e MUITÍSSIMO PERTO, então não precisamos discriminar esses estados.

image 47
Figura 15 – dois exemplos similares, mas com diferentes níveis de detalhamento

Ferramentas

Você pode criar diagramas de estados até mesmo na praia, passando o seu dedo na areia. Mas provavelmente seria melhor usar papel e lápis. Se estiver trabalhando em grupo, uma ótima opção para discutir e construir o comportamento do robô é com um quadro branco.

No computador você pode utilizar programas criados especificamente para a modelagem de diagramas de estados, como a Yakindu Statechart Tools. Ferramentas deste tipo possuem os seguintes benefícios:

  • verificação de sintaxe, que avisa quando há erros no diagrama. Por exemplo, uma boa ferramenta iria avisar que o diagrama da Figura 15 está errado, já que ele não especifica os eventos de cada transição;
  • execução de simulações, permitindo que você teste e valide o comportamento do seu robô antes mesmo de construí-lo;
  • geração automática de código a partir dos diagramas.

Ferramentas gerais de desenho, como Microsoft Paint e Adobe Photoshop não são muito boas para esta finalidade. No entanto, ferramentas para desenho de diagramas, como o Microsoft Visio e a diagrams.net (ferramenta online e gratuita), são boas opções.

Para termos certeza que os diagramas deste artigo estão corretos, os testamos com simulações na ferramenta Yakindu. Em seguida, os redesenhamos com diagrams.net, para que ficassem mais bonitinhos…

Conclusão

Pronto, agora você já sabe tudo sobre diagramas de estados! Que nada, na verdade isso é só o começo; à medida que for praticando você irá aprender cada vez mais e talvez sinta a necessidade de conhecer alguns conceitos mais avançados, como ações de entrada de estados, ações de saída de estados e pseudo-estados.

Por sinal, existem diversas variações de diagramas de estados. O que você aprendeu aqui é baseado na Yakindu Statechart Tools, que é a ferramenta que utilizamos para testar os diagramas deste artigo. Na área de Sistemas de Informações vale a pena conhecer também a linguagem UML State Machines, específica para a modelagem orientada a objetos. Profissionais de Eletrônica costumam adotar a FSM (do inglês, Máquina de Estados Finita).

Uma coisa que vale a pena levar em conta é que é muito difícil fazer o diagrama de estados para um sistema inteiro de uma só vez. Como quase tudo na vida, o ideal é criá-lo de forma iterativa e incremental, complementando e adicionando detalhes aos diagramas à medida que você constrói o seu sistema.

Programar é bom, mas no fim das contas, não adianta sermos feras na programação se mandamos o robô fazer certo a coisa errada. Os diagramas de estados irão lhe ajudar a definir a coisa certa a ser feita – ou seja, o comportamento que o robô deverá seguir.

Autoria

YhK8m9OSANX1gwFuiVdvzb5b794vhQniI29lXkWllIdd9GbWBwQ 1i8F0kxUJOjuGmg9NS8IfqZpxcpUMYC uzjMQ3cn0mJXxiXGGQrjQH Dte7WlnETDjtg5OFQ8Kdpj7CsJLQCleberson Andrade da Silva Santos é um apaixonado por robótica e graduando em  Engenharia Eletrônica na Universidade Federal Rural de Pernambuco (UFRPE)
pwUo3aMSaYdCH9I fg1wudrnDedms73ofWCW0pY tEyi0BpPbTmGkGPFUUgFbZk 8wD4pX HrdD6Ff6cU4PCpaG80nAJvo3nT5iJWpFujUrrv9XnQ7j2MdmlMZDs5 lEi 2KrgtVO Prof. Dr. João Henrique Correia Pimentel ama ensinar computação para os estudantes de engenharia na Unidade Acadêmica do Cabo de Santo Agostinho da Universidade Federal Rural de Pernambuco (UFRPE). Faz parte dos grupos de pesquisa Grupo de Engenharia Elétrica e Eletrônica (GEEE) e Laboratório de Engenharia de Requisitos (LER)

Agradecimentos

Agradecemos ao prof. Roberto Kenji Hiramatsu, da UFRPE, pela revisão deste artigo. A escrita deste artigo é resultado de um projeto de Bolsa de Incentivo Acadêmico financiado pela Fundação de Amparo à Ciência e Tecnologia do Estado de Pernambuco (FACEPE).

Crédito para foto utilizada como fundo na imagem destacada: Peter Heeling (Creative Commons CC0)

Notificações
Notificar
guest
0 Comentários
Inline Feedbacks
View all comments

WEBINAR

Imagens de Ultrassom: Princípios e Aplicações

DATA: 26/10 ÀS 19:30 H