Skocz do zawartości

GPS powoduje regularne drżenie/trzęsienie się serwomechanizmów.


Pomocna odpowiedź

Napisano

Mam poważny problem w swoim projekcie na inżynierkę, chcę mieć zarówno Pan/Tilta jak i moduł GPS, dziś dostałem obydwie rzeczy.

Problem polega na tym, że no GPS komunikuje się przez UART i jeżeli podłączę do dowolnego PINU ustalonego w kodzie jako "RX" to w momencie podłączenia serwomechanizmów do pinów z PWM, czyli np. 9 i 10 po wgraniu programu zaczynają się regularne, powtarzalne wstrząsy dwoma serwomechanizmami z Pan/Tilta o około 45 stopni (dół - góra, dół - góra, a drugie serwo lewo - prawo, lewo - prawo).

Jak temu zaradzić i w ogóle jakim cudem coś takiego ma miejsce, jak TX z GPS (do Arduino podłączony jako RX) ma wpływ na wszystkie porty PWM (wszystkie sprawdzałem 3,6,7,9,10,11) na każdym jednym jest to samo. Tak samo podłączałem z GPS'a do Arduino RX'a na każdym innym porcie i zawsze jest tak, że po podłączeniu do dowolnego portu PWM serwomechanizmi mają oscylacje.

Jak sobie z tym poradzić? Jak bym chciał postawić moduł GPS na drugim Arduino to bym musiał mieć drugi moduł Bluetooth, więc to raczej beznadziejny pomysł. Mieliście kiedyś taki dziwaczny problem?

To kod w moim projekcie jest dużo bardziej rozbudowany, ale w tym prostym kodzie też się tak dzieje:

#include <SoftwareSerial.h>


#include <TinyGPS++.h>
// The TinyGPS++ object
TinyGPSPlus gps;
SoftwareSerial GPS(2, 3); // RX, TX

#include <Servo.h>
Servo panServo;      
Servo tiltServo; 
int servoPanPosition = 1;
int servoTiltPosition = 1;
int servoPanPin = 10;
int servoTiltPin = 9;

int BluetoothData;


void forwardPan(){
  servoPanPosition = constrain((servoPanPosition + 179), 1, 180);
  panServo.write(servoPanPosition);

 }

void forwardTilt(){
  servoTiltPosition = constrain((servoTiltPosition + 179), 1, 180);
    tiltServo.write(servoTiltPosition);   
}

void reversePan(){
    servoPanPosition = constrain((servoPanPosition - 179), 1, 180);
    panServo.write(servoPanPosition);

}

void reverseTilt(){
   servoTiltPosition = constrain((servoTiltPosition - 179), 1, 180);
    tiltServo.write(servoTiltPosition);
}

void setup()  
{
 Serial.begin(9600);

 while (!Serial) { }

 GPS.begin(9600);

 pinMode(servoPanPin, OUTPUT);
 pinMode(servoTiltPin, OUTPUT);
 panServo.attach(servoPanPin);
 tiltServo.attach(servoTiltPin);
}

void loop()
{

if(GPS.available())  // If the bluetooth sent any characters
{
BluetoothData = (int)GPS.read();
 if (BluetoothData == '0')
 {
   forwardPan();
 }
 if (BluetoothData == '1')
 {
   reversePan();
 }
 if (BluetoothData == '2')
 {
   forwardTilt();
 }
 if (BluetoothData == '3')
 {
   reverseTilt();
 }
}

   if(Serial.available())
   {
   GPS.write(Serial.read());
   }

}

U mnie na Arduinowym serialu jest GPS, a na tych portach 2,3 Bluetooth, bo jak było odwrotniej, to były jeszcze większe oscylacje.

To to jest GPS czy bluetooth w końcu?

I jak to masz wszystko połączone? Jak zasilasz serwa? Jakie to serwa?

Jest GPS i Bluetooth GPS ma RX PIN 0 TX PIN 1 Bluetooth RX PIN 2 TX PIN 3, po prostu GPS jest jako główny Serial, a nie Software Serial, ponieważ gdy było na odwrót oscylacje serwomechanizmów, były jeszcze większe.

Serwa zasilam wprost z Arduino (a Arduino jest podłączone do laptopa) 5V podobnie moduł GPS też 5V. Dodam, że gdy wyjmuję z Arduino RX od GPS ten z pinu 0 to oscylacji nie ma, więc to raczej od GPS'u.

To są te serwa kupiłem razem z Pan/Tiltem -> https://botland.com.pl/chwytaki-uchwyty-gimbale/2547-uchwyt-do-serw-micro-pantilt-serwa-dagu.html

No to masz zadanie: na stronie botlandu masz podany pobór prądu pojedynczego serwa.

Na stronie arduino.cc masz podane ile pradu możesz pobrać na raz z płytki Arduino.

Porównaj sobie te dwie wartości i napisz do jakich wniosków doszedłeś.

No to masz zadanie: na stronie botlandu masz podany pobór prądu pojedynczego serwa.

Na stronie arduino.cc masz podane ile pradu możesz pobrać na raz z płytki Arduino.

Porównaj sobie te dwie wartości i napisz do jakich wniosków doszedłeś.

Zaraz policzę, ale co ma to ile prądu może serwo pobrać do tego, że się trzęsie w trakcie transmisji przez UART od GPS'u, przecież one powinno wtedy stać w miejscu i nic nie robić (no chyba, że walczy z grawitacją 😃). I jak mam je zasilić, bezpośrednio z baterii 9V raczej nie mogę, bo one są na 5V 😃

[ Dodano: 28-09-2017, 23:59 ]

No to masz zadanie: na stronie botlandu masz podany pobór prądu pojedynczego serwa.

Na stronie arduino.cc masz podane ile pradu możesz pobrać na raz z płytki Arduino.

Porównaj sobie te dwie wartości i napisz do jakich wniosków doszedłeś.

Tak, więc jedna płytka Arduino może zapewnić maks pobór prądu do 500mA, a na stronie Botlandu jest

Parametry serwomechanizmów

Napięcie zasilania: 4,8 V - 6 V

Pobór prądu: do 500 mA

Więc jeśli to jest dla jednego serwa to by trzeba zapewnić 1000mA.

Poprawka, przed chwilą odłączyłem te jedno serwo, a drugie zostawiłem i jednak i tak trzęsie 🙁 A czym je najlepiej zasilić, z baterii 9V da się, zrobić dzielnik napięcia i tyle?

Jak ostatnio sprawdzałem, to na 5V arduino mogło dać maksymalnie 200mA. Zasilanie serw i innych silników z baterii alkalicznych (a już szczególnie tych wyjątkowo słabych 9V) mija się z celem, bo tylko bardzo szybko rozładujesz/uszkodzisz baterie takimi prądami.

Najlepiej gdybyś się zaopatrzył w 4-5 baterii niklowych (NiMH, NiMg, NiCd, etc.) — tak zwane "ładowalne" paluszki, używane na przykład do aparatów fotograficznych. Każdy ma napięcie 1.2V, więc dostajesz dokładnie 4.8-6V tak jak te serwa chcą. Możesz oczywiście także zaopatrzyć się w baterie LiPo i przetwornicę napięcia, użyć gotowego "powerbanku" USB, albo, jeśli to nie jest urządzenie mobilne, zasilać je z ładowarki USB. W każdym z tych przypadków zasilanie serw (czerwony kabelek) nie powinno przechodzić przez płytkę Arduino.

Co robi serwo, kiedy jego napięcie zasilania zmienia się w zasadzie losowo (bo spada gdy tylko serwo próbuje pobrać większy prąd) trudno przewidzieć — bardzo zależy to od jego wewnętrznej elektroniki. Raczej nie będzie stać w miejscu.

Oczywiście nie mam pewności, że to właśnie zasilanie jest źródłem twojego problemu — zwróciłem na nie uwagę, bo to bardzo częsty błąd. Ale równie dobrze mogą być złe połączenia, dlatego też poprosiłem cię o podanie ich — czego na razie nie zrobiłeś.

Jak ostatnio sprawdzałem, to na 5V arduino mogło dać maksymalnie 200mA. Zasilanie serw i innych silników z baterii alkalicznych (a już szczególnie tych wyjątkowo słabych 9V) mija się z celem, bo tylko bardzo szybko rozładujesz/uszkodzisz baterie takimi prądami.

Najlepiej gdybyś się zaopatrzył w 4-5 baterii niklowych (NiMH, NiMg, NiCd, etc.) — tak zwane "ładowalne" paluszki, używane na przykład do aparatów fotograficznych. Każdy ma napięcie 1.2V, więc dostajesz dokładnie 4.8-6V tak jak te serwa chcą. Możesz oczywiście także zaopatrzyć się w baterie LiPo i przetwornicę napięcia, użyć gotowego "powerbanku" USB, albo, jeśli to nie jest urządzenie mobilne, zasilać je z ładowarki USB. W każdym z tych przypadków zasilanie serw (czerwony kabelek) nie powinno przechodzić przez płytkę Arduino.

Co robi serwo, kiedy jego napięcie zasilania zmienia się w zasadzie losowo (bo spada gdy tylko serwo próbuje pobrać większy prąd) trudno przewidzieć — bardzo zależy to od jego wewnętrznej elektroniki. Raczej nie będzie stać w miejscu.

Oczywiście nie mam pewności, że to właśnie zasilanie jest źródłem twojego problemu — zwróciłem na nie uwagę, bo to bardzo częsty błąd. Ale równie dobrze mogą być złe połączenia, dlatego też poprosiłem cię o podanie ich — czego na razie nie zrobiłeś.

Zaraz podam, albo zrobię rysunek. Ogólnie zaraz, bo mam taki moduł do zasilania płytki stykowej i zasilacz, ale on ma wydajność na poziomie właśnie 500 mA, więc podłącze go, zasilę jedno serwo z płytki stykowej, a nie wprost z Arduino, drugie odłączę i zobaczę czy nie będzie trzęsło, a później wstawię schemat połączeń.

EasyPeasy_, czy przypadkiem biblioteki z których korzystasz, czyli SoftwareSerial oraz Servo nie pracują na przerwaniach? Zgaduję, chociaż kodu nie sprawdzałem - Serwo działa na przerwaniach, bo atmega nie ma odpowiedniej liczby sprzętowych PWM. Do tego SoftwareSerial wyłącza przerwania podczas transmisji, żeby uzyskać poprawne czasy... I masz przepis na drgające serwa.

EasyPeasy_, czy przypadkiem biblioteki z których korzystasz, czyli SoftwareSerial oraz Servo nie pracują na przerwaniach? Zgaduję, chociaż kodu nie sprawdzałem - Serwo działa na przerwaniach, bo atmega nie ma odpowiedniej liczby sprzętowych PWM. Do tego SoftwareSerial wyłącza przerwania podczas transmisji, żeby uzyskać poprawne czasy... I masz przepis na drgające serwa.

Więc nie da się obsłużyć w jednym Arduino jednocześnie GPS'a oraz serwa? Co za sztynks, co ja teraz zrobię 🙁

Ja ogólnie GPS' mam podłączonego jako normalny Serial, a Bluetooth korzysta z Software Serial, ale trzęsienie się i tak występuje z każdym wywołaniem Read'a z GPS'a, gdy daję delay(xxx) się zmniejsza, ale nadal występuje.

Tak wygląda u mnie schemat połączeń:

Da się, ale albo na sprzętowym serialu, albo sprzętowym PWM-em.

Możesz też użyć sterownika serw, na przykład jakiegoś opartego na PCA9685 — u mnie się sprawdzają.

Ale ja mam podłączonego GPS'a do sprzętowego serialu (jak na rysunku post wyżej) i trzęsienia występują, a sprzętowym PWM'em, czyli chodzi Tobie o analog.write() ??

Te sterowniki serwa korzystają z cyfrowych pinów, czy jak, zaraz obczaję tego co podałeś.

@EDIT

Widzę, że korzysta z I2C, a jutro przyjdzie mi czujnik 9DOF, który też jest na I2C, więc da się w jednym Arduino obsłużyć 2 x I2C ?

Da się, ale albo na sprzętowym serialu, albo sprzętowym PWM-em.

Możesz też użyć sterownika serw, na przykład jakiegoś opartego na PCA9685 — u mnie się sprawdzają.

Ale ja mam podłączonego GPS'a do sprzętowego serialu (jak na rysunku post wyżej) i trzęsienia występują,

Kod, który wkleiłeś, ma software-owego UARTA. To w końcu o czym my rozmawiamy?

a sprzętowym PWM'em, czyli chodzi Tobie o analog.write() ??

Nie, chodzi mi o PWM za pomocą timerów sprzętowych. Tak przy okazji, polska interpunkcja nie przwiduje podwójnych znaków zapytania i nie będą się one tutaj obracać.

Te sterowniki serwa korzystają z cyfrowych pinów, czy jak, zaraz obczaję tego co podałeś.

@EDIT

Widzę, że korzysta z I2C, a jutro przyjdzie mi czujnik 9DOF, który też jest na I2C, więc da się w jednym Arduino obsłużyć 2 x I2C ?

I²C to magistrala — może obsłużyć ponad setkę urządzeń na raz, pod warunkiem, że mają różne adresy. W przypadku PCF9685 adres ustawiasz pięcioma zworkami, więc masz 64 możliwości.

  • 2 tygodnie później...
Da się, ale albo na sprzętowym serialu, albo sprzętowym PWM-em.

Możesz też użyć sterownika serw, na przykład jakiegoś opartego na PCA9685 — u mnie się sprawdzają.

Ale ja mam podłączonego GPS'a do sprzętowego serialu (jak na rysunku post wyżej) i trzęsienia występują,

Kod, który wkleiłeś, ma software-owego UARTA. To w końcu o czym my rozmawiamy?

O tym, że GPS jest podłączony do sprzętowego/Arduinowego UARTA, a Bluetooth do jak to nazwałeś software-owego UARTA.

EasyPeasy_, problemem nie jest komunikacja przez uart, ale biblioteka Servo. Wykorzystuje ona przerwania, ale PWM nie jest sprzętowy tylko programowy - w oparciu o przerwania właśnie.

PWM sprzętowy jest niezależny od programu, razu uruchomiony po prostu działa i generuje sygnał o określonym okresie i wypełnieniu całkiem niezależnie od reszty kodu. Czasem nawet zatrzymanie programu przez debugger nie wstrzymuje PWM-a, to po porstu kawałek krzemu który generuje syngał wyjściowy.

Natomiast programowa implementacja bazuje na przerwaniach. Oznacza to, że jakiekolwiek zakłócenia, czy opóźnienia w obsłudze przerwań zmieniają sygnał wyjściowy. Moduł programowego UART-a wyłącza przerwania podczas transmisji - inaczej przerwania miałyby wpływ na czasy, a one są krytyczne w komunikacji asynchronicznej. Ale wyłączenie przerwań sprawia, że sygnał wysyłany przez Servo jest inny niż zaprogramowany. Na to reaguje serwomechanizm, w pełni poprawnie jakby nie patrzeć.

Problem wynika więc z użycia dwóch niezgodnych ze sobą bibliotek. Albo Servo albo SoftwareSerial, ale nie obie na raz 🙁

EasyPeasy_, problemem nie jest komunikacja przez uart, ale biblioteka Servo. Wykorzystuje ona przerwania, ale PWM nie jest sprzętowy tylko programowy - w oparciu o przerwania właśnie.

PWM sprzętowy jest niezależny od programu, razu uruchomiony po prostu działa i generuje sygnał o określonym okresie i wypełnieniu całkiem niezależnie od reszty kodu. Czasem nawet zatrzymanie programu przez debugger nie wstrzymuje PWM-a, to po porstu kawałek krzemu który generuje syngał wyjściowy.

Natomiast programowa implementacja bazuje na przerwaniach. Oznacza to, że jakiekolwiek zakłócenia, czy opóźnienia w obsłudze przerwań zmieniają sygnał wyjściowy. Moduł programowego UART-a wyłącza przerwania podczas transmisji - inaczej przerwania miałyby wpływ na czasy, a one są krytyczne w komunikacji asynchronicznej. Ale wyłączenie przerwań sprawia, że sygnał wysyłany przez Servo jest inny niż zaprogramowany. Na to reaguje serwomechanizm, w pełni poprawnie jakby nie patrzeć.

Problem wynika więc z użycia dwóch niezgodnych ze sobą bibliotek. Albo Servo albo SoftwareSerial, ale nie obie na raz 🙁

Masz rację, dlatego napisałem własną bibliotekę w oparciu o odczyty czasów włączenia i wyłączenia pinów z Servo.h -> w stylu "

if(a<181){
   panServo.attach(9);
   panServo.write(a);
   Serial.print(a);
   Serial.print(":");
   Serial.println(panServo.readMicroseconds());
   a++;
   }

" tj. printuj mi czasy sygnału ON dla kątów od 0 do 180 stopni

i moja biblioteka później będzie obliczała czasy on i of dla tego typu funkcji -> "

 a=200;    
   digitalWrite(9,HIGH);
   delayMicroseconds(a);
   digitalWrite(9,LOW);
   delayMicroseconds(20000-a); 

"

gdzie 'a' jest odczytanym czasem 'a' dla danego kąta obrotu serwa, a dlaczego 20000 microsecond, bo gdzieś wyczytałem, że taki jest okres PWM'a dla tego serwa.

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...