Ta strona używa ciasteczek (plików cookies), dzięki którym może działać lepiej. Dowiedz się więcejRozumiem i akceptuję
Sprawdź ofertę filamentów!

Enkodery magnetyczne pololu - pomysł na program

Autor Wiadomość
simba92 




Posty: 68
Otrzymał 18 piw(a)
Skąd: Bydgoszcz
Programuję w:
C
Wysłany: 12-07-2017, 19:14   Enkodery magnetyczne pololu - pomysł na program

Witam!

Aktualnie realizuje projekt dwukołowego robota mobilnego o napędzie różnicowym z enkoderami magnetycznymi na każdym z kół, konstrukcja mechaniczna została już zrealizowana, elektronika obejmująca projekt plytki drukowanej też, aktualnie programuje. Robot jest sterowany procesorem STM32f103vc i enkodery są podpięte pod TIMER3 tj. sygnały 1A(kanał CH4) i 1B ( CH3) oraz 2A (CH1) i 2B(CH2).

Moje pytanie do forumowiczów jest następujące : czy istnieje możliwość pomiaru ilości impulsów + kierunku obrotu dla każdego koła przy użyciu JEDNEGO TIMERA, jeśli tak to jak ?

:-( Chyba nie przewidziałem opcji sterowania dwoma Timerami, na upartego mogę podpiąć się pod inny timer zmieniając połączenia kabli na płytce, wówczas miałbym do dyspozycji TIM3 + TIM2.

Polecany artykuł » Raspberry Pi. Niesamowite projekty. Szalony Geniusz


Postaw piwo autorowi tego posta
 
 
Więcej szczegółów
Wystawiono 1 piw(a):
alksanda
ps19 



Posty: 558
Pomógł: 22 razy
Otrzymał 43 piw(a)
Skąd: Opole
Programuję w:
C,C#
Należę do:
GROM,Clever Kameleon
Moje roboty:
[Minisumo]Foton, [Minisumo]Buster, [Sumo]Twister, [MegaSumo]POGROMCA

Wysłany: 13-07-2017, 18:11   

Encoder mode jest tylko na dwóch kanałach, ale możesz na pozostałych dwóch odpalić przerwanie zewnętrzne EXTI i na nim liczyć zbocza.

Mam tak zrobione u siebie i działa bez problemowo


Kanał YouTube (Relacje z zawodów)
European Robot Challenge (ERC)
Ostatnio zmieniony przez ps19 13-07-2017, 18:14, w całości zmieniany 1 raz  
Postaw piwo autorowi tego posta
 
 
simba92 




Posty: 68
Otrzymał 18 piw(a)
Skąd: Bydgoszcz
Programuję w:
C
Wysłany: 17-07-2017, 16:18   

ps19 napisałem poniższy kod do obsługi enkoderów, założenia są następujące:

1) kanały 1A i 1B obsługiwane są przez timer TIM8 w trybie Encoder Mode na kanałach CH1 i CH2
2) kanały 2A i 2B obsługiwane są przez timer TIM3 w trybie Encoder Mode na kanałach CH1 i CH2

i kod, który niestety nie działa to znaczy w pętli while() w main() robot powinien obrócić się dokładnie o 90 stopni po zliczeniu 585 impulsów przez jakikolwiek enkoder. ps19 mógłbyś rzucić okiem czy czegoś nie brakuje w kodzie ????
Kod programu: Zaznacz cały

#include <stdint.h>
#include "stm32f10x.h"

#include "rcc_konfiguracja.h"
#include "init.h"
#include "silniki_sterowanie.h"

//definicje enkodera dla silnika1 - LEWY
#define silnik1_ENKODERY_GPIO_PORT                    GPIOC
#define silnik1_ENKODERY_TIMER                        TIM8
#define enkoder_1A_PIN                            GPIO_Pin_6
#define enkoder_1B_PIN                            GPIO_Pin_7


//definicje enkodera dla silnika2 - PRAWY
#define silnik2_ENKODERY_GPIO_PORT                    GPIOA
#define silnik2_ENKODERY_TIMER                        TIM3
#define enkoder_2A_PIN                            GPIO_Pin_6
#define enkoder_2B_PIN                            GPIO_Pin_7


//zmienne do obslugi enkoderow
static volatile int16_t old_silnik1_Enkoder;
static volatile int16_t old_silnik2_Enkoder;

static volatile int16_t silnik1_Enkoder;
static volatile int16_t silnik2_Enkoder;
static volatile int16_t enkoder_Suma;

volatile int16_t silnik1_Count;
volatile int16_t silnik2_Count;
volatile int32_t silnik1_Total;
volatile int32_t silnik2_Total;

void delay(int time)
{
    int i;
    for (i = 0; i < time * 4000; i++) {}
}

void Enkodery_Init(void)
{
GPIO_InitTypeDef             gpio;
TIM_TimeBaseInitTypeDef         tim;
TIM_ICInitTypeDef              incapture;





/*------ KONFIGURACJA kanałów 2A i 2B w trybie Encoder_Mode dla timera TIM3------ */

GPIO_StructInit(&gpio);
gpio.GPIO_Pin = enkoder_2A_PIN| enkoder_2B_PIN;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(silnik2_ENKODERY_GPIO_PORT, &gpio);

TIM_TimeBaseStructInit(&tim);
tim.TIM_CounterMode = TIM_CounterMode_Up;
tim.TIM_Prescaler = 0x0;
tim.TIM_Period = 0xffff;
TIM_TimeBaseInit(TIM3, &tim);

TIM_ICStructInit(&incapture);
incapture.TIM_Channel = TIM_Channel_1;
incapture.TIM_ICPolarity = TIM_ICPolarity_Rising;
incapture.TIM_ICPrescaler = TIM_ICPSC_DIV1;
incapture.TIM_ICSelection = TIM_ICSelection_DirectTI;
incapture.TIM_ICFilter = 0;
TIM_ICInit(TIM3, &incapture);

incapture.TIM_Channel = TIM_Channel_2;
TIM_ICInit(TIM3, &incapture);

TIM_EncoderInterfaceConfig(silnik2_ENKODERY_TIMER, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_SetAutoreload(silnik2_ENKODERY_TIMER,0xffff);
TIM_Cmd(silnik2_ENKODERY_TIMER, ENABLE);

/*----------------------------------------------------------------------------------*/



/*------ KONFIGURACJA kanałów 1A i 1B w trybie Encoder_Mode dla timera TIM8------ */

gpio.GPIO_Pin = enkoder_1A_PIN| enkoder_1B_PIN;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(silnik1_ENKODERY_GPIO_PORT, &gpio); 

tim.TIM_CounterMode = TIM_CounterMode_Up;
tim.TIM_Prescaler = 0x0;
tim.TIM_Period = 0xffff;
TIM_TimeBaseInit(TIM8, &tim);

incapture.TIM_Channel = TIM_Channel_1;
incapture.TIM_ICPolarity = TIM_ICPolarity_Rising;
incapture.TIM_ICPrescaler = TIM_ICPSC_DIV1;
incapture.TIM_ICSelection = TIM_ICSelection_DirectTI;
incapture.TIM_ICFilter = 0;
TIM_ICInit(TIM8, &incapture);

incapture.TIM_Channel = TIM_Channel_2;
TIM_ICInit(TIM8, &incapture);


TIM_EncoderInterfaceConfig(silnik1_ENKODERY_TIMER, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_SetAutoreload(silnik1_ENKODERY_TIMER,0xffff);
TIM_Cmd(silnik1_ENKODERY_TIMER, ENABLE);

/*----------------------------------------------------------------------------------*/



Enkodery_Reset();





}


void Enkodery_Reset(void)
{
    __disable_irq();
    old_silnik1_Enkoder = 0;
    old_silnik1_Enkoder = 0;

    silnik1_Enkoder = 0;  //POPRAWIONE
    silnik2_Enkoder = 0;

    silnik1_Total = 0;
    silnik2_Total = 0;

    TIM_SetCounter(silnik1_ENKODERY_TIMER, 0);
    TIM_SetCounter(silnik2_ENKODERY_TIMER, 0);

    __enable_irq();


}

void Enkodery_Read(void)
{   
    old_silnik1_Enkoder = silnik1_Enkoder;                          //POPRAWIONE
    silnik1_Enkoder = TIM_GetCounter(silnik1_ENKODERY_TIMER);
   
    old_silnik2_Enkoder = silnik2_Enkoder;
    silnik2_Enkoder = TIM_GetCounter(silnik2_ENKODERY_TIMER);




    silnik1_Count = silnik1_Enkoder - old_silnik1_Enkoder;
    silnik2_Count = silnik2_Enkoder - old_silnik2_Enkoder;

    silnik1_Total = silnik1_Total + silnik1_Count; //zmienne okreslajace sume zliczonych impulsow przez
    silnik2_Total = silnik2_Total + silnik2_Count;


}



int main(void)
{

    RCC_Conf();
    RCC_Periph_Conf();   //FUNKCJA wlaczajaca wszystkie potrzebne zegary
    Gpio_Init();




    while(1)
    {


        Enkodery_Init();
   

        while((silnik1_Total <= 585) && (silnik2_Total <= 585))
        {

            robot_jazda(40,-40);  //funkcja odpowiedzialna za obrot robota, PS : napewno działa, robot obraca sie w kolko
            Enkodery_Read();
    }


    }
}







Ostatnio zmieniony przez simba92 18-07-2017, 11:26, w całości zmieniany 1 raz  
Postaw piwo autorowi tego posta
 
 
Więcej szczegółów
Wystawiono 1 piw(a):
alksanda
Elvis 



Posty: 1467
Pomógł: 95 razy
Otrzymał 266 piw(a)
Skąd: wawa
Programuję w:
C, asm
Wysłany: 18-07-2017, 07:56   

Kod programu: Zaznacz cały
    silnik1_Enkoder = TIM_GetCounter(silnik1_ENKODERY_TIMER);
    old_silnik1_Enkoder = silnik1_Enkoder;
    silnik1_Count = silnik1_Enkoder - old_silnik1_Enkoder;

Czy to przypadkiem nie zwraca zawsze zera?

Ostatnio popularny » Snapmaker - więcej niż drukarka 3D


Postaw piwo autorowi tego posta
 
 
simba92 




Posty: 68
Otrzymał 18 piw(a)
Skąd: Bydgoszcz
Programuję w:
C
Wysłany: 18-07-2017, 11:36   

Elvis tak wartość zwracana zawsze byłaby zerowa, poprawiłem to. Efekt działania programu jest taki, że pętla
Kod programu: Zaznacz cały
       
while((silnik2_Total <= 585))
        {
            Enkodery_Read();
            robot_jazda(40,-40);


        }


wykonuję się w nieskończoność, a silniki na dodatek przyspieszają !!!???.
Funkcja
Kod programu: Zaznacz cały

            robot_jazda(40,-40)

wysterowuję mostki TB6612 z wypełnieniem PWM 40 i - 40 , gdzie max. wypełnienie wynosi 200 - 1, a znak oznacza kierunek obrotów. Piszę program do obsługi już kilka dni na podstawie
m.in obsluga_enkoderów F4 , powinno działać :-(

Postaw piwo autorowi tego posta
 
 
Więcej szczegółów
Wystawiono 1 piw(a):
alksanda
Elvis 



Posty: 1467
Pomógł: 95 razy
Otrzymał 266 piw(a)
Skąd: wawa
Programuję w:
C, asm
Wysłany: 18-07-2017, 16:52   

A sprawdzałeś czy same enkodery działają? Może warto sprawdzić za pomocą debuggera czy zmienne mają oczekiwane wartości, ewentalnie wysyłać dane testowe przez port szeregowy?
Inna sprawa, to nie wiem czego oczekujesz po zliczeniu 585 impulsów, bo program który wkleiłeś po prostu zresetuje liczniki i będzie kręcił silnikami od początku

Postaw piwo autorowi tego posta
 
 
simba92 




Posty: 68
Otrzymał 18 piw(a)
Skąd: Bydgoszcz
Programuję w:
C
Wysłany: 18-07-2017, 17:25   

Elvis sprawdzę działanie enkoderów wykorzystując port szeregowy i terminal, tak będzie najlepiej. Swoje pytanie odnośnie kodu wrzuciłem, bo liczyłem ,że może robię jakiś podstawowy błąd i ktoś mi go wytknie.
Cytat:
Inna sprawa, to nie wiem czego oczekujesz po zliczeniu 585 impulsów, bo program który wkleiłeś po prostu zresetuje liczniki i będzie kręcił silnikami od początku
Zgł
Po osiągnięciu wartości 585 impulsów robot obróci się w miejscu o dokładnie 90 stopni, obliczałem to na podstawie długości łuku po jakim porusza się koło o danej średnicy i obwodzie z nią związanym.

Postaw piwo autorowi tego posta
 
 
Więcej szczegółów
Wystawiono 1 piw(a):
alksanda
Elvis 



Posty: 1467
Pomógł: 95 razy
Otrzymał 266 piw(a)
Skąd: wawa
Programuję w:
C, asm
Wysłany: 18-07-2017, 18:00   

Chodziło mi o to, że pętla zliczająca do 585 jest wewnątrz kolejnej pętli. Więc nawet jeśli enkodery działają ok, to doliczasz do 585 i co dalej? Nie masz instrukcji zatrzymującej silniki, zakładam, że robot_jazda() wystarczy wywołać raz i później PWM steruje silnikami do zatrzymania.
Więc nawet po zakończeniu wewnętrznej pętli silniki się kręcą, a kilka mikrosekund później program wraca do głównej pętli, wywołuje Enkodery_Init() i od początku liczy do 585. Może dlatego wygląda jakby ta pętla się nie kończyła? :)
Wydaje mi się, że robot_jazda(40, -40) wystarczy wywołać raz, później w pętli możesz poczekać na enkodery i zatrzymać silniki - może wywołując robot_jazda(0,0)?
Po zatrzymaniu silników musisz trochę poczekać, inaczej nawet nie zauważysz zmiany - możesz poczekać określony czas, albo i nieskończoność ale bez opóźnienia na pewno nie będzie działało zgodnie z oczwkiwaniami.

Postaw piwo autorowi tego posta
 
 
simba92 




Posty: 68
Otrzymał 18 piw(a)
Skąd: Bydgoszcz
Programuję w:
C
Wysłany: 15-08-2017, 16:08   

Elvis poprawiłem i uprościłem program do minimum, generalnie chcę po prostu tylko uruchomić tryb enkoderów na liczniku TIM3 i funkcją
Kod programu: Zaznacz cały
 printf("wartosc=%d\r\n",TIM_GetCounter(TIM3));
wyświetlić na terminalu wartość w liczniku. Przy pisaniu programu posługiwałem się m.in kursem STM32 F4, gdzie konfiguracja licznika w trybie enkodera https://forbot.pl/blog/artykuly/programowanie/kurs-stm32-f4-8-zaawansowane-funkcje-licznikow-id13473 jest banalna i zawiera ustawienie kilku parametrów nic więcej co w analogi do standardowej biblioteki powinno wyglądać tak samo. Poniżej kod programu obejmujący funkcje sterującą silnikami, konfiguracje transmisji przez interfejs UART i wspomnianych enkoderów tj. enkodera na silniku nr 2

Kod programu: Zaznacz cały

#include "stm32f10x.h"
#include "math.h"
#include "stdint.h"
#include "stdio.h"


#define silnik1_IN1                            GPIO_Pin_14
#define silnik1_IN2                            GPIO_Pin_15
#define silnik1_IN_GPIO                        GPIOD
#define silnik1_PWM                            GPIO_Pin_8

#define silnik2_IN1                            GPIO_Pin_15
#define silnik2_IN2                            GPIO_Pin_14
#define silnik2_IN_GPIO                        GPIOE
#define silnik2_PWM                            GPIO_Pin_9

#define silniki_PWM_GPIO                        GPIOA
#define licznik_max                            199


#define enkoder_2A_Pin                        GPIO_Pin_6
#define enkoder_2B_Pin                        GPIO_Pin_7
#define silnik2_ENKODERY_GPIO_Port            GPIOA




void robot_jazda(int lewy, int prawy)
{


    if(lewy >= 0 )
    {
        if(lewy > licznik_max)
            lewy = licznik_max;

        GPIO_SetBits(silnik1_IN_GPIO, silnik1_IN1);   //jazda do przodu lewe koło
        GPIO_ResetBits(silnik1_IN_GPIO, silnik1_IN2);


    }
    else
    {
        if(lewy < -licznik_max)
            lewy = -licznik_max;

        GPIO_ResetBits(silnik1_IN_GPIO, silnik1_IN1);
        GPIO_SetBits(silnik1_IN_GPIO, silnik1_IN2);



    }


    if(prawy >= 0)                         //jazda do przodu prawe koło
    {
        if(prawy > licznik_max)
            prawy = licznik_max;

        GPIO_SetBits(silnik2_IN_GPIO, silnik2_IN2);
        GPIO_ResetBits(silnik2_IN_GPIO, silnik2_IN1);


    }
    else
    {
        if(prawy < -licznik_max)
            prawy = -licznik_max;

        GPIO_ResetBits(silnik2_IN_GPIO, silnik2_IN2);
        GPIO_SetBits(silnik2_IN_GPIO, silnik2_IN1);

    }


    TIM_SetCompare1(TIM1, fabs(lewy));
    TIM_SetCompare2(TIM1, fabs(prawy));

}


int main(void)
{
    GPIO_InitTypeDef gpio;
    TIM_TimeBaseInitTypeDef tim;
    TIM_OCInitTypeDef  channel;
    USART_InitTypeDef uart;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |  RCC_APB2Periph_GPIOD| RCC_APB2Periph_GPIOC| RCC_APB2Periph_GPIOE, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);


    GPIO_StructInit(&gpio);
    gpio.GPIO_Pin = silnik1_IN1 | silnik1_IN2; // silnik1 wejscia sterujace IN_1 i IN_2
    gpio.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(silnik1_IN_GPIO, &gpio);

    gpio.GPIO_Pin = silnik2_IN1 | silnik2_IN2; // silnik2 wejscia sterujace IN_1 i IN_2
    gpio.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(silnik2_IN_GPIO, &gpio);

    gpio.GPIO_Pin = GPIO_Pin_5; // led test
    gpio.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &gpio);



    gpio.GPIO_Pin = silnik1_PWM | silnik2_PWM;  // konfiguracja pinow dla trybu pwm
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    gpio.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(silniki_PWM_GPIO, &gpio);

    TIM_TimeBaseStructInit(&tim);
    tim.TIM_CounterMode = TIM_CounterMode_Up;
    tim.TIM_Prescaler = 800 - 1; //80khz
    tim.TIM_Period = 200 - 1;
    TIM_TimeBaseInit(TIM1,&tim);


    TIM_OCStructInit(&channel);
    channel.TIM_OCMode = TIM_OCMode_PWM1;
    channel.TIM_OutputState = TIM_OutputState_Enable;
    channel.TIM_OCNPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM1, &channel);
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

    channel.TIM_OCMode = TIM_OCMode_PWM1;
    channel.TIM_OutputState = TIM_OutputState_Enable;
    channel.TIM_OCNPolarity = TIM_OCPolarity_High;
    TIM_OC2Init(TIM1, &channel);
    TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);


    TIM_ARRPreloadConfig(TIM1, ENABLE);
    TIM_CtrlPWMOutputs(TIM1, ENABLE);


    TIM_Cmd(TIM1, ENABLE);


    /*--------------Konfiguracja UART4---------------------*/
    gpio.GPIO_Pin = GPIO_Pin_10;
    gpio.GPIO_Mode = GPIO_Mode_AF_PP;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &gpio);

    gpio.GPIO_Pin = GPIO_Pin_11;
    gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &gpio);


    USART_StructInit(&uart);
    uart.USART_BaudRate = 9600;
    uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    uart.USART_WordLength = USART_WordLength_8b;
    uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    uart.USART_Parity = USART_Parity_No;
    uart.USART_StopBits = USART_StopBits_1;
    USART_Init(UART4, &uart);

    USART_Cmd(UART4, ENABLE);

    /*------------Konfiguracja uart---------------------------*/



    /*--------------KONFIGURACJA ENKODERA - prawy silnik(silnik2) - licznik TIM3 ---------------------*/

    gpio.GPIO_Pin = enkoder_2A_Pin | enkoder_2B_Pin;
    gpio.GPIO_Mode = GPIO_Mode_AF_PP;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(silnik2_ENKODERY_GPIO_Port, &gpio);

    tim.TIM_CounterMode = TIM_CounterMode_Up;
    tim.TIM_Period = 0xffff; //wartość po której licznik się przepełnia
    TIM_TimeBaseInit(TIM3,&tim);

    TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
    TIM_Cmd(TIM3, ENABLE);


    /*--------------------------------------------------------*/





    while(1)
    {


        robot_jazda(40,40); //wypełnienie PWM wynosi 40 dla obu silników, funkcja działa w momencie jej wywolania i koła kręcą się w nieskończoność

        printf("wartosc=%d\r\n",TIM_GetCounter(TIM3)); //wyswietlana wartość wynosi 0, licznik nic nie zlicza, a powinnien ?!
       

    }

}


Poniżej zdjęcie z terminala :



Podsumowując :

1) licznik nic nie zlicza, może brakuje jakieś linijki kodu, etc ?!
2) połączenie fizyczne kanałów jest poprawne

[ Dodano: 15-08-2017, 19:16 ]
Uruchomiłem tryb enkoderów, brakowało konfiguracji kilku peryferiów m.in kontrolera przerwań i ustawienia wejść jako
Kod programu: Zaznacz cały
 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
, później wrzucę pełen kod może komuś się przyda :-)

Ostatnio zmieniony przez simba92 15-08-2017, 16:19, w całości zmieniany 3 razy  
Postaw piwo autorowi tego posta
 
 
Wyświetl posty z ostatnich:   
Odpowiedz do tematu
Nie możesz pisać nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Nie możesz załączać plików na tym forum
Możesz ściągać załączniki na tym forum
Wersja do druku

Skocz do:  

Nie rozwiązałeś swojego problemu? Zobacz podobne tematy: Styczniki w MiniSumo... Jaki czujnik do robo... "czunik" d... Odkurzach TCM jako b...
lub przeszukaj forum po wybranych tagach: enkodery, magnetyczne, na, pololu, pomysl, program


Powered by phpBB modified by Przemo © 2003 phpBB Group
Popularne kursy: Arduinopodstawy elektroniki