Classe+DoubleStepperTm

Home > Robótica > Bibliotecas **Recursos** > RunTimer > Timer2 > CircularBuffer > SerialLog > ActionPlan **Dispositivos** > Ultrassom > Array de sensores > NRF24L01 > Wireless log > RF24Control **Movimento** > StepperMotor > StepperMotorTm > DoubleStepper > **DoubleStepperTm**

Descendente de **//DoubleStepper//**, esta classe acrescenta a temporização dos pulsos para os motores de passo. O controle de tempo pode ser feito via software, com a emulação de um timer, ou via hardware, usando o timer2 do arduino. Além disso, também é implementado um sistema de aceleração/desaceleração automática e de proteção de sobrecarga aos circuitos e motores.

Abaixo a declaração pública da classe: code format="java5" typedef void (*MoveDoneEvent)(char movType, int steps);

class DoubleStepperTm: public DoubleStepper { public: DoubleStepperTm; void init(uint startSpeed, uint cruizeSpeed); boolean moveSteps(char movType, uint steps); void addStepsToMove(uint steps); void setStepsToReport(uint steps); virtual boolean isMoving; char currentMoveType; void decelStop; void stopNow;

void run;
 * 1) ifndef _USE_TIMER2_
 * 1) endif

// Herdado de DoubleStepper void initLeftMotor(int mPin_1, int mPin_2, int mPin_3, int mPin_4); void initRightMotor(int mPin_1, int mPin_2, int mPin_3, int mPin_4); void turboOn; void turboOff; void halfStepOn; void halfStepOff; boolean halfStep; void motorOff;

protected: virtual void onMoveDone(char movType, int steps){} virtual void onStepsDone(char movType, int steps){} };

code

Temporização dos pulsos
O controle de tempo para os pulsos enviados aos motores pode ser feito por hardware usando o timer2 do arduino ou por software. Por hardware fica mais preciso e interfere menos com o loop principal, mas gasta um timer pra isso. O timer 2 é usado pela função //tone//, portanto essa função deixa de funcionar se escolher essa opção. Por outro lado, se o robô tiver uma grande quantidade de sensores e atuadores para controlar enquanto se move, é melhor usar o timer2 mesmo, assim a interferência com outras tarefas é mínima. Robôs mais simples podem usar o controle por software. Para ativar o uso do timer2 deixe ativo (fora de comentários) o **//#define _USE_TIMER2_//** declarado no arquivo //doubleStepper.h//. Se comentar esse //#define// o controle será feito por software, nesse caso não esqueça de fazer uma chamada ao método **//run//** pelo menos uma vez a cada iteração do loop principal. Quando o timer2 é usado, esse método não existe nesta classe.

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. Os dois parâmetros do método //init// controlam a aceleração. //startSpeed// informa a velocidade de partida. É nessa velocidade que o robô inicia ou finaliza seus movimentos. //cruizeSpeed// é a velocidade de cruzeiro que ele atinge após a aceleração. As duas velocidades devem ser indicadas em pulsos por segundo. O controle da aceleração é automático, basta indicar as velocidades de partida e de cruzeiro.

Comando de movimentos
Para iniciar um movimento use o método **//moveSteps//** indicando o tipo de movimento e a quantidade de passos. Veja a lista de movimentos na página da classe **//DoubleStepper//**. O método //moveSteps// não é bloqueante, ele inicia o movimento e já retorna, o movimento será executado em //background//. O método ** //addStepsToMove// ** adiciona passos ao movimento em curso alongando o movimento. Não tem efeito se os motores não estão em movimento ou se já estão na fase de desaceleração.

**Controle de vibrações** Motores de passo têm algumas características de funcionamento que precisam ser levadas em conta durante sua operação. Em baixas rotações, antes de atingir a velocidade de cruzeiro, pode ocorrer alguma vibração. Eventualmente, dependendo dos motores utilizados, da voltagem da bateria, do peso do robô e de outros fatores, em determinados valores de RPM a vibração pode ficar intensa o suficiente para atrapalhar a navegação provocando desvios na trajetória robô. Para diminuir a vibração, a classe corta a alimentação das bobinas antes do final do pulso durante o período de aceleração/desaceleração. Normalmente as bobinas dos motores são alimentadas por todo o período de duração do pulso. Mas a fim de diminuir a vibração, foi implementado o recurso de cortar a alimentação das bobinas antes do final do pulso e aguardar o tempo restante com as bobinas desligadas. Esta técnica além de diminuir bastante a vibração em baixas rotações, também acaba por economizar energia aumentando a autonomia do robô. Os testes realizados deram resultados bastante positivos, então esse recurso já está ativado por default.

Essa técnica também é usada pela classe //StepperMotorTm// então o #define que estabelece a porcentagem de corte está declarado no arquivo //stepperMotor.h//:

code format="java5"
 * 1) define accelCutPercent 0.9

code

Essa porcentagem é um valor entre 0 e 1 que indica a porcentagem do pulso antes do corte. Por exemplo, se o pulso tem a duração de 10 milissegundos e a porcentagem informada é de 0.75, então as bobinas serão alimentadas por 75% do tempo (7.5 ms) e mantidas desligadas pelo tempo restante (2.5 ms). O melhor valor para esse parâmetro depende de tantos fatores que deve ser calibrado especialmente para o robô em questão e para o modo de operação dos motores (half ou full step) experimentalmente. Valores muito altos (próximos de 1) são menos efetivos, mas valores muito baixos podem provocar a perda de passos. O valor default é 0.9.

Corte com as rodas travadas
Os quatro movimentos do tipo //turn// exigem que uma das rodas fique parada na mesma posição enquanto a outra se move fazendo um círculo. Para garantir que a roda parada fique realmente parada, as bobinas são ativadas travando a roda na posição em que está. No caso do movimento //mvBrake//, as duas rodas ficam travadas na mesma posição. Sempre que as rodas estão travadas, a classe também utiliza a técnica de corte de alimentação ao energizar as bobinas, só que o corte é muito mais intenso, o valor default é 50%. Esse corte evita que uma bobina fique ligada continuamente por um tempo longo, o que poderia queimar o motor ou a placa controladora. Além de proteger o motor e os circuitos, também economiza energia, já que a bobina não fica ligada o tempo todo. O #define que estabelece a porcentagem de corte também está declarado no arquivo //stepperMotor.h//:

code format="java5"
 * 1) define brakeCutPercent 0.5

code Abaixo um programa de exemplo para testar os movimentos.

code format="java5"
 * 1) include 

// motor esquerdo // motor direito // Aceleração // Movimentos
 * 1) define lfMotorPin4 4
 * 2) define lfMotorPin3 5
 * 3) define lfMotorPin2 2
 * 4) define lfMotorPin1 3
 * 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 turnSteps 630
 * 2) define spinSteps (turnSteps/2)

DoubleStepperTm rob;

void setup { Serial.begin(57600); Serial.println("Iniciando");

rob.init(startSpeed, cruizingSpeed); rob.initLeftMotor (lfMotorPin1, lfMotorPin2, lfMotorPin3, lfMotorPin4); rob.initRightMotor(rgMotorPin1, rgMotorPin2, rgMotorPin3, rgMotorPin4);

rob.turboOff; rob.halfStepOn; rob.move(mvBrake, 200); }

int mv= 0;

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

if(!rob.isMoving) {   switch(mv) {     case 0: rob.moveSteps(mvTurnL, turnSteps); break; case 1: rob.moveSteps(mvTurnR, turnSteps); break; case 2: rob.moveSteps(mvAhead, 500); break; case 3: rob.moveSteps(mvSpinL, spinSteps); break; case 4: rob.moveSteps(mvBrake, 200); break; case 5: rob.moveSteps(mvSpinR, spinSteps); break; case 6: rob.moveSteps(mvBack, 200); break; case 7: rob.moveSteps(mvCurveR, turnSteps*2); break; case 8: rob.moveSteps(mvCurveL, turnSteps*2); break; case 9: rob.moveSteps(mvBrake, 200); break; }   mv= (mv+1)%10; } } code