Serwomechanizm Możliwość dokładnego sterowania położenia (lub podobnej wartości) za pomocą układu ze sprzężeniem zwrotnym: Systemy Wbudowane Raspberry Pi Sterowanie serwomechanizmem (wersja 2019) Zadajemy nowe położenie, Układ zmierza ku położeniu, Odbywa się ciągły pomiar położenia, Gdy położenie osiągnie żądane, układ zatrzymuje się. Problemy: mgr inż. Marek Wilkus http://home.agh.edu.pl/~mwilkus Wydział Inżynierii Metali i Informatyki Przemysłowej AGH Kraków 1 Serwomechanizm z silnikiem krokowym Bezwładność, Niedokładność mechanizmu, Oscylacje (zbyt wąska histereza) 2 Serwomechanizm na silniku klasycznym Dodatkowe pomiary położenia za pomocą tarczy magnesów trwałych i czujnika (hallotron lub kontaktron), rzadziej stosowany jest pomiar wartości ciągłej (potencjometr). Często dostępne jako "wszystko w jednym", Możliwość użycia gotowych układów aparaturowych i modelarskich Stosowany gdy pozycja wału silnika jest niewystarczająca do ustalenia położenia, Pomiar położenia odbywa się na ostatnim stadium (np. sterowanie kamerą na samej obudowie kamery, nie wale silnika kilka przekładni wcześniej), Niezbędne układy pomiarowe, stały monitoring położenia (np. transoptor odbiciowy), nie tylko położeń krańcowych (wyłączniki krańcowe). Zastosowanie: Aparatura produkcyjna wysokiej precyzji, Profesjonalne skanery, Urządzenia wielkiej skali. 3 Potencjometr: 4 Regulator PID: Sprzężenie zwrotne, ale jak? Nie tylko położenie... Jakkolwiek większość serwomechanizmów służy do regulacji położenia, możliwe jest zastosowanie regulatorów o sprzężeniu zwrotnym do regulacji i stabilizacji innych wielkości. Fotografia: Detektor prędkości silnika napędu taśmowego. Pomiar służy do stabilizacji prędkości i kompensacji niedokładności szybkości silnika. Problemy: Zapamiętujemy poprzednie wskazania i wyciągamy wnioski, Przewidujemy do przodu, Cały czas mamy aktualną pozycję i korygujemy ją, Poprawki nanosimy iteracyjnie, małymi krokami, Konieczna dokładność pomiarów Szybki układ obsługi sprzężenia zwrotnego. 5 6
Regulator PID Skład PID: Człon proporcjonalny e(t) = r(t) y(t) Człon całkujący u(t) zmiany które trzeba uwzględnić r(t) cel do osiągnięcia e(t) błąd w danym momencie y(t) efekt wprowadzanych zmian Człon różniczkujący u(t) zmiany które trzeba uwzględnić r(t) cel do osiągnięcia e(t) błąd w danym momencie y(t) efekt wprowadzanych zmian 7 Serwomechanizm podłączenie do RPi i efekt (w zależności od K): Kp 8 Sterowany dedykowanym układem konwertującym ws. wypełnienia PWM na położenie, Niezbędne 3 linie na każdy serwomechanizm: Zasilanie (z reguły 5V), GND, sygnał sterujący, Niektóre serwomechanizmy o dużym momencie wymagają osobnego zasilania silników. Ki Kd 9 Podłączenie servo do RPi 10 Konwersja PWM->Położenie 0o Ground 0.45/20*100%=2.25% 5V 90 o PWM 1.5/20*100%=7.5% 180o 2.5/20*100%=12.5% 11 12
PWM 0% 0o 0.45/20*100% = 2.25% 50% 90o 1.5/20*100% = 7.5% 100% 180o 2.5/20*100% = 12.5% 13 14 Magistrala SPI Szeregowa magistrala służąca do komunikacji między elementami układu, Linie: SCK Zegar MISO Master In, Slave Out MOSI Master Out, Slave In /Select Magistrala SPI Wiele urządzeń wiele linii /SELECT. /SELECT Active LOW (urządzenie jest wybrane gdy stan niski) Zaproponowana przez firmę Philips, zaadaptowana do przetworników pomiarowych, pamięci, a nawet programowania mikrokontrolerów (AVR!) 15 SPI vs I2C 16 Wiele urządzeń SPI SPI: Dwie linie dla dwóch kierunków I2C: Jedna linia dwukierunkowa. SPI: Wybór układu kolejnymi liniami adresów I2C: wybór układu przez jego zdres, inne układy ignorują komunikat. I2C: Slave może na jakiś czas być urządzeniem Master, jeżeli nic temu nie przeszkadza, SPI: Jedno urządzenie Master. I2C: Urządzenie slave może spowolnić komunikację. SPI: Zegar jest zawsze nadawany przez urządzenie Master. 17 18
Konfiguracja CPOL i CPHA Przykład 19 20 Przykładowe podłączenie MCP3008 - Komunikacja Przetwornik Analogowo-cyfrowy (ADC) MCP3008 SS SCK MOSI MISO 21 22 21 (2) #include <iostream> #include <stdint.h> uint8_t mode = SPI_MODE_0; uint8_t bpw = 8; // bits per word uint32_t speed = 500000; // some code here... int main() { // some code here... uint8_t int handle = -1; bool open() { handle = ::open( "/dev/spidev0.0", O_RDWR ); 3 ]; 0 ] = 1; 1 ] = ( differential? 0 : ( 1 << 7 ) ) ( channel << 4 ); 2 ] = 0; if( handle < 0 ) return false; if( ::ioctl( handle, SPI_IOC_WR_MODE, &mode ) < 0 ::ioctl( handle, SPI_IOC_RD_MODE, &mode ) < 0 ::ioctl( handle, SPI_IOC_WR_BITS_PER_WORD, &bpw ) < 0 ::ioctl( handle, SPI_IOC_RD_BITS_PER_WORD, &bpw ) < 0 ::ioctl( handle, SPI_IOC_WR_MAX_SPEED_HZ, &speed ) < 0 ::ioctl( handle, SPI_IOC_RD_MAX_SPEED_HZ, &speed ) < 0 ) { ::close( handle ); return false; return true; if( transfer( buffer, 3 ) ) { uint16_t hi = ( 1 ] << 8 ) & 0x0300; uint16_t lo = ( 2 ] << 0 ) & 0x00FF; uint16_t value = hi lo; cout << 100.0 * ( (double)value / 1023.0 ); return 0; 23 24
(3) bool transfer( uint8_t *data, uint16_t length ) { struct ::spi_ioc_transfer pack; pack.tx_buf = (unsigned long)data; // transmit from "data" pack.tx_nbits = 8; pack.rx_buf = (unsigned long)data; // receive into "data" pack.rx_nbits = 8; pack.len = length; pack.delay_usecs = 0; pack.speed_hz = speed; // 500000 pack.bits_per_word = bpw; // 8 pack.cs_change = 0; // 0 or 1 for RPi // data transmission if( ::ioctl( handle, SPI_IOC_MESSAGE( 1 ), &pack ) < 0 ) return false; return true; 25