collapse

* Posts Recentes

Amplificador - Rockboard HA 1 In-Ear por almamater
[Ontem às 19:13]


O que é isto ? por KammutierSpule
[26 de Março de 2024, 19:35]


Bateria - Portátil por almamater
[25 de Março de 2024, 22:14]


Emulador NES em ESP32 por dropes
[13 de Março de 2024, 21:19]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]


Meu novo robô por josecarlos
[06 de Janeiro de 2024, 16:46]


Laser Engraver - Alguém tem? por almamater
[16 de Dezembro de 2023, 14:23]

Autor Tópico: Controle Analógico com Pic16f876  (Lida 5942 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline ewertonluiz

  • Mini Robot
  • *
  • Mensagens: 6
Controle Analógico com Pic16f876
« em: 24 de Maio de 2009, 05:32 »
Meu nome é Ewerton e sou estudante de Automação Industrial no Instituto Federal de Educação Tecnológica, Cuiabá MT, Brasil. Comecei agora e não sei muita coisa além do que minha experiência com telefones móveis me proporcionou (sou proprietário de uma pequena assistência técnica).

Haverá uma competição (sumo de robo) em breve. E há alguns dias idealizei um controle remoto, e como eu já esperava não era exclusividade minha essa idéia.

Coincidência... é muito parecido com um postado no tópico http://lusorobotica.com/index.php/topic,613.0.html pelo nosso amigo Guilherme, que por sua vez baseou-se noutro http://letsmakerobots.com/node/4643. A diferença é que vou usar apenas um joystick que deve controlar dois motores cc. Usando apenas uma mão quero que dê ao robo todos os movimentos possíveis.

São eles:
  • Frente
  • Curva à esquerda
  • Curva à direita
  • Spin para esquerda
  • Spin para direita
  • Fuga em ré para esquerda
  • Fuga em ré para direita
  • Ré.

Preciso de ajuda. porque não tenho experiência em programação com microcontroladores (só havia programado em delphi e php, até então). Mas estudei alguns materiais sobre C e Pic na internet e consegui desenvolver um código. Ele está 'bugado' e não consigo achar os erros.

Mas vamos lá... Vou falar um pouco das idéias que tive com relação ao funcionamento do mesmo. A Figura 1 mostra cada um dos movimentos desejados.



Com um controle analógico de playstation ainda podemos colocar os movimentos intermediários e controle de aceleração por PWM.

Para não perder aceleração no momento que mais precisamos (ex.: movimento frontal) preferi trabalhar com o vetor formado pelos dois eixos. A Figura 2 mostra a conversão em coordenada polar.



Em cada posição os motores devem entender de forma diferenciada o módulo. Por isso coloquei fatores, para cada ângulo notável dessa situação, como mostra a Figura 3. Eles multiplicarão o módulo e com isso nos dará um valor para o PWM de cada motor. Esses fatores geraram funções que determinarão o fator de angulos intermediários aos nossos "notáveis". Veja o gráfico na Figura 4.





Estou postando o código fonte que fiz para um PIC16F876 com oscilidador de 4MHz. Utilizei CCS v4.

Fiz todos os desenhos que pude no CorelDRAW para esclarecer bem. Mas posso ser mais claro se alguém não entender direito.

Código: [Seleccione]
//////////// Configuração do Chip ////////////
#include <16F876.H>
#include <math.h>
#use Delay(Clock=4000000)
#fuses    HS, NOWDT, NOPUT, NOPROTECT, NOBROWNOUT, NOLVP

//////////// Declaração da Funções //////////////

void init();

/////////// Declaração da Variaveis /////////////

#byte   port = 6                                     // endereço da porta B (não sei pq está aqui)

#define PWM_FREQ 255

char    pwme,pwmd;
float   modulo,angulo,fe,fd;
short   reve,revd;
signed long int x,y;
////////// Implementação das Funções ////////////

void main()
{
    init();                                          // não sei pq está aqui
    while(TRUE)
    {

        setup_port_a(ALL_ANALOG);                    // Define que as portas A serão analogicas
        setup_adc(adc_clock_internal);               // não sei explicar mas acho que entendi
        set_adc_channel( 0 );                        // prepara para ler o 1º canal analógico
        delay_us(30);
        x = (2 * read_adc())-255;                    // le o 1º canal e armazena na variavel 'x'
        set_adc_channel( 1 );                        // prepara para ler o 2º canal analógico
        delay_us(30);
        y = (2 * read_adc())-255;                    // le o 2º canal e armazena na variavel 'y'
        modulo = SQRT((x^2)+(y^2));                  // define o módulo do vetor produzido pelo joystick
        if (x==0)                                    // se o x joystick está em estado inicial
        {
            if (y==0)                                // se o y joystick tb está em estado inicial
            {
                angulo = 0;                          // define as variaveis como nula
                modulo = 0;
            }
            else                                     // angulos de 90 e 270 não possuem tangente
            {
                if (y < 0)                           // caso y seja "negativo"
                {
                    angulo = 3*PI/2;
                }
                else                                 // caso y seja "positivo" poderia ser "if (y > 0)]"
                {
                    angulo = PI/2;
                }
            }
        }

////////// Inicia calculo da coordenada polar //////////

        if (x < 0)                                   // caso x seja "negativo"
        {
            angulo=ATAN(x/y)+PI;                     // arco tangente dos angulos do 2º e 3º quadrante
        }
        else                                         // poderia ser (x > 127)
        {
            angulo = ATAN(x/y);                      // arco tangente, 1º e 4º quadrantes
        }                                            // finaliza o calculo da coordenada polar

/////////// Correção para angulos do 4º quadrante ///////////

        while (angulo < 0)                            // enquanto o angulo for negativo
        {
            angulo = angulo+(2*PI);                   // adiciona uma volta completa
        }

/////////// Apenas para garantir /////////////

        while (angulo > (2*PI))                         // enquanto o angulo for maior que 360
        {
            angulo = angulo-(2*PI) ;                    // remove uma volta completa
        }

/////////// Grafico de funções matemática /////////////

        if (angulo <= (PI/2))
        {
            fe = 1;                                     // fator esquerdo
            fd = (4*angulo/PI)-1;                       // fator direito
        }
        else
        {
            if (angulo <= PI)
            {
                fe = ((-4)*angulo/PI)+3;
                fd = 1;
            }
            else
            {
                if (angulo <= (5*PI/4))
                {
                    fe = (4*angulo/PI)-5;
                    fd = ((-8)*angulo/PI)+9;
                }
                else
                {
                    if (angulo <= (3*PI/2))
                    {
                        fe = ((-4)*angulo/PI)+5;
                        fd = -1;
                    }
                    else
                    {
                        if (angulo <= (7*PI/4))
                        {
                            fe = -1;
                            fd = (4*angulo/PI)-7;
                        }
                        else                         // para todos os outros angulos, poderia ser if (angulo <= (2*PI))
                        {
                            fe = (8*angulo/PI)-15;
                            fd = ((-4)*angulo/PI)+7;
                        }
                    }
                }
            }
        }

/////////// Determina sentido de rotação dos motores /////////////

        if (fe < 0)
        {
            reve = 1;                                // reverso esquerdo
            fe = 0-fe;
        }
        else
        {
            reve = 0;
        }
        if (fd < 0)
        {
            revd = 1;                                // reverso direito
            fd = 0-fd;
        }
        else
        {
            revd = 0;
        }
        
/////////// PWM para os dois motores /////////////
        
        pwme = floor(fe * modulo);
        pwmd = floor(fd * modulo);
        if(pwme == 0)
        {
            setup_ccp1(CCP_OFF);                     // desliga o 1º pwm
            output_low(PIN_B0);                      // desliga o pino 21
            output_low(PIN_B1);                      // desliga o pino 22
        }
        else
        {
            set_tris_c(0x80);
            setup_ccp1(CCP_PWM);                     // Configure CCP1 as a PWM
            setup_timer_2(T2_DIV_BY_1, PWM_FREQ, 1); // PWM_FREQ => determina a frequencia do PWM
            set_pwm1_duty(pwme);
        }
        if(pwmd == 0)
        {
            setup_ccp2(CCP_OFF);                     // desliga o 2º pwm
            output_low(PIN_B2);                      // desliga o pino 23
            output_low(PIN_B3);                      // desliga o pino 24
        }
        else
        {
            set_tris_c(0x80);
            setup_ccp2(CCP_PWM);                     // Configure CCP1 as a PWM
            setup_timer_2(T2_DIV_BY_1, PWM_FREQ, 1); // PWM_FREQ => determina a frequencia do PWM
            set_pwm1_duty(pwmd);
        }
/////////// Aplica o sentido de rotação dos motores /////////////
       if(reve==1)                                   // se o reverso esquerdo estiver ligado
       {
          output_high(PIN_B0);                       // liga o pino 21
          output_low(PIN_B1);                        // desliga o pino 22
       }
       else                                          // se o reverso esquerdo estiver desligado
       {
          output_low(PIN_B0);                        // desliga o pino 21
          output_high(PIN_B1);                       // liga o pino 22
       }
       if(revd==1)                                   // se o reverso direito estiver ligado
       {
          output_high(PIN_B2);                       // liga o pino 23
          output_low(PIN_B3);                        // desliga o pino 24
       }
       else                                          // se o reverso direito estiver desligado
       {
          output_low(PIN_B2);                        // desliga o pino 23
          output_high(PIN_B3);                       // liga o pino 24
       }
    }
}

////////// Outras funções declaradas ////////////

void init()
{
        enable_interrupts(global);              // Habilita Interrupção Geral (não sei se precisa disto)
}
« Última modificação: 24 de Maio de 2009, 05:56 por ewertonluiz »

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re:Controle Analógico com Pic16f876
« Responder #1 em: 24 de Maio de 2009, 15:16 »
Olás, vou só dar-te 2 indicações genéricas:

1) Fizeste um excelente post de explicação do teu sistema mas não disseste uma das coisas mais importantes: quais são os problemas que estás a ter com esse programa. Se um cliente deixar um telemóvel na tua loja para reparação com uma nota a descrever o problema, o que preferes que diga a nota: "não funciona" ou "quando faço uma chamada o ecran fica preto" :)?

2) Quando estamos a iniciar-nos o pior que se pode fazer é construir logo um sistema inteiro e depois tentar pôr a funcionar. Depois de termos um monte de código (ou hardware) é muito dificil perceber o que vai mal. O que se deve fazer é ir construindo e testando por partes. É muito mais fácil perceber o que vai mal num pedaço de código pequeno. E também é muito mais fácil fazer crescer o sistema quando temos a certeza que as partes que já lá estão funcionam. Devias começar por exemplo por tirar todo o código deixando apenas a leitura do joystick, e testar essa leitura até teres a certeza de que estás a lê-lo bem. Só depois adicionar mais um pouco de código e testar, corrigir, e assim sucessivamente até teres o sistema completo. Quando adicionas mais uma nova funcionalidade, se o programa deixar de funcionar já sabes que o problema foi introduzido apenas por essa nova funcionalidade (e podes sempre voltar atrás se necessário).

Offline ewertonluiz

  • Mini Robot
  • *
  • Mensagens: 6
Re:Controle Analógico com Pic16f876
« Responder #2 em: 24 de Maio de 2009, 15:27 »
 ;D Você tem toda a razão!!! Como pude me esquecer do mais importante ao pedir ajuda???

O problema é com o reverso esquerdo, só fica ligado.

Obrigado!!! Vou dividi-lo e testar passo-à-passo...
« Última modificação: 24 de Maio de 2009, 15:28 por ewertonluiz »

Offline guibot

  • Mini Robot
  • *
  • Mensagens: 651
    • Guibot
Re:Controle Analógico com Pic16f876
« Responder #3 em: 24 de Maio de 2009, 15:56 »
olá Ewerton, não será algo deste género que precisas?

Take that values from the joystick as it sits, up-down axis called Y with values given from 75 bottom to 225 top, right-left values called axis X with 225 left, 75 right.

         Y
        225
X 225 <>  75   Joystick
         75

PWM values for left and right wheels can then be calculated from formulas :

L_PWM = (Y - X) + 150

R_PWM = (Y+ X) - 150

Evaluation of calculated output :

Direction (Y,X) :
Full Fwd (225,150): L_PWM = (225 - 150) + 150 = 225, R_PWM = (225 + 150) - 150 = 225
Full Rev (75,150) : L_PWM = (75 - 150) + 150 = 75, R_PWM = (75 + 150) - 150 = 75
spin CW (150,225): L_PWM = (150 - 225) + 150 = 75, R_PWM = (150 + 225) - 150 = 225
spin CCW (150,75): L_PWM = (150 - 75) + 150 = 225, R_PWM = (150 + 75) - 150 = 75

curve forward left (205,205): L_PWM = (205 - 205) + 150 = 150, R_PWM = (205 + 205) - 150 = 260, out of range
curve forward right (205,95): L_PWM = (205 - 95) + 150 = 260 out of range, R_PWM = (205 + 95) - 150 = 150

curve back left (95,205): L_PWM = (95 - 205) + 150 = 40 out of range, R_PWM = (95 + 205) - 150 = 150
curve back right (95,95): L_PWM = (95 - 95) + 150 = 150, R_PWM = (95 + 95) - 150 = 40 out of range

Might be needed to limit max and min range values for PWM output.

Offline ewertonluiz

  • Mini Robot
  • *
  • Mensagens: 6
Re:Controle Analógico com Pic16f876
« Responder #4 em: 24 de Maio de 2009, 22:40 »
Muito bom!!!

Foi você quem desenvolveu esse cálculo? Se foi, parabéns. Se não foi podia citar a fonte.

Provavelmente resolveu o problema sem arco tangente, graficos e funções matemáticas complexas. Muito bom mesmo.

Vou implementar e testar.

Muito obrigado.

Offline guibot

  • Mini Robot
  • *
  • Mensagens: 651
    • Guibot
Re:Controle Analógico com Pic16f876
« Responder #5 em: 24 de Maio de 2009, 23:11 »
este cálculo foi o robologist que o escreveu neste post  :)
http://letsmakerobots.com/node/5358

Offline ewertonluiz

  • Mini Robot
  • *
  • Mensagens: 6
Re:Controle Analógico com Pic16f876
« Responder #6 em: 25 de Maio de 2009, 21:07 »

Fiz o gráfico das funções



Percebi que as fugas para esquerda e direita em ré ficam invertidas (225º vai para direita e 315º vai para esquerda.



Mas já é uma evolução e tanto... Obrigado Guilherme!!!