Classe+StepperRobot+-+Inicialização

Home > Robótica > Bibliotecas **Recursos** > RunTimer > Timer2 > CircularBuffer > SerialLog > ActionPlan **Dispositivos** > Ultrassom > Array de sensores > NRF24L01 > Wireless log > RF24Control **Movimento** > StepperMotor > StepperMotorTm > **StepperRobot Inicialização** > StepperRobot Operação > StepperRobot Recursos

Introdução
Esta classe finaliza a hierarquia de classes feita para o controle de dois motores de passo em configuração diferencial. Foi feita especificamente para o controle de movimento e posicionamento de um robô. Implementa recursos avançados que funcionam automaticamente sendo necessário um mínimo de interferência. Também foi feito um grande esforço no sentido de economizar bytes no programa e na memória, inclusive com a opção de eliminar partes do código que não sejam necessárias. Um ponto que merece destaque é que TODOS os métodos da classe são não-bloqueantes, ou seja, nenhum deles faz o processamento ficar parado esperando alguma coisa, todos retornam imediatamente, o movimento dos motores é sempre executado em background liberando o processamento para cuidar de outras tarefas.

**Direção diferencial:** Esse tipo de sistema de direção, bastante comum em robôs, dispensa a roda de direção. Usa dois motores de tração conectados a duas rodas independentes. Os movimentos são obtidos sincronizando o giro das duas rodas. Para andar para a frente em linha reta, as duas rodas giram no mesmo sentido e na mesma velocidade. Para fazer curvas, as rodas deve girar no mesmo sentido, mas em velocidades diferentes. Para executar um giro, mantendo a mesma posição, as rodas devem girar na mesma velocidade, mas em sentidos opostos. Todo esse controle é feito por esta biblioteca. Abaixo a lista de movimentos implementados com seus respectivos nomes de definição.
 * **mvAhead**: para frente.
 * **mvBack**: para trás.
 * **mvSpinL**: giro à esquerda. O robô continua na mesma posição, mas gira mudando sua orientação.
 * **mvSpinR**: giro à direita.
 * **mvTurnL**: Curva fechada à esquerda. A roda direita fica travada na mesma posição e a esquerda se move para frente. Como resultado o robô começa a descrever um círculo em volta da roda direita.
 * **mvTurnR**: Curva fechada à direita.
 * **mvBkTurnL**: Curva reversa à esquerda. É o mesmo movimento de mvTurnL, só que em vez da roda esquerda andar pra frente, ela anda para trás.
 * **mvBkTurnR**: Curva reversa à direita.
 * **mvCurveL**: Curva aberta à esquerda. As duas rodas andam para frente, mas a roda direita anda na metade de velocidade que a esquerda. O resultado é uma curva à esquerda.
 * **mvCurveR**: Curva aberta à direita.
 * **mvBrake**: As duas rodas ficam travadas na mesma posição. Como as bobinas ficam ativadas, o robô mantém sua posição mesmo que esteja em um declive.

Inicialização
A inicialização inclui informar os pinos para o controle dos motores de passo e os dados para aceleração e cálculo dos movimentos. Sobre os motores, na versão atual a biblioteca ainda não suporta drives de potência do tipo **//ramp//** para motores´de passo, isso será implementado em uma próxima versão. É assumido que são usados motores de 2 bobinas com 2 fases por bobina (os mais comuns), portando precisam de 4 canais de sinais para serem controlados, como os sinais são gerados pela biblioteca, é necessário usar 4 pinos para cada motor. A boa notícia é isso torna irrelevante para a biblioteca se está sendo usado um motor unipolar ou bipolar, ou seja, pode-se usar qualquer motor de 4 fases. Os drives do tipo //ramp// funcionam apenas com com motores bipolares. Sobre motores de passo leia **//esta discussão//** sobre o assunto para entender melhor a diferença. É claro que os drives de potência precisam estar de acordo com o tipo do motor. Motores unipolares geralmente usam drives baseados no CI //ULN2003//, motores bipolares costumam usar drives baseados em dupla ponte H. Sobre placas de potência **//veja aqui//** mais detalhes. O método **//init//** deve ser chamado para informar os dados sobre a aceleração e cálculo dos movimentos (veja os tópicos seguintes). Os pinos de controle dos motores são informados chamando os métodos **//initRightMotor//** e **//initLeftMotor//** para inicializar os motores direito e esquerdo respectivamente. O código abaixo é um exemplo de como isso pode ser feito.

Calibração
**Controle de aceleração** Os motores de passo podem atingir velocidades relativamente altas, mas precisam ser acelerados gradativamente para ganhar inércia, especialmente quando têm que carregar um peso como o do robô. Também para parar é necessário desacelerar para que os dispositivos instalados no robô não sofram os impactos de uma parada brusca. Então é necessário um sistema de aceleração/desaceleração para que o robô atinja maior velocidade e tenha movimentos suaves. A biblioteca cuida de acelerar e desacelerar automaticamente sempre que necessário. Para isso precisam ser informadas a velocidade de partida (**//startSpeed//**) e a velocidade de cruzeiro (**//cruizeSpeed//**) nos dois primeiros parâmetros do método **init**//.// As duas velocidades devem ser indicadas em pulsos por segundo. Não é muito fácil descobrir as velocidades ideais de partida e cruzeiro para um robô, isso depende de uma infinidade de variáveis que mudam bastante de robô para robô. Mas com algumas tentativas é possível chegar em valores pelo menos aceitáveis. Os motores de passo funcionam muito melhor em altas rotações. Em velocidades baixas vibram muito e gastam muito mais energia. Para descobrir a velocidade de cruzeiro é fácil, basta ir aumentando a velocidade até o momento em que os motores começam a perder passos. E aí basta reduzir um pouco o valor para dar uma margem de segurança. Uma velocidade muito próxima do limite pode ter que ser alterada no futuro se o robô ganhar mais dispositivos e aumentar seu peso. Já a velocidade de partida é um pouco mais trabalhoso. Precisa ser capaz de iniciar o movimento, mas sem muita vibração e sem trancos muito fortes na partida. Velocidades muito baixas provocam vibração e muito altas provocam trancos ou perda de passos.

**Modo de operação dos motores** Motores de passo podem ser operados em 3 modos diferentes: passo completo, meio-passo ou duplo torque. A biblioteca dá suporte aos 3 modos. O modo passo completo é o mais econômico em termos de consumo de energia. É usada uma bobina por fase. Também é o modo com menos torque. Se os motores são fortes o suficiente para o peso do robô e existe preocupação com o consumo de energia, esse é o modo mais indicado. O modo duplo torque usa duas bobinas por fase, o torque do motor dobra, mas também o consumo de energia é dobrado. Caso os motores estejam fracos demais para o peso do robô, usar esse modo pode resolver o problema, com um custo de energia. O modo meio-passo dobra a resolução de passos do motor. Um motor de 400 passos por volta vai completar uma volta em 800 passos, isso melhora muito a precisão dos movimentos. Também o motor tem um funcionamento mais suave que nos outros modos com menos vibrações e trancos menores na partida. O consumo de energia é cerca de 30% maior que no modo passo completo, assim como o torque do motor. Caso não haja problemas de consumo de energia ou de falta de torque, esse é o modo mais indicado. Os métodos **//turboOn//** e **//turboOff//** controlam o modo de duplo torque e os métodos **//halfStepOn//** e **//halfStepOff//** o modo meio-passo. Se os dois modos estão desativados, é o modo passo completo que será usado. Selecione o modo na inicialização, não é aconselhado mudar de modo depois que o robô está em operação.

**turnSteps** O feliz usuário da biblioteca não precisa se preocupar com pulsos e passos ao comandar os movimentos do robô, a biblioteca é capaz de calcular os passos necessários para mover o robô tantos centímetros ou girar tantos graus e providenciar os pulsos correspondentes. Mas para que essa mágica aconteça é preciso informar a medida entre as rodas (em centímetros) e a quantidade de passos que o robô precisa para dar uma volta completa de 360 graus usando um dos movimentos do tipo **//turn//** nos dois últimos parâmetros de **//init//**. No movimento //turn//, uma das rodas fica parada enquanto a outra se move, descrevendo um círculo em torno da primeira. Essa informação deve ser descoberta experimentalmente. Até pode ser calculada a partir do diâmetro das rodas, mas a experiência mostrou que robôs caseiros medidos com recursos caseiros raramente conseguem medidas exatas. Para descobrir a quantidade passos, use o método **//moveSteps//**. Abaixo um exemplo de programa que poderia ser usado para a calibração:

code format="javascript"
 * 1) include 

// motor esquerdo // // motor direito // // Aceleração // Movimento
 * 1) define lfMotorPin1 3
 * 2) define lfMotorPin2 2
 * 3) define lfMotorPin3 5
 * 4) define lfMotorPin4 4
 * 1) define rgMotorPin1 9
 * 2) define rgMotorPin2 8
 * 3) define rgMotorPin3 10
 * 4) define rgMotorPin4 11
 * 1) define startSpeed   130
 * 2) define cruizingSpeed 300
 * 1) define wheelsDist   18.3

class Robot: public StepperRobot{ public: Robot:StepperRobot{}

void init{ init(startSpeed, cruizingSpeed, wheelsDist, 500); // <- valor a ser descoberto, não é usado por moveSteps initLeftMotor (lfMotorPin1, lfMotorPin2, lfMotorPin3, lfMotorPin4); // pinos para o motor esquerdo initRightMotor(rgMotorPin1, rgMotorPin2, rgMotorPin3, rgMotorPin4); // pinos para o motor direito turboOff; halfStepOn; } };

Robot rob;

void setup{ rob.init; }

boolean odd= true;

void loop{ rob.run;
 * 1) ifndef _USE_TIMER2_
 * 1) endif

if(!rob.isMoving){ if(odd) rob.moveSteps(mvTurnL, 468); else rob.moveSteps(mvBrake, 300); // dá uma parada pra permitir a verificação

odd= !odd; } }

code

Talvez essa seja a informação mais simples de encontrar mas mesmo assim existem algumas armadilhas. Afinal em que ponto exatamente da roda deve ser feita a medida? O ideal seria que a roda tivesse uma área de contato com o chão que seja a menor possível para evitar esse tipo de dúvida, rodas mais grossas são mais complicadas e introduzem imprecisão no movimento. Pode ser usado o meio da roda para a medida, mas ela pode apresentar imperfeições que farão com que o valor obtido não seja exato. Essa medida interfere com os cálculos para os movimentos ** //mvAhead// ** e ** //mvBack// **. Para verificar se o valor informado está exato, faça o seguinte. Coloque marcas no chão em distâncias regulares, 50 cm é um bom valor. Eu costumo usar fita crepe para fazer essas marcas. Depois altere o programa acima e na linha onde está:
 * Distância entre as rodas **

code format="javascript" rob.moveSteps(mvTurnL, 468); code troque por:

code format="javascript" rob.move(mvAhead, 50); code e verifique se o robô para exatamente nas marcas. Se estiver parando antes ou depois, mude o valor de wheelsDist até que as paradas coincidam com as marcas no chão.

**Dicas úteis:** Comece a calibração pelas velocidades de partida e cruzeiro. Não vai ser fácil descobrir o valor de **//turnSteps//** se o robô estiver perdendo passos ou dando saltos na partida. Caso o motor esteja muito violento, dando trancos muito fortes na partida, experimente diminuir o tempo de alimentação na partida modificando o valor de **//accelCutPercent//** no arquivo //pbotDefs.h//. Esse valor é a porcentagem de tempo que as bobinas ficam ligadas a cada pulso na partida. O valor default é 0.9, significa que se o pulso tem duração de 10ms, as bobinas serão alimentadas por 9ms e mantidas desligadas por 1ms. Conforme o motor é acelerado esse valor vai aumentando até chegar a 1 na velocidade de cruzeiro (sem corte). Valores menores diminuem o tranco e as vibrações, mas a partir de certo ponto provocam perda de passos. Usar o modo de meio-passo também faz com que o motor funcione mais suavemente e além disso dobra a resolução de passos aumentando a precisão dos movimentos.

A calibração pode ser usada para verificar o alinhamento do eixo de tração (se uma roda está bem alinhada em relação à outra) e das rodas em relação ao chassi. Se o robô estiver perfeitamente alinhado, os eixos das duas rodas estarão sobre a mesma reta e essa reta será perpendicular ao chassi. Além disso o ponto médio entre as duas rodas deve ficar exatamente na linha central do chassi. Uma vez descoberto o valor de **//turnSteps//** para um dos movimentos **//turn//**, basta aplicar o mesmo valor para os outros 3 movimentos e verificar se esse valor continua válido. Comece verificando se usando o movimento reverso o valor continua válido. Por exemplo no código acima foi usado o movimento **//mvTurnL//**, depois de chegar a um valor para **//turnSteps//**, mude o movimento para **//mvBkTurnL//**. Se a roda direita estiver bem paralela ao chassi, o valor continuará válido. Depois faça o mesmo para a roda esquerda usando os movimentos **//mvTurnR//** e **//mvBkTurnR//**.

Se os movimentos //turn// para a esquerda exigem valores diferentes dos movimentos //turn// para a direita, significa que as rodas tem algum desalinhamento uma em relação à outra, ou seja, o eixo delas não está exatamente sobre a mesma reta. Quanto maior for a distância entre as rodas, maior será o erro introduzido pelo desalinhamento. Robôs menores são mais tolerantes a esse tipo de falha.

Temporização dos pulsos
Motores de passo são operados através de pulsos que são enviados a suas bobinas. Cada pulso ativa uma fase de uma bobina por um tempo, depois o pulso é enviado para outra fase de outra bobina e assim por diante. A cada pulso, o motor gira um passo. A temporização desses pulsos é crítica para o bom funcionamento do motor e a biblioteca faz enorme esforço para garantir a precisão do tempo dos pulsos. São oferecidos dois métodos de temporização: por hardware e por software. O método precisa ser escolhido antes de compilar o programa, não é possível mudar o método de operação com o programa rodando.

A temporização por hardware usa o //**timer2**// do arduino para calcular o tempo dos pulsos. É selecionada ativando o **//#define _USE_TIMER2_//** que está declarado no arquivo //stepperDouble.h//. Todo o código relacionado à temporização está dentro de cláusulas #ifdef, de maneira que apenas uma das opções será compilada junto com o programa, isso economiza preciosos bytes no tamanho do programa e no uso de memória RAM, mas impede que o modo seja selecionado com o programa rodando. O //timer2// é o que menos interfere com as funções do arduino. Ele é usado pela função **//tone//** e para gerar os pulsos de //**pwm**// nos pinos 3 e 11, portanto essa função deixa de funcionar, assim como o //pwm// nesses pinos. O uso do //timer2// é indicado em robôs mais complexos que precisem monitorar ou controlar uma grande quantidade de sensores e/ou atuadores enquanto está em movimento. Dessa forma o controle dos motores não interfere muito com o loop principal e vice versa. Mesmo com o uso de delays (arghhh!!!) no código do programa, o movimento dos motores não é afetado.
 * Temporização por hardware **

Robôs mais simples e com menos dispositivos podem usar a temporização por software, nesse caso basta comentar o **//#define _USE_TIMER2//**_ no arquivo //stepperDouble.h//. Isso libera o **//timer2//** para outros usos, mas exige alguns cuidados extras no programa. Para começar é preciso chamar o método **//run//** da classe **//StepperRobot//** pelo menos uma vez a cada iteração do loop principal (veja o código de exemplo acima). É esse método que cuida da temporização, sem ele os motores não funcionam. Além disso o código não pode ter delays ou funções bloqueantes, pelo menos enquanto o robô está se movendo, delays irão parar a temporização e podem até comprometer os motores e as placas de potência se os motores ficarem travados muito tempo com as bobinas ligadas. O método **//run//** não existe na classe quando é usada a temporização por hardware.
 * Temporização por software **