Olá robô - Banco de testes
Banco de testes
Um dos passos mais importantes no processo de design de engenharia e no ciclo de vida do desenvolvimento de software é o teste. Ao trabalhar com código, garantir que ele funcione sem erros e atenda ao padrão decidido na fase de planejamento do processo é crucial. Para garantir que o código está funcionando conforme o previsto, os testes precisam ser realizados. Antes de entrar nas seções de introdução à programação, Test Bed - Blocks ou Test Bed - OnBot Java; é importante entender o teste, os benefícios de criar um banco de testes, os componentes necessários para as próximas seções e como usar os gamepads. Siga adiante nesta seção para aprender mais sobre o teste!
Seção | Objetivos da seção |
---|---|
Noções básicas de testes | Saiba por que é um dos aspectos mais importantes do desenvolvimento de software e como ele difere da solução de problemas. |
Banco de testes | Por que a criação de uma plataforma de teste de atuadores e sensores pode ajudar na programação. Este banco de testes, ou algo equivalente, será usado nas seções seguintes. |
Utilizando controles | Compreender as convenções de nomenclatura para programar um gamepad. |
Tenha em mente que esta é a introdução ao guia básico de programação. Test Bed - Blocks e Test Bed - OnBot Java irão guiá-lo pelos fundamentos da programação com o Sistema de Controle REV.
Noções básicas de testes
O objetivo dos testes é identificar, isolar e corrigir possíveis problemas em um projeto antes que o design seja colocado em uso. Os testes assumem diferentes formas ou fornecem diferentes métricas para diversos propósitos no design. Um mecanismo, como um atirador, por exemplo, pode ser testado para confirmar que está funcionando de forma confiável. Durante a fase de planejamento do processo de design, você deve criar várias métricas de desempenho, qualidade e confiabilidade. Quando o design é construído, ou o programa é escrito, essas métricas ajudarão a identificar se o mecanismo atende aos padrões esperados. Se os padrões de operação não forem atendidos, o problema precisa ser isolado.
Para corrigir um problema no processo de design, é necessário isolar a origem do problema. Para entender como isso funciona, considere o seguinte exemplo:
A equipe adquiriu recentemente um Control Hub e um Motor Core Hex. Eles conectam o Motor Core Hex ao Control Hub usando o cabeamento correto, mas quando tentam executar o código, o motor não se move. Qual é a razão mais provável para essa falha: O problema está no programa; o problema está no motor; o problema está no fio que conecta o motor ao Hub; o problema está no Hub.
Sem mais informações, não há uma maneira precisa de descobrir por que o motor não está funcionando. Para estreitar as possibilidades, os diferentes componentes precisam ser testados até que a causa raiz do problema seja encontrada. A prática comum é começar com um código que se sabe funcionar, como um dos códigos de exemplo no SDK. Se o motor ainda não funcionar, a próxima coisa que a equipe deve verificar é se os fios estão funcionando conforme o esperado. A equipe deve passar por cada componente, testando ou solucionando problemas, para identificar o que está funcionando e o que não está.
Uma vez que a origem do problema foi isolada, é necessário corrigi-lo. A duração da correção depende das fontes do problema e de sua profundidade. Por exemplo, se um modo operacional não estiver funcionando conforme o esperado, a correção pode ser uma mudança simples, como no arquivo de configuração ou no hardwareMap. Um problema maior que requer um redesenho, como um mecanismo que não atende às métricas de desempenho, aciona um reinício do processo de design de engenharia.
Testes x Solução de problemas
Anteriormente, o teste foi definido como o processo de identificar, isolar e corrigir possíveis problemas durante o processo de design. Isso difere da solução de problemas, que é o processo de identificar, isolar e corrigir problemas em um mecanismo que passou pelo processo de teste e funcionou conforme o esperado.
Na seção de solução de problemas, foram usados exemplos da luz indicadora do motor de um carro. Nesse exemplo, o indicador conhecido de uma falha foi a luz do motor do carro. A luz do motor informa ao motorista que há algo errado com o carro, mas para encontrar a causa do problema, etapas de solução de problemas e diagnóstico devem ser realizadas. Para manter essa comparação, o teste é o que os engenheiros do carro usam para estabelecer as métricas do desempenho esperado do motor. Se esses padrões não forem atendidos, a luz do motor acende para alertar o motorista sobre o problema.
Banco de testes
Um dos inconvenientes ao testar código em um sistema de componentes, como o REV Control System, é que não há garantia de que todos os componentes estão funcionando como deveriam. Por exemplo, se um motor no robô não estiver funcionando, existem várias razões potenciais para a falha. O motor, a porta do motor no Control Hub, o fio que conecta o motor à porta e o código são todas causas potenciais de falha do motor.
Se uma falha ocorrer após a montagem do robô, pode ser difícil retroceder e fazer alterações ou solucionar problemas sem ter que desmontar o robô. Uma das maneiras de se preparar para essa circunstância é criar um banco de testes antes de criar um robô.
Ao testar código, não assuma que uma falha ocorre devido ao mecanismo em vez do código. Testar e solucionar problemas, embora sejam conceitos semelhantes, são fundamentalmente diferentes. Verificar o código ou usar um código conhecido que funcione sempre deve ocorrer antes de solucionar problemas com componentes como atuadores e sensores.
Um banco de testes é um ambiente de teste para componentes de hardware e software, comumente usado no mundo da engenharia. As aplicações de bancos de testes incluem uma ampla variedade de equipamentos e testes de medição. Em alguns casos, um banco de testes é um equipamento para testar um produto específico; em outros casos, é um sistema de componentes que cria um ambiente de teste. Independentemente disso, o objetivo final de um banco de testes é garantir que um componente esteja funcionando antes de ser usado para seu propósito pretendido.
Criar um banco de testes facilita o processo de solução de problemas se houver uma falha durante o teste de código. O objetivo desta seção é criar um banco de testes para testar código básico nas seções de Test Bed - Blocks e Test Bed - OnBot Java.
Criando um banco de testes
O design de um banco de testes depende do caso de uso e dos recursos disponíveis. Por exemplo, um dos requisitos de design para o banco de testes apresentado abaixo foi a acessibilidade. Observe que a disposição dos componentes de hardware na extrusão permite que os atuadores, sensores e Control Hub sejam removidos ou trocados com facilidade.
Outra consideração importante de design para este banco de testes foi incluir os componentes comuns necessários para ensinar aos usuários o básico da programação com o REV Control System. Neste caso, os componentes foram escolhidos a partir do REV FTC Starter Kit.
- Control Hub
- REV Core Hex Motor
- Smart Robot Servo
- Touch Sensor
- Color Sensor V3
- Bateria
Qualquer um desses componentes do banco de testes pode ser trocado por um componente equivalente. Por exemplo, se você tiver um Expansion Hub em vez de um Control Hub. No entanto, com um Expansion Hub, pode ser necessário considerar o local para o telefone do controlador do robô.
Existem outras considerações de design menores, mas importantes, a serem feitas para um banco de testes. Por exemplo, ao adicionar um atuador a um banco de testes, considere as seguintes perguntas:
Qual nível de restrição o atuador precisa?
- Um dos benefícios de criar um banco de testes para motores ou outros atuadores é que os motores podem ser devidamente restritos durante o processo de teste. Nesse caso, fornecer suporte e restrição básicos de movimento é valioso.
Como você poderá observar o comportamento do atuador?
- O banco de testes de exemplo usa uma roda com um enforcador de cabo de nylon (zip tie) para ajudar os usuários a visualizar o comportamento do motor. Fitas adesivas ou outros marcadores também podem ser usados. Para o propósito deste guia, um banco de testes semelhante ao exemplo pode ser construído.
Utilizando controles
As seções do Banco de Testes destacam os componentes de robô necessários para aprender os conceitos básicos de programação utilizados nas seções Test Bed - Blocks e Test Bed - OnBot Java. No entanto, há dois componentes adicionais necessários para ter sucesso nos testes de seu código: um Driver Hub (ou dispositivo Android equivalente para Estação do Condutor) e um gamepad.
Para obter informações sobre a configuração de um Driver Hub e gamepad, por favor, visite o guia Começando com o Driver Hub.
Todos os botões em um gamepad podem ser programados para uma tarefa ou comportamento específico. Ao longo do Guia Olá Robô, você encontrará várias situações onde o gamepad é utilizado. Conhecer a convenção de nomenclatura geral para os gamepads ajudará você a programá-los corretamente. O guia pressupõe que você está usando um gamepad da Logitech ou um gamepad PS4, como o Etpark Wired Controller for PS4 (REV-39-1865). Para entender como programar um gamepad, especialmente com diferenças na forma como certos botões são nomeados, consulte o gráfico e a tabela a seguir, que mostram a correspondência entre as linhas de código e cada botão.
Tipos de Dados
Booleano
Dados booleanos têm dois valores possíveis: Verdadeiro e Falso. Esses dois valores também podem ser representados por Ligado e Desligado, ou 1 e 0. Botões, bumpers e gatilhos no gamepad fornecem dados booleanos ao seu robô. Por exemplo, um botão que não está pressionado retornará o valor Falso e um botão que está pressionado retornará o valor Verdadeiro.
Float
Dados de ponto flutuante são números que podem incluir casas decimais e valores positivos ou negativos. No gamepad, os dados de ponto flutuante retornados estarão entre 1 e -1 para a posição do joystick em cada eixo. Alguns exemplos de valores possíveis são 0.44, 0, -0.29 ou -1.
Blocos
A Ferramenta de Programação por Blocos é uma ferramenta visual de programação que permite aos programadores usar um navegador da web para criar, editar e salvar seus modos operacionais (op modes). Os blocos, assim como outras ferramentas de programação baseadas em blocos, são uma coleção de trechos de código predefinidos que os usuários podem arrastar e soltar na linha de código apropriada. Nesta seção, os usuários podem aprender a criar um modo operacional, bem como os conceitos básicos de programação dos atuadores e sensores apresentados no banco de testes. Siga o guia para obter uma compreensão aprofundada do trabalho com Blocos ou navegue até a seção que atenda às suas necessidades:
Criando um Op Mode
Antes de mergulhar e criar o seu primeiro modo operacional (op mode), é importante considerar o conceito de convenções de nomenclatura. Ao escrever código, o objetivo é ser o mais claro possível sobre o que está acontecendo dentro do código. É aqui que entra o conceito de convenções de nomenclatura. Convenções de nomenclatura comuns foram estabelecidas pelo mundo da programação para denotar variáveis, classes, funções, etc. Modos operacionais compartilham algumas semelhanças com classes. Portanto, a convenção de nomenclatura para modos operacionais tende a seguir a convenção de nomenclatura para classes, onde a primeira letra de cada palavra é maiúscula.
Esta seção pressupõe que você já acessou a plataforma de Blocos durante a introdução à programação no Guia Olá Robô. Se você não souber como acessar os Blocos, por favor, reveja esta seção antes de continuar.
Para começar, acesse o Console do Controlador do Robô e vá para a página de Blocos. No canto superior direito, há um botão "Criar Novo Modo Operacional", clique nele.
Clicar no botão "Criar Novo Modo Operacional" abrirá a janela "Criar Novo Modo Operacional". Esta janela permite que os usuários nomeiem seus modos operacionais e selecionem um código de exemplo para desenvolver. Para este guia, utilize o exemplo padrão "BasicOpMode" e nomeie o modo operacional como "HelloRobot_TeleOp", conforme mostrado na imagem abaixo.
Depois de nomear o modo operacional, clique em 'OK' para prosseguir. A criação de um modo operacional abrirá a página principal de programação por blocos. Antes de prosseguir com a programação, reserve um tempo para aprender e entender os seguintes componentes-chave dos Blocos, apresentados na imagem abaixo.
Salvar Modo Operacional - Clique neste botão para salvar um modo operacional no robô. É importante salvar o modo operacional sempre que parar de trabalhar em um código para que o progresso não seja perdido.
TeleOperado/Autônomo - Esta seção de blocos permite aos usuários alternar entre os dois tipos de modos operacionais: teleoperado e autônomo.
Blocos Categorizados - Esta seção da tela é onde os blocos de programação são categorizados e acessíveis. Por exemplo, clicar em Lógica abrirá o acesso a blocos de programação como declarações if/else.
Espaço de Programação - Este espaço é onde os blocos são adicionados para construir programas.
Se uma configuração foi feita, os Atuadores, Sensores e Outros Dispositivos na seção de Blocos Categorizados devem aparecer como menus suspensos, onde blocos específicos para hardware podem ser acessados. Se isso não acontecer, um arquivo de configuração não foi criado. Para obter mais informações, visite a página de Configuração antes de prosseguir com a programação.
Fundamentos da programação
Durante o processo de criação de um modo operacional, a ferramenta de Blocos solicitou a seleção de um código de exemplo. Nos Blocos, esses exemplos funcionam como modelos, fornecendo os blocos e a estrutura lógica para diferentes casos de uso em robótica. Na seção anterior, o código de exemplo BasicOpMode foi selecionado. Este código de exemplo, visto na imagem abaixo, é a estrutura base necessária para ter um modo operacional funcional.
Um modo operacional pode frequentemente ser considerado um conjunto de instruções para um robô seguir a fim de entender o mundo ao seu redor. O BasicOpMode fornece o conjunto inicial de instruções necessárias para que um modo operacional funcione adequadamente. Embora este exemplo seja fornecido aos usuários para reduzir algumas das complexidades da programação à medida que aprendem, ele introduz alguns dos blocos de código mais importantes. Também é importante entender o que está acontecendo na estrutura do BasicOpMode, para que os blocos de código sejam colocados na área correta.
Principais blocos do modo operacional
Comentários são blocos de código que beneficiam o usuário humano. Eles são usados pelos programadores para explicar a função de uma seção de código. Isso é especialmente útil em ambientes de programação colaborativa. Se o código é repassado de um programador para outro, os comentários comunicam a intenção do código ao outro programador. Blocos como // são comentários escritos pela equipe técnica da FIRST para informar ao usuário o que acontecerá quando blocos forem adicionados diretamente abaixo do comentário.
Por exemplo, quaisquer blocos de programação que são colocados após o comentário (e antes do waitForStart bloco) serão executados quando o modo operacional for selecionado pela primeira vez por um usuário na Estação do Condutor. Normalmente, os blocos colocados nesta seção têm o propósito de criar e definir variáveis entre as fases de inicialização e início do modo operacional.
Uma variável é uma localização de armazenamento com um nome simbólico associado, que contém alguma quantidade conhecida ou desconhecida de informações referidas como um valor. Variáveis podem ser números, caracteres ou até mesmo motores e servos.
Quando o Controlador do Robô atinge o bloco waitForStart, ele irá parar e aguardar até receber um comando de Iniciar da Estação do Condutor. Um comando de Iniciar não será enviado até que o usuário pressione o botão Iniciar na Estação do Condutor. Qualquer código após o bloco waitForStart será executado após o botão Iniciar ser pressionado.
Após o bloco waitForStart, há um bloco condicional if que só será executado se o modo operacional ainda estiver ativo (ou seja, um comando de parada não foi recebido).
As instruções if-then (if-else) são semelhantes ao conceito de causa e efeito. Se a causa (ou condição) acontecer, então execute o efeito.
Quaisquer blocos que são colocados após o comentário // pur run blocks here e antes do bloco // OpMode is active serão executados sequencialmente pelo Controlador do Robô depois que o botão Iniciar for pressionado.
O bloco while é uma estrutura de controle iterativa ou de loop.
Este controle realizará as etapas listadas na parte "do" do bloco enquanto a condição opModeIsActive() for verdadeira. Isso significa que as instruções incluídas na parte "do" do bloco serão repetidamente executadas enquanto o modo operacional HelloRobot_TeleOp estiver em execução.
Assim que o usuário pressiona o botão Parar, a condição opModeIsActive() não é mais verdadeira e o loop while para de se repetir.
Funções e métodos
A seção anterior não entrou em uma discussão detalhada dos blocos de função (ou método) roxos. Funções e métodos são procedimentos semelhantes em programação que são mais avançados do que o que será abordado neste guia.
Por enquanto, a coisa mais importante a saber é que ocasionalmente será necessário chamar métodos dentro das bibliotecas SDK para realizar uma determinada tarefa. Por exemplo, a linha while (opModeIsActive()) chama o método opModeIsActive, que é o procedimento no SDK que consegue dizer quando o robô foi iniciado ou parado.
Quando suas habilidades de programação estiverem mais avançadas, reserve um tempo para explorar os conceitos de funções e métodos, e descubra como eles podem ajudar a aprimorar seu código.
Programando atuadores
Noções básicas do servo
O objetivo desta seção é cobrir alguns dos conceitos básicos de programação de um servo nos Blocos. No final desta seção, os usuários devem ser capazes de controlar um servo com um gamepad, além de compreender algumas das necessidades fundamentais de programação do servo.
Esta seção está considerando o Smart Robot Servo no seu modo padrão. Se o seu servo foi alterado para funcionar no modo contínuo ou com limites angulares, ele não se comportará da mesma forma utilizando os exemplos de código abaixo. Você pode aprender mais sobre o Smart Robot Servo ou alterar o modo do servo através do SRS Programmer clicando nos hiperlinks abaixo.
Servo robô inteligente
Programador SRS
Com um servo típico, você pode especificar uma posição alvo para o servo. O servo girará o eixo do motor para mover-se até a posição alvo e, em seguida, manterá essa posição, mesmo se for aplicada uma força moderada para tentar perturbar sua posição.
Para ambos os Blocos e o OnBot Java, você pode especificar uma posição alvo que varia de 0 a 1 para um servo. Para um servo com um alcance de 270°, se a faixa de entrada for de 0 a 1, então um sinal de entrada de 0 faria com que o servo virasse para -135°. Para um sinal de entrada de 1, o servo viraria para +135°. Entradas entre o mínimo e o máximo têm ângulos correspondentes distribuídos uniformemente entre o ângulo mínimo e máximo do servo. Isso é importante ter em mente ao aprender a programar servos.
Como esta seção se concentrará em servos, é importante entender como acessar servos dentro dos Blocos. No topo da seção de Blocos Categorizados, há um menu suspenso para Atuadores. Quando o menu é selecionado, ele mostrará duas opções: DcMotor ou Servo. Selecionar Servo abrirá uma janela lateral preenchida com vários blocos relacionados a servos.
Programando um servo
O bloco acima mudará de nome dependendo do nome do servo em um arquivo de configuração. Se houver vários servos em um arquivo de configuração, a seta ao lado de "test_servo" irá abrir um menu com todos os servos na configuração.
Adicione este bloco ao código do modo operacional dentro do
Clique no bloco numérico para mudar de
Para:
Selecione "Salvar Modo Operacional" no canto superior direito no Console do Controlador do Robô.
Tente executar este modo operacional no banco de testes duas vezes e considere as seguintes perguntas:
- O servo se moveu durante a primeira execução?
- O servo se moveu durante a segunda execução?
- Se o servo não se moveu, mude de volta para e tente novamente.
A intenção do bloco setPosition é definir a posição do servo. Se o servo já estiver na posição definida quando o código for executado, ele não mudará de posição. Vamos tentar adicionar outro bloco setPosition e ver o que muda. Arraste mais um bloco setPosition para o código do modo operacional, abaixo do bloco de comentário Put initialization blocks here.
Tente executar este modo operacional no banco de testes e considere a seguinte pergunta: O que é diferente da execução anterior?
O bloco setPosition(0) que foi adicionado na etapa acima altera a posição do servo para 0 durante a fase de inicialização, portanto, quando o modo operacional é executado, o servo sempre se moverá para a posição 1. Para algumas aplicações, iniciar o servo em um estado conhecido, como na posição zero, é benéfico para o funcionamento de um mecanismo. Definir o servo no estado conhecido na inicialização garante que ele esteja na posição correta quando o modo operacional é executado.
Programando um servo com um controle
O foco deste exemplo é atribuir determinadas posições do servo a botões no gamepad. Para este exemplo, o estado conhecido permanecerá na posição 0, de modo que após a inicialização o servo estará na posição de -135 graus do intervalo do servo. A lista a seguir mostra quais botões correspondem a quais posições do servo.
Se você estiver usando um controle PS4, como o Etpark Wired Controller para PS4 (REV-39-1865), consulte a seção Usando Controles na página anterior para determinar como o código do controle usado nesta seção se traduz para o controle do PS4.
Botões | Posição em graus | Posição no código |
---|---|---|
Y | -135 | 0 |
X | 0 | 0.5 |
B | 0 | 0.5 |
A | 135 | 1 |
A melhor maneira de alternar a posição do servo será usar uma instrução condicional if/else if. Uma instrução if avalia se uma declaração condicional é verdadeira ou falsa. Se a declaração condicional for verdadeira, uma ação definida (como o movimento do servo) é executada. Se a declaração condicional for falsa, a ação não é executada.
Uma instrução if/else if aceita várias declarações condicionais diferentes. Se a primeira declaração condicional for considerada falsa, então a segunda declaração condicional é analisada. Cada declaração no if/else if será analisada uma por uma até que uma declaração seja considerada verdadeira ou todas as declarações sejam consideradas falsas. Para este exemplo, haverá três condições que precisarão ser verificadas.
Clique no ícone de Configurações azul e branco para o bloco if/else if. Isso exibirá um menu pop-up que permite modificar o bloco if/else if.
Arraste um bloco else if da parte esquerda do menu pop-up e encaixe-o sob o bloco if. Arraste um segundo bloco else if da parte esquerda e encaixe-o no lado direito sob o primeiro bloco else if.
Existem três caminhos diferentes neste bloco if/else if. Cada um corresponde a uma das três posições escolhidas do servo: 0, 0.5 e 1. No entanto, existem quatro botões diferentes que serão usados para este exemplo. Tanto o botão B quanto o botão X devem ser capazes de mover o servo para a posição 0.5. Para fazer isso, o operador lógico "or" precisa ser usado.
O operador lógico "or" considera dois operandos; se qualquer um (ou ambos) forem verdadeiros, a declaração "or" é verdadeira. Se ambos os operandos forem falsos, a declaração "or" é falsa.
Da categoria Lógica no Blocks, selecione o bloco and.
Adicione este bloco ao bloco if/else if, como mostrado na imagem abaixo. Use o menu suspenso no bloco para alterá-lo de um bloco and para um bloco or.
Todos os blocos relacionados ao gamepad estão no Menu do Gamepad.
Adicione cada botão ao bloco if/else if conforme visto na imagem abaixo.
Adicione blocos de setar a posição do servo para 1 em cada seção do bloco if/else if. Defina a posição do servo para corresponder a cada botão.
Existem três caminhos diferentes neste bloco if/else if. Se a primeira declaração condicional for verdadeira (o botão Y está pressionado), o servo se move para a posição de código 0 e as outras declarações condicionais são ignoradas. Se a primeira condição for falsa (o botão Y não está pressionado), a segunda condição é analisada. Lembre-se de que esse comportamento se repete até que uma condição seja atendida ou todas as condições tenham sido testadas e consideradas falsas.
Servoss e telemetria
Telemetria é o processo de coletar e transmitir dados. Na robótica, a telemetria é usada para enviar dados internos de atuadores e sensores para a Estação do Condutor. Esses dados podem então ser analisados pelos usuários para tomar decisões que possam melhorar o código.
A telemetria mais útil do servo é a posição do servo ao longo de sua faixa de 270 graus. Para obter essa informação, a seguinte linha precisa ser usada.
Para acessar os blocos de telemetria, selecione o menu suspenso de Utilitários. O menu de utilitários está em ordem alfabética, então a telemetria está localizada mais para o final das opções do menu suspenso. Selecione o seguinte bloco do menu de telemetria:
Arraste o seguinte bloco e coloque-o abaixo do bloco if/else if:
Mude o parâmtro key para "Servo Position"
Quando o modo operacional é executado, o bloco de telemetria exibirá as informações de posição atual com a Chave de Posição do Servo. O número correspondente à posição atual mudará conforme a posição do eixo do servo se altera.
Noções básicas de motor
Modifique o seu modo operacional para adicionar o código relacionado ao motor. Isso pode ser feito limpando suas modificações de código atuais ou adicionando o código relacionado ao motor ao seu modo operacional atual.
O objetivo desta seção é abordar alguns conceitos básicos de programação de um motor dentro do ambiente de Blocos. Ao final desta seção, os usuários deverão ser capazes de controlar um motor usando um gamepad, além de compreender alguns princípios básicos de trabalho com encoders de motor.
Dado que esta seção se concentrará em motores, é importante compreender como acessar motores dentro do ambiente de Blocos. Na parte superior da seção de Blocos Categorizados, há um menu suspenso para Atuadores. Quando o menu é selecionado, serão exibidas duas opções: DcMotor ou Servo. Selecionar DC Motor abrirá uma janela lateral preenchida com vários blocos relacionados a motores.
Controlando motores
O bloco acima terá nomes diferentes dependendo do nome do motor em um arquivo de configuração. Se houver vários motores em um arquivo de configuração, a seta ao lado de "test_motor" abrirá um menu com todos os motores presentes na configuração.
Adicione este bloco ao código do modo operacional (op mode) dentro do loop while.
Selecione "Salve Op Mode" no canto superior direito na Console do Controlador do Robô.
Tente executar este modo operacional no banco de testes e considere as seguintes perguntas:
- A que velocidade o motor está funcionando?
- O que acontece se você alterar a potência de 1 para 0.3?
- O que acontece se você mudar a potência para -1?
O nível de potência enviado ao motor depende do número numérico atribuído ao motor. A mudança de 1 para 0,3 reduziu a velocidade do motor de 100% do ciclo de trabalho para 30% do ciclo de trabalho. Enquanto isso, a mudança para -1 permitiu que o motor girasse a 100% do ciclo de trabalho na direção oposta. Assim, a potência pode ser variada para mover um motor para frente ou para trás.
No entanto, o bloco de motor setPower(1) executará o motor na direção atribuída até que algo no código pare o motor ou cause uma mudança na direção.]
Para compreender melhor os motores e o conceito de ciclo de trabalho, consulte a documentação sobre Motores e Escolha de Atuadores da REV Robotics
Controlando motores pelo controle
Na seção anterior, você aprendeu como configurar o motor para funcionar em um nível de potência específico em uma direção específica. No entanto, em algumas aplicações, pode ser necessário controlar o motor com um gamepad para alterar facilmente a direção ou o nível de potência de um mecanismo.
Arraste o bloco leftStickY para que ele se encaixe no lado direito do bloco Power. Este conjunto de blocos irá repetidamente ler o valor do joystick esquerdo (posição y) do gamepad #1 e definir a potência do motor para o valor Y do joystick esquerdo.
Observe que, para os gamepads Logitech F310, o valor Y de um joystick varia de -1, quando o joystick está em sua posição mais alta, até +1, quando o joystick está em sua posição mais baixa. Se o motor não estiver se movendo na direção desejada, adicionar um símbolo negativo ou um operador de negação à linha de código alterará a direção do motor em relação ao gamepad.
Da seção Matemática no Blocks, selecione o bloco da imagem abaixo.
Arraste o bloco do símbolo de negativo para que ele se encaixe entre os blocos de Power e leftStickY, como na imagem abaixo:
Motores e telemetria
Lembre-se de que telemetria é o processo de coletar e transmitir dados. Na robótica, a telemetria é usada para enviar dados internos de atuadores e sensores para a Estação do Motorista. Esses dados podem ser analisados pelos usuários para tomar decisões que melhorem o código.
Para obter dados de telemetria do motor, é necessário usar encoders de motor. Os motores DC REV, como o Core Hex Motor, são equipados com encoders internos que transmitem informações na forma de contagens.
Para acessar os blocos de telemetria, selecione o menu Utilitários. O menu Utilitários está em ordem alfabética, então a telemetria está localizada na parte inferior das opções do menu. Selecione o bloco abaixo e faça o seguinte:
Arraste esse bloco para baixo do bloco anteriormente feito, como mostra a seguinte imagem:
Mude o parâmetro key para "Counts per Revolution"
Quando o modo operacional é executado, o bloco de telemetria exibirá as informações de posição atual com a chave "Counts Per Revolution". O número correspondente à posição atual mudará à medida que a posição do eixo do motor for alterada.
Para obter mais informações sobre a programação de encoders, consulte a página "Using Encoders" (Usando Encoders). Para mais informações sobre a métrica de contagens por revolução e como utilizá-la, confira a página "Encoders".
Programando um sensor
Noções básicas de sensor
Modifique o seu modo operacional para adicionar o código relacionado ao dispositivo digital. Isso pode ser feito limpando as modificações atuais do seu código ou adicionando o código do dispositivo digital ao seu modo operacional.
O objetivo desta seção é abordar alguns dos conceitos básicos de programação de um dispositivo digital, ou Sensor de Toque, dentro do Blocks. Como esta seção se concentrará em dispositivos digitais, é importante entender como acessar blocos específicos para esses dispositivos. No topo da seção "Categorize Blocks", há um menu suspenso para "Other Devices". Quando o menu é selecionado, ele exibirá uma opção para "Digital Devices". Selecionar "Digital Devices" abrirá uma janela lateral preenchida com vários blocos relacionados a dispositivos digitais. O bloco mais frequentemente usado é o de State
Antes de programar com um Sensor de Toque ou outro dispositivo digital, é importante entender o que é um dispositivo digital e quais são as aplicações comuns para esses dispositivos. Visite a página de Sensores Digitais para obter mais informações.
Programando um dispositivo digital
As informações provenientes de dispositivos digitais vêm em dois estados, também conhecidos como estados binários. A maneira mais comum de utilizar essas informações é por meio de uma instrução condicional, como uma declaração if/else.
Arraste esse bloco e coloque-o abaixo do bloco de comentário Put run blocks here
Selecione um bloco de State no menu de Dispositivos Digitais e adicione-o ao bloco if/do/else, conforme mostrado na imagem abaixo.
O bloco de State armazena a informação binária FALSO/VERDADEIRO do sensor de toque e atua como a condição para o bloco if/else. Se o State for verdadeiro, qualquer código colocado na parte de "fazer" do bloco será ativado. Se o State for falso, qualquer coisa colocada na parte de "senão" do bloco será ativada.
O estado FALSO/VERDADEIRO de um Sensor de Toque REV corresponde a se o botão no Sensor de Toque está pressionado ou não. Quando o botão não está pressionado, o estado do Sensor de Toque é Verdadeiro. Quando o botão é pressionado, o estado do Sensor de Toque é Falso.
Para ajudar a lembrar como os estados físicos e digitais do sensor correspondem nas próximas seções, vamos usar alguns comentários.
Blocos de comentário podem ser encontrados no menu Diversos.
Após achar esse bloco, monte um sistema conforme a imagem abaixo:
O próximo passo no processo é usar a telemetria para exibir o status do Sensor de Toque no dispositivo da Estação do Motorista. Para fazer isso, vamos criar uma variável de string chamada touchStatus.
Uma String é uma sequÇecia de caracteres
Esse processo criou uma variável chamada touchStatus. Atualmente, touchStatus está indefinido; para defini-lo, o bloco precisa ser usado. Este bloco pode ser encontrado no menu Variáveis, agora que a variável foi criada.
Arraste esse bloco e coloque-o abaixo do comentário Touch is not pressed.
Adicione outro abaixo do Touch is pressed.
O bloco touchStatus permite que você altere o valor da variável. Dependendo de qual estado ele estiver, touchStatus será definido para outra String. Para isso selecione o bloco de String do menu Text. Como a imagem abaixo mostra:
Adicione um bloco de string ao touchStatus. Preencha o bloco com uma mensagem de status que relate o estado do sensor. Como "Not pressed" e "Pressed".
Para exibir essas informações na Driver Station, é necessário utilizar a telemetria. Para acessar os blocos de telemetria, selecione o menu suspenso de Utilitários. O menu de utilitários está em ordem alfabética, então a telemetria está localizada mais para o final das opções do menu suspenso. Selecione o bloco abaixo:
Arraste esse bloco e coloque-o abaixo do bloco if/else.
Arraste o bloco de touchStatus para a área de texto da função addData e mude o parâmetro key para "Button"
Enquanto esse programa estiver operando o estado do botão será mostrado na telemetria.
Dispositivos digitais como um interruptor de limite
Um dos usos mais comuns para um dispositivo digital, como um sensor de toque, é utilizá-lo como um interruptor de limite. A intenção de um interruptor de limite é interromper o funcionamento de um mecanismo, como um braço ou elevador, antes que ultrapasse suas limitações físicas. Nessa aplicação, a energia precisa ser cortada do motor quando o limite é atingido.
O conceito de um interruptor de limite envolve muitas etapas semelhantes à seção anterior sobre a programação de um dispositivo digital. Por essa razão, vamos retomar a partir do conjunto de blocos a seguir:
O bloco if/else estabelece um ambiente condicional para o interruptor de limite. Se o sensor de toque não estiver pressionado, o motor pode funcionar; no entanto, se estiver pressionado, o motor não pode funcionar. Para adicionar isso ao código, o bloco Power precisa ser utilizado.
Para obter informações sobre onde encontrar blocos específicos para motores, por favor, reveja a seção sobre motores.
Adicione um bloco de Power abaixo do comentário "Touch is not Pressed". Altere o valor de Power para 0.3. Adicione outro bloco de Power abaixo do comentário "Touch is Pressed". Altere o valor de Power para 0.
Este bloco if/else introduz os conceitos básicos de um interruptor de limite. Como na maioria dos sensores, é bom ter telemetria que atualiza a Estação do Motorista sobre o status do sensor. Considere o código da seção anterior ou o seguinte código como ideias potenciais para telemetria.
OnBot Java
O OnBot Java é uma ferramenta de programação baseada em texto que permite aos programadores usar um navegador da web para criar, editar e salvar seus modos de operação Java (op modes). Nesta seção, os usuários podem aprender como criar um op mode, bem como os conceitos básicos de programação dos atuadores e sensores apresentados no banco de testes.
Siga o guia para obter uma compreensão aprofundada de como trabalhar com o OnBot Java ou navegue até a seção que atenda às suas necessidades:
Seção | Objetivos da seção |
---|---|
Criando um Op Mode | Concentre-se em como navegar na interface do OnBot Java e criar um op mode. |
Fundamentos da programação | Explora a estrutura e os elementos-chave necessários para um modo de operação (op mode), assim como alguns dos componentes essenciais do Java. |
Programando acionadores | Como codificar servos e motores. Esta seção guia através da lógica básica de codificar atuadores, controlar atuadores com um gamepad e utilizar telemetria. |
Programando sensores | Como codificar um dispositivo digital. Esta seção concentra-se na lógica básica de programar um dispositivo digital, como um Sensor de Toque REV. |
Criando um Op Mode
Antes de mergulhar e criar o seu primeiro modo de operação (op mode), você deve considerar o conceito de convenções de nomenclatura. Ao escrever código, o objetivo é ser o mais claro possível sobre o que está acontecendo dentro do código. É aqui que entra o conceito de convenções de nomenclatura. Convenções de nomenclatura comuns foram estabelecidas pelo mundo da programação para denotar variáveis, classes, funções, etc. Os modos de operação compartilham algumas semelhanças com as classes. Assim, a convenção de nomenclatura para modos de operação tende a seguir a convenção de nomenclatura para classes; onde a primeira letra de cada palavra é maiúscula.
Esta seção pressupõe que você já acessou a plataforma OnBot Java durante a introdução ao "Olá Robô - Programação". Se você não souber como acessar o OnBot Java, por favor, reveja esta seção antes de continuar.
Para começar, acesse o Robot Controller Console e vá para a página do OnBot Java. Há algumas coisas importantes para observar na página principal do OnBot Java.
-
Criar Novo Modo de Operação - O botão de sinal de adição abre uma janela para criar um novo modo de operação.
-
Painel do Navegador de Projetos - Este painel mostra todos os arquivos de projeto Java no Controlador do Robô.
-
Painel de Edição de Código-Fonte - Esta área é a principal para edição de código.
-
Painel de Mensagens - Este painel fornece mensagens sobre o sucesso ou falha na compilação do código.
-
Compilar Tudo - Compila todos os arquivos .java no Controlador do Robô.
Quando um modo de operação é criado ou editado, o editor OnBot Java salvará automaticamente o arquivo .java no sistema de arquivos do Controlador do Robô. No entanto, para executar o código no Controlador do Robô, o arquivo de texto .java precisa ser convertido para um binário que pode ser carregado dinamicamente no aplicativo FTC Robot Controller. Essa conversão é feita compilando os modos de operação.
Selecione o botão Create new Op Mode. Isso abrirá a janela New File. Esta janela permite que os usuários escolham configurações como: nomear seus modos op, selecionar um código de exemplo para desenvolver, ou escolher o tipo de modo op. Para este guia, selecione as seguintes seções:
- File Name: HelloRobot_TeleOp
- Sample: BlankLinearOpMode
- Op Mode Type: TeleOp
- Setup for Configured Hardware: on
Após as configurações adequadas terem sido escolhidas, selecione "OK" para criar o modo op. O novo arquivo será exibido no Painel de Navegação do Projeto.
Fundamentos da programação
Durante o processo de criação de um modo op, a ferramenta OnBot Java oferecia várias opções para escolher. Essas opções definem quais informações já estão incluídas no modo op, o que pode simplificar o que um programador precisa fazer do seu lado. Por exemplo, uma opção foi dada para selecionar um exemplo. No OnBot Java, esses exemplos atuam como modelos; fornecendo declarações, estrutura lógica e sintaxe para diferentes casos de uso em robótica.
Na seção anterior, as seguintes configurações foram selecionadas: a opção Setup Code for Configured Hardware, a opção TeleOp e um exemplo de código chamado BlankLinearOpMode. Essas opções combinadas configuram a estrutura básica de código necessária para ter um modo op funcional.
Um modo op é considerado um conjunto de instruções para um robô seguir a fim de entender o mundo ao seu redor. Embora o SDK forneça estruturas prontas para modos op, entender quais conceitos o modelo está utilizando e por que, ajuda a aumentar o conhecimento em programação. Siga nesta seção para aprender mais sobre o modelo de modo op e os conceitos de programação que compõem sua estrutura.
package org.firstinspires.ftc.teamcode;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.Blinker;
import com.qualcomm.robotcore.hardware.Gyroscope;
import com.qualcomm.robotcore.hardware.ColorSensor;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.hardware.DigitalChannel;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.util.ElapsedTime;
@TeleOp
public class HelloWorld_TeleOp extends LinearOpMode {
private Gyroscope imu;
private ColorSensor test_color;
private DcMotor test_motor;
private Servo test_servo;
private DigitalChannel test_touch;
@Override
public void runOpMode() {
imu = hardwareMap.get(Gyroscope.class, "imu");
test_color = hardwareMap.get(ColorSensor.class, "test_color");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(DigitalChannel.class, "test_touch");
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
telemetry.addData("Status", "Running");
telemetry.update();
}
}
O bloco de código fornece a estrutura do modelo de modo op com base na Configuração Hello Robot e com alguns comentários ausentes. Se outra configuração estiver sendo usada, o código será ligeiramente diferente, mas muitos dos conceitos subjacentes são os mesmos.
Conceitos de programação
No início do modo op, há uma anotação que ocorre antes da definição da classe. Essa anotação afirma que este é um modo op teleoperado (ou seja, controlado pelo motorista):]
@TeleOp
Em Java, as anotações são metadados ou informações descritivas sobre o código. Neste caso, a anotação está sendo usada para informar ao sistema que este modo de operação é tele-operado. Alterar a anotação de @TeleOp para @Autonomous modificará o código para um modo de operação autônomo.
public class HelloWorld_TeleOp extends LinearOpMode {
Você também pode observar que o editor OnBot Java criou cinco variáveis de membro privado para este modo de operação. Essas variáveis irão conter referências aos cinco dispositivos configurados que o editor OnBot Java detectou na configuração ativa.
private Gyroscope imu;
private ColorSensor test_color;
private DcMotor test_motor;
private Servo test_servo;
private DigitalChannel test_touch;
Em seguida, há um método sobrescrito chamado runOpMode. Todo modo de operação do tipo LinearOpMode deve implementar este método. Este método é chamado quando um usuário seleciona e executa o modo de operação.
@Override
public void runOpMode() {
O mapeamento de hardware foi introduzido na seção de configuração, como um processo de duas partes. A primeira parte do processo consistiu em criar um arquivo de configuração. A segunda parte do processo é obter referências aos dispositivos de hardware a partir do objeto hardwareMap.
O objeto hardwareMap está disponível para uso no método runOpMode. Trata-se de um objeto do tipo classe hardwareMap.
No início do método runOpMode, o modo de operação utiliza o objeto hardwareMap para obter referências aos dispositivos de hardware listados no arquivo de configuração do Controlador do Robô:
imu = hardwareMap.get(Gyroscope.class, "imu");
test_color = hardwareMap.get(ColorSensor.class, "test_color");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(DigitalChannel.class, "test_touch");
A chamada do método hardwareMap.get() é utilizada para recuperar os dispositivos de hardware e atribuí-los a variáveis. A chamada do método aceita dois argumentos: uma referência à classe específica de dispositivos de hardware à qual o dispositivo pertence e o nome do dispositivo de hardware no arquivo de configuração. O nome fornecido no hardwareMap.get() precisa corresponder ao nome do dispositivo no arquivo de configuração. Se os nomes não coincidirem, o modo de operação gerará um erro em tempo de execução indicando que não é possível encontrar o dispositivo.
Para mais infomrações sobre erros de execução cheque nossa seção de Erros comuns
Nas próximas declarações do exemplo, o modo de operação solicita ao usuário que pressione o botão de início para continuar. Ele utiliza outro objeto disponível no método runOpMode. Esse objeto é chamado de "telemetry", e o modo de operação utiliza o método addData para adicionar uma mensagem a ser enviada para a Estação do Motorista. Em seguida, o modo de operação chama o método update para enviar a mensagem para a Estação do Motorista. Depois disso, ele chama o método waitForStart para aguardar até que o usuário pressione o botão de início na estação do motorista para iniciar a execução do modo de operação.
Telemetria é o processo de coleta e transmissão de dados. Na robótica, a telemetria é frequentemente utilizada para enviar dados internos provenientes de atuadores e sensores para a Estação do Motorista. Esses dados podem ser analisados pelos usuários para tomar decisões que possam aprimorar o código.
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
Todas as operações lineares (linear op modes) devem conter uma instrução waitForStart para garantir que o robô não começará a executar o modo de operação até que o motorista pressione o botão de início.
Após receber um comando de início, o modo de operação entra em um loop while e continua iterando neste loop até que o modo de operação não esteja mais ativo (ou seja, até que o usuário pressione o botão de parada na Estação do Motorista):
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
telemetry.addData("Status", "Running");
telemetry.update();
}
Conforme o modo de operação itera no loop while, ele continuará a enviar mensagens de telemetria com o índice "Status" e a mensagem "Running" para serem exibidas na Estação do Motorista.
Sintaxe
Linguagens de programação, assim como qualquer idioma, possuem um conjunto de regras e princípios orientadores que permitem que as declarações sejam compreendidas universalmente. Elementos como pontuação, estrutura de palavras e formatação desempenham um papel na interpretação de uma linha de código. Em linguística e ciência da computação, as regras que governam a estrutura de uma sentença são conhecidas como sintaxe.
É importante compreender a sintaxe do Java, pois erros de sintaxe serão comuns e difíceis de rastrear sem um nível básico de entendimento.
Programação Orientada a objetos
Esta seção fez várias referências a métodos, objetos e classes. Todos esses são tópicos de programação intermediários a avançados, frequentemente centrados no conceito de programação orientada a objetos. O objetivo do guia Olá Robô é servir como um curso introdutório para programação de robôs, em vez de aprofundar-se em conceitos de programação.
No entanto, mantenha a programação orientada a objetos em mente à medida que suas habilidades se desenvolvem. Por enquanto, a coisa mais importante a saber é que, ocasionalmente, métodos dentro das bibliotecas do SDK precisarão ser chamados para realizar uma determinada tarefa. Por exemplo, a linha OláRobo_TeleOp.opModeIsActive() chama o método opModeIsActive, que é o procedimento no SDK capaz de indicar quando o modo de operação foi ativado pelo telefone da estação do motorista.
À medida que avançarmos, grande parte do código específico para motores, servos ou sensores lidará com chamadas a outros métodos ou classes.
For more information on classes and methods in the SDK check out the Java Doc.
Programando acionadores
Noções básicas do servo
O objetivo desta seção é abordar alguns conceitos básicos de programação de um servo no OnBot Java. Ao final desta seção, os usuários devem ser capazes de controlar um servo com um gamepad, bem como entender algumas das necessidades fundamentais de programação relacionadas ao servo.
Esta seção está considerando o Servo Robô Inteligente no seu modo padrão. Se o seu servo foi alterado para funcionar em modo contínuo ou com limites angulares, ele não se comportará da mesma forma usando os exemplos de código abaixo. Você pode aprender mais sobre o Servo Robô Inteligente ou alterar o modo do servo através do SRS Programmer clicando nos hiperlinks.
Com um servo típico, você pode especificar uma posição alvo para o servo. O servo girará seu eixo do motor para mover-se até a posição alvo e, em seguida, manterá essa posição, mesmo que forças moderadas sejam aplicadas para tentar perturbar sua posição.
Tanto para o Blocks quanto para o OnBot Java, você pode especificar uma posição alvo que varia de 0 a 1 para um servo. Para um servo com uma faixa de 270°, se a faixa de entrada fosse de 0 a 1, então um sinal de entrada de 0 faria com que o servo se movesse para -135°. Para um sinal de entrada de 1, o servo se moveria para +135°. Entradas entre o mínimo e o máximo têm ângulos correspondentes distribuídos uniformemente entre o ângulo mínimo e máximo do servo. Isso é importante ter em mente enquanto aprende a programar servos.
Programando um Servo
Adicione a seguinte linha ao loop while do Op Mode: test_servo.setPosition(1);
Como segue abaixo:
while (opModeIsActive()) {
test_servo.setPosition(1);
telemetry.addData("Status", "Running");
telemetry.update();
}
Selecione Build everything para compilar o código
Execute este modo operacional (op mode) no banco de testes duas vezes e considere as seguintes perguntas:
- O servo motor se moveu durante a primeira execução?
- O servo motor se moveu durante a segunda execução?
- Se o servo motor não se moveu, altere test_servo.setPosition(1); para test_servo.setPosition(0); e tente novamente.
A intenção do test_servo.setPosition(); é definir a posição do servo. Se o servo já estiver na posição definida quando o código é executado, ele não mudará de posição. Vamos tentar adicionar a linha test_servo.setPosition(0); ao código na seção de inicialização.
public void runOpMode() {
imu = hardwareMap.get(Gyroscope.class, "imu");
test_color = hardwareMap.get(ColorSensor.class, "test_color");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(DigitalChannel.class, "test_touch");
test_servo.setPosition(0);
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
test_servo.setPosition(1);
telemetry.addData("Status", "Running");
telemetry.update();
}
}
}
Tente executar este modo operacional no banco de testes. Dê algum tempo entre pressionar "init" e pressionar "play" e considere a seguinte pergunta: O que é diferente da execução anterior?
A linha test_servo.setPosition(0); que foi adicionada na etapa anterior altera a posição do servo para 0 durante a fase de inicialização, então, quando o modo operacional é executado, o servo sempre se moverá para a posição 1. Para algumas aplicações, iniciar o servo em um estado conhecido, como na posição zero, é benéfico para o funcionamento de um mecanismo. Definir o servo no estado conhecido durante a inicialização garante que ele esteja na posição correta quando o modo operacional é executado.
Programando um servo com um controle
O foco deste exemplo é atribuir determinadas posições de servo a botões no gamepad. Para este exemplo, o estado conhecido permanecerá na posição 0, de modo que, após a inicialização, o servo estará na posição de -135 graus no intervalo do servo. A lista a seguir mostra quais botões correspondem a quais posições do servo.
Botões | Posição em graus | Posiçaõ no código |
---|---|---|
Y | -135 | 0 |
X | 0 | 0.5 |
B | 0 | 0.5 |
A | 135 | 1 |
A melhor maneira de alternar a posição do servo será usar uma instrução condicional if/else if. Uma instrução if avalia se uma afirmação condicional é verdadeira ou falsa. Se a afirmação condicional for verdadeira, uma ação definida (como o movimento do servo) é realizada. Se a afirmação condicional for falsa, a ação não é realizada.
Uma instrução if/else if aceita várias afirmações condicionais diferentes. Se a primeira afirmação condicional for falsa, então a segunda afirmação condicional é analisada. Para entender melhor esse conceito, considere o seguinte código:
if (gamepad1.y){
//move to -135 degrees
test_servo.setPosition(0);
} else if (gamepad1.x || gamepad1.b) {
//move to 0 degrees
test_servo.setPosition(0.5);
} else if (gamepad1.a) {
//move to 135 degrees
test_servo.setPosition(1);
}
Existem três caminhos diferentes nesta instrução if/else if. Se a primeira afirmação condicional for verdadeira (o botão Y está pressionado), o servo se move para a posição 0 e as outras afirmações condicionais são ignoradas. Se a primeira condição for falsa (o botão Y não está pressionado), a segunda condição é analisada. Esse comportamento se repete até que uma condição seja atendida ou todas as condições tenham sido testadas e consideradas falsas.
|| é um operador lógico em Java. Esse símbolo é o equivalente ao "ou". Usando isso como um parâmetro condicional, ele vai verificar se o botão x ou b estão pressionados para ser verdadeira.
public void runOpMode() {
imu = hardwareMap.get(Gyroscope.class, "imu");
test_color = hardwareMap.get(ColorSensor.class, "test_color");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(DigitalChannel.class, "test_touch");
test_servo.setPosition(0);
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
if (gamepad1.y){
//move to -135 degrees
test_servo.setPosition(0);
} else if (gamepad1.x || gamepad1.b) {
//move to 0 degrees
test_servo.setPosition(0.5);
} else if (gamepad1.a) {
//move to 135 degrees
test_servo.setPosition(1);
}
telemetry.addData("Status", "Running");
telemetry.update();
}
}
}
Servos e telemetria
Lembrando que telemetria é o processo de coletar e transmitir dados. Na robótica, a telemetria é usada para enviar dados internos de atuadores e sensores para a Estação do Motorista (Driver Station). Esses dados podem ser analisados pelos usuários para tomar decisões que podem aprimorar o código.
A telemetria mais útil do servo é a posição do servo ao longo de sua faixa de 270 graus. Para obter essa informação, a seguinte linha precisa ser usada.
test_servo.getPosition();
Na seção de fundamentos de programação, a linha telemetry.addData(); foi discutida brevemente. Essa chamada de método recebe um parâmetro de chave (key) e variável e envia as informações para a Estação do Motorista. A chave é uma string, ou uma linha de texto, que deve definir a variável. Neste caso, telemetry.addData(); está sendo usado para enviar para a Estação do Motorista a posição do servo conforme ela é alterada, então a chave pode ser "Posição do Servo". O parâmetro, no entanto, será a chamada do método test_servo.getPosition();.
double motorPower = 0;
while (opModeIsActive()) {
if (gamepad1.y){
//move to -135 degrees
test_servo.setPosition(0);
} else if (gamepad1.x || gamepad1.b) {
//move to 0 degrees
test_servo.setPosition(0.5);
} else if (gamepad1.a) {
//move to 135 degrees
test_servo.setPosition(1);
telemetry.addData("Servo Position", test_servo.getPosition());
telemetry.addData("Status", "Running");
telemetry.update();
}
Noções básicas de motor
Modifique o seu modo de operação (op mode) para adicionar o código relacionado ao motor. Isso pode ser feito limpando as modificações atuais do seu código ou adicionando o código relacionado ao motor ao seu modo de operação atual.
O objetivo desta seção é abordar alguns conceitos básicos de programação de um motor no ambiente OnBot Java. Ao final desta seção, os usuários deverão ser capazes de controlar um motor usando um gamepad, bem como compreender alguns dos fundamentos ao lidar com codificadores de motor.
Controlando motores
Adicione a linha test_motor.setPower(1); ao loop while do modo de operação (op mode).
while (opModeIsActive()) {
test_motor.setPower(1);
telemetry.addData("Status", "Running");
telemetry.update();
}
Selecione Build Everything para compilar o código
Tente executar este modo de operação no banco de testes e considere as seguintes perguntas:
- A que velocidade o motor está funcionando?
- O que acontece se você alterar a potência de 1 para 0.3?
- O que acontece se você alterar a potência para -1?
O nível de potência enviado ao motor depende do número numérico atribuído ao motor. A mudança de 1 para 0,3 diminuiu a velocidade do motor de 100% do ciclo de trabalho para 30% do ciclo de trabalho. Enquanto isso, a mudança para -1 permitiu que o motor girasse a 100% do ciclo de trabalho na direção oposta. Portanto, a potência pode ser variada para mover um motor para frente ou para trás. No entanto, a linha test_motor.setPower(1); fará com que o motor funcione na direção atribuída até que algo no código pare o motor ou cause uma mudança na direção.
Controlando motores com um gamepad
Na seção anterior, você aprendeu como configurar o motor para funcionar em um nível de potência específico em uma direção específica. No entanto, em algumas aplicações, pode ser necessário controlar o motor com um gamepad para alterar facilmente a direção ou o nível de potência de um mecanismo.
Para esta seção, vamos criar uma variável dupla chamada motorPower. Essa variável será criada dentro do modo de operação (op mode), mas fora do loop while.
public void runOpMode() {
imu = hardwareMap.get(Gyroscope.class, "imu");
test_color = hardwareMap.get(ColorSensor.class, "test_color");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(DigitalChannel.class, "test_touch");
double motorPower = 0;
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
telemetry.addData("Status", "Running");
telemetry.update();
}
}
}
Um tipo de dado double é um tipo numérico que pode armazenar números com pontos decimais. Dado que a potência, ou ciclo de trabalho, do motor opera em uma escala entre 1 e -1, a variável motorPower precisará ser capaz de armazenar dados numéricos com pontos decimais.
Considere as seguintes linhas de código:
motorPower = - this.gamepad1.left_stick_y;
test_motor.setPower(motorPower);
A linha motorPower = -this.gamepad1.left_stick_y; recebe uma entrada numérica que corresponde à posição do joystick do gamepad conforme ele se move ao longo do eixo y, e a atribui à variável motorPower. A próxima linha, test_motor.setPower(motorPower);, define a potência do motor como sendo igual à variável motorPower.
Observe que, para os gamepads Logitech F310, o valor Y de um joystick varia de -1, quando o joystick está em sua posição mais alta, a +1, quando o joystick está em sua posição mais baixa. Para alterar a relação direcional entre o motor e o joystick, de modo que a posição mais alta do joystick esteja correlacionada com a direção para frente do motor, é necessário usar um símbolo negativo ou o operador de negação.
// run until the end of the match (driver presses STOP)
double motorPower = 0;
while (opModeIsActive()) {
motorPower = - this.gamepad1.left_stick_y;
test_motor.setPower(motorPower);
telemetry.addData("Status", "Running");
telemetry.update();
}
Motores e telemetria
Lembre-se de que telemetria é o processo de coletar e transmitir dados. Na robótica, a telemetria é usada para enviar dados internos de atuadores e sensores para a Estação do Condutor (Driver Station). Esses dados podem então ser analisados pelos usuários para tomar decisões que podem melhorar o código.
Uma das formas mais comuns de dados de telemetria de motores é a informação retirada do encoder do motor. Motores DC REV, como o Core Hex Motor, são equipados com encoders internos que transmitem informações de posição na forma de contagens. Para obter informações dos encoders, a seguinte linha precisa ser utilizada:
test_motor.getCurrentPosition();
Na seção de fundamentos de programação, a linha telemetry.addData(); foi brevemente discutida. Essa chamada de método recebe um parâmetro de chave e variável e envia as informações para a Estação do Condutor (Driver Station). A chave é uma string, ou uma linha de texto, que deve definir a variável. Neste caso, o telemetry.addData(); está sendo usado para exibir a posição do motor na forma de contagens do encoder, então a chave pode ser "Encoder Value." No entanto, o parâmetro será a chamada de método test_motor.getCurrentPosition();.
double motorPower = 0;
while (opModeIsActive()) {
motorPower = - this.gamepad1.left_stick_y;
test_motor.setPower(motorPower);
telemetry.addData("Encoder Value", test_motor.getCurrentPosition());
telemetry.addData("Status", "Running");
telemetry.update();
}
Para obter mais informações sobre a programação de encoders, consulte a página "Using Encoders" (Usando Encoders). Para obter mais informações sobre a métrica "counts per revolution" (contagens por revolução) e como usá-la, consulte a página "Encoders" (Encoders).
Programando sensores
Noções básicas do sensor de toque
O objetivo desta seção é abordar alguns dos conceitos básicos de programação de um dispositivo digital, ou sensor de toque, dentro do ambiente de programação Blocks.
Antes de programar com um sensor de toque ou outro dispositivo digital, é importante entender o que é um dispositivo digital e quais são as aplicações comuns para esses dispositivos. Visite a página "Digital Sensors" (Sensores Digitais) para obter mais informações.
Programando um dispositivo digital
Modifique seu modo operacional para adicionar o código relacionado ao dispositivo digital. Isso pode ser feito limpando as modificações de código atuais ou adicionando o código do dispositivo digital ao seu modo operacional.
A informação proveniente de dispositivos digitais vem em dois estados, também conhecidos como estados binários. A forma mais comum de utilizar essa informação é através de uma instrução condicional, como uma instrução if/else. A linha test_touch.getState(); coleta o estado binário FALSO/VERDADEIRO do sensor de toque e atua como condição para a instrução if/else.
if (test_touch.getState()){
//Touch Sensor is not pressed
} else {
//Touch Sensor is pressed
}
O código acima destaca a estrutura básica da instrução if/else para um dispositivo digital. O estado FALSO/VERDADEIRO de um sensor de toque REV corresponde a se o botão no sensor de toque está pressionado ou não. Quando o botão não está pressionado, o estado do sensor de toque é verdadeiro. Quando o botão é pressionado, o estado do sensor de toque é falso. Essa condição é refletida pelos comentários no código.
A maneira mais básica de usar um dispositivo digital é usar a telemetria para exibir informações, como o status do botão do sensor de toque. Para fazer isso, vamos criar uma variável de string chamada touchStatus. Essa variável será criada dentro do modo de operação (op mode).
String é um conjunto de caracteres
public void runOpMode() {
imu = hardwareMap.get(Gyroscope.class, "imu");
test_color = hardwareMap.get(ColorSensor.class, "test_color");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(DigitalChannel.class, "test_touch");
String touchStatus = "";
A linha String touchStatus = ""; declara que a variável touchStatus é uma variável de string vazia. Isso significa que touchStatus está atualmente armazenando uma string sem nenhum caractere.
public void runOpMode() {
imu = hardwareMap.get(Gyroscope.class, "imu");
test_color = hardwareMap.get(ColorSensor.class, "test_color");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(DigitalChannel.class, "test_touch");
String touchStatus = "";
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
if (test_touch.getState()){
//Touch Sensor is not pressed
} else {
//Touch Sensor is pressed
}
telemetry.addData("Status", "Running");
telemetry.update();
}
}
}
Agora, a variável touchStatus está vazia, mas para este exemplo, ela deverá ser alterada para refletir o status do sensor de toque. Para fazer isso, touchStatus deve ser definida como "Não Pressionado" ou "Pressionado".
if (test_touch.getState()){
//Touch Sensor is not pressed
touchStatus = "Not Pressed";
} else {
//Touch Sensor is pressed
touchStatus = "Pressed";
}
Para exibir as informações atribuídas ao touchStatus, é necessário utilizar a telemetria. Na seção de fundamentos de programação, a linha telemetry.addData() foi discutida brevemente. Essa chamada de método recebe um parâmetro de chave e variável, e exibe as informações no Driver Station. A chave é uma string, ou uma linha de texto, que deve definir a variável. Neste caso, a telemetry.addData() está sendo usada para exibir alterações na variável touchStatus, então "Touch Status" seria uma boa chave. O parâmetro será a variável touchStatus. Adicione esta linha acima da linha telemetry.update(); no loop while.
telemetry.addData("Touch Sensor", touchStatus);
Dispositivos digitais como interruptores de limite
Um dos usos mais comuns para um dispositivo digital, como um sensor de toque, é utilizá-lo como um interruptor de limite. A finalidade de um interruptor de limite é interromper um mecanismo, como um braço ou elevador, antes que ele ultrapasse suas limitações físicas. Nesta aplicação, a alimentação precisa ser cortada do motor quando o limite é atingido. Programar um interruptor de limite requer a mesma lógica if/else aplicada na seção anterior. Se o estado do sensor de toque for verdadeiro (não está pressionado), o motor terá energia. Caso contrário (está pressionado), o motor não terá energia.
if (test_touch.getState()){
//Touch Sensor is not pressed
test_motor.setPower(0.3);
} else {
//Touch Sensor is pressed
test_motor.setPower(0);
}
O bloco de código acima introduz os conceitos básicos de um interruptor de limite. Assim como na maioria dos sensores, é bom ter telemetria que atualiza a Estação do Motorista sobre o status do sensor. Considere o seguinte código:
public void runOpMode() {
imu = hardwareMap.get(Gyroscope.class, "imu");
test_color = hardwareMap.get(ColorSensor.class, "test_color");
test_motor = hardwareMap.get(DcMotor.class, "test_motor");
test_servo = hardwareMap.get(Servo.class, "test_servo");
test_touch = hardwareMap.get(DigitalChannel.class, "test_touch");
String touchStatus = "";
telemetry.addData("Status", "Initialized");
telemetry.update();
// Wait for the game to start (driver presses PLAY)
waitForStart();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
if (test_touch.getState()){
//Touch Sensor is not pressed
test_motor.setPower(0.3);
touchStatus = "Not Pressed";
} else {
//Touch Sensor is pressed
test_motor.setPower(0);
touchStatus = "Pressed";
}
telemetry.addData("Touch Sensor:", touchStatus);
telemetry.addData("Status", "Running");
telemetry.update();
}
}
}