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

Enkodery magnetyczne pololu - pomysł na program

Autor Wiadomość
simba92 




Posty: 17
Skąd: Bydgoszcz
Programuję w:
C
Wysłany: 12-07-2017, 20: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ł z FORBOT.PL:
Port szeregowy i interfejs USART

Poprzednia część praktycznie w całości została poświęcona tworzeniu programu od strony komputera. Teraz przysz... Czytaj całość

Ostatnio popularny » Kurs Intel Edison - #9 - Własny czujnik w chmurze


Postaw piwo autorowi tego posta
 
 
ps19 



Posty: 540
Pomógł: 21 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, 19: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, 19:14, w całości zmieniany 1 raz  
Postaw piwo autorowi tego posta
 
 
simba92 




Posty: 17
Skąd: Bydgoszcz
Programuję w:
C
Wysłany: 17-07-2017, 17: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, 12:26, w całości zmieniany 1 raz  
Postaw piwo autorowi tego posta
 
 
Elvis 



Posty: 1187
Pomógł: 83 razy
Otrzymał 216 piw(a)
Skąd: wawa
Programuję w:
C, asm
Wysłany: 18-07-2017, 08: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?

Popularny artykuł » Dni Druku 3D - Kielce, 11-12.03.2015


Postaw piwo autorowi tego posta
 
 
simba92 




Posty: 17
Skąd: Bydgoszcz
Programuję w:
C
Wysłany: 18-07-2017, 12: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
 
 
Elvis 



Posty: 1187
Pomógł: 83 razy
Otrzymał 216 piw(a)
Skąd: wawa
Programuję w:
C, asm
Wysłany: 18-07-2017, 17: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: 17
Skąd: Bydgoszcz
Programuję w:
C
Wysłany: 18-07-2017, 18: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
 
 
Elvis 



Posty: 1187
Pomógł: 83 razy
Otrzymał 216 piw(a)
Skąd: wawa
Programuję w:
C, asm
Wysłany: 18-07-2017, 19: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
 
 
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