Spisu treści:

Używanie Arduino Uno do pozycjonowania XYZ ramienia robota 6 DOF: 4 kroki
Używanie Arduino Uno do pozycjonowania XYZ ramienia robota 6 DOF: 4 kroki

Wideo: Używanie Arduino Uno do pozycjonowania XYZ ramienia robota 6 DOF: 4 kroki

Wideo: Używanie Arduino Uno do pozycjonowania XYZ ramienia robota 6 DOF: 4 kroki
Wideo: Serwonapęd ELP Leadshine - podłączenie, uruchomienie, sterowanie, ustawienia 2024, Lipiec
Anonim
Image
Image

Ten projekt polega na zaimplementowaniu krótkiego i stosunkowo łatwego szkicu Arduino, aby zapewnić pozycjonowanie odwrotnej kinematyki XYZ. Zbudowałem ramię robota z 6 serwomechanizmami, ale jeśli chodzi o znalezienie oprogramowania do jego uruchomienia, nie było tam zbyt wiele, z wyjątkiem niestandardowych programów działających na niestandardowych osłonach serwo, takich jak SSC-32 (U) lub innych programów i aplikacji, które były skomplikowane w instalacji i komunikacji z ramieniem. Potem znalazłem najdoskonalszą "Robotic Arm Inverse Kinematics on Arduino" Olega Mazurova, w której zaimplementował kinematykę odwrotną w prostym szkicu Arduino.

Dokonałem dwóch modyfikacji, aby dostosować jego kod:

1. Użyłem biblioteki VarSpeedServo zamiast jego niestandardowej biblioteki osłon serw, ponieważ mogłem wtedy kontrolować prędkość serw i nie musiałbym używać osłony serw, której używał. Wszystkim, którzy rozważają uruchomienie podanego tutaj kodu, zalecam korzystanie z tej biblioteki VarSpeedServo, a nie z biblioteki servo.h, aby spowolnić ruchy ramienia robota podczas programowania lub może się okazać, że ramię nieoczekiwanie cię wepchnie twarz lub gorzej, ponieważ będzie się poruszał z pełną prędkością serwa.

2. Używam prostej osłony czujnika / serw do podłączenia serw do Arduino Uno, ale nie wymaga to specjalnej biblioteki serwo, ponieważ wykorzystuje tylko piny Arduino. Kosztuje tylko kilka dolców, ale nie jest wymagany. Zapewnia to ładne, czyste połączenie serw z Arduino. I już nigdy nie wrócę do okablowania serw do Arduino Uno. Jeśli używasz tego czujnika/osłony serwomechanizmu, musisz dokonać jednej drobnej modyfikacji, którą opiszę poniżej.

Kod działa świetnie i pozwala na obsługę ramienia za pomocą jednej funkcji, w której podajesz parametry x, y, x i prędkości. Na przykład:

set_arm (0, 240, 100, 0, 20); // parametry to (x, y, z, kąt chwytaka, prędkość serwa)

opóźnienie(3000); // opóźnienie jest wymagane, aby czas uzbrojony mógł przenieść się do tej lokalizacji

Prościej się nie da. Szkic dołączę poniżej.

Film Olega jest tutaj: Sterowanie ramieniem robota za pomocą Arduino i myszy USB

Oryginalny program, opisy i zasoby Olega: Kinematyka odwrotna Olega dla Arduino Uno

Nie rozumiem całej matematyki stojącej za rutyną, ale fajną rzeczą jest to, że nie musisz używać kodu. Mam nadzieję, że spróbujesz.

Krok 1: Modyfikacje sprzętu

Modyfikacje sprzętowe
Modyfikacje sprzętowe

1. Jedyną rzeczą, która jest wymagana, jest to, aby twoje serwo obracało się w oczekiwanych kierunkach, co może wymagać od ciebie fizycznego odwrócenia mocowania serwomechanizmów. Przejdź do tej strony, aby zobaczyć oczekiwany kierunek serw dla serw podstawy, ramienia, łokcia i nadgarstka:

2. Jeśli używasz osłony czujnika, której używam, musisz zrobić jedną rzecz: zgiąć pin łączący 5v z osłoną z Arduino Uno tak, aby nie łączył się z płytką Uno. Chcesz użyć zewnętrznego napięcia na tarczy do zasilania tylko serw, a nie Arduino Uno lub może zniszczyć Uno, wiem, że spaliłem dwie płyty Uno, gdy moje zewnętrzne napięcie wynosiło 6 woltów, a nie 5. To pozwala ci aby użyć napięcia wyższego niż 5 V do zasilania serw, ale jeśli napięcie zewnętrzne jest wyższe niż 5 V, nie podłączaj żadnych czujników 5 V do tarczy, ponieważ zostaną usmażone.

Krok 2: Pobierz bibliotekę VarSpeedServo

Musisz użyć tej biblioteki, która zastępuje standardową bibliotekę serwo arduino, ponieważ pozwala na przekazanie prędkości serwomechanizmu do instrukcji zapisu servo. Biblioteka znajduje się tutaj:

Biblioteka VarSpeedServo

Możesz po prostu użyć przycisku zip, pobrać plik zip, a następnie zainstalować go za pomocą Arduino IDE. Po zainstalowaniu polecenie w twoim programie będzie wyglądać tak: servo.write(100, 20);

Pierwszy parametr to kąt, a drugi to prędkość serwomechanizmu od 0 do 255 (pełna prędkość).

Krok 3: Uruchom ten szkic

Oto program konkursowy. Musisz zmodyfikować kilka parametrów wymiarów ramienia robota:

1. Długości BASE_HGT, HUMERUS, ULNA, GRIPPER w milimetrach.

2. Wprowadź numery pinów serwa

3. Wprowadź min i max serwa w załączonych oświadczeniach.

4. Następnie wypróbuj proste polecenie set_arm(), a następnie funkcje zero_x(), line() i circle() do testowania. Upewnij się, że prędkość serwomechanizmu jest niska przy pierwszym uruchomieniu tych funkcji, aby zapobiec uszkodzeniu ramienia i własnego ramienia.

Powodzenia.

#include VarSpeedServo.h

/* Sterowanie serwo dla ramienia AL5D */

/* Wymiary ramienia (mm) */

#define BASE_HGT 90 //wysokość bazowa

#define HUMERUS 100 //kość od ramienia do łokcia

#define ULNA 135 //kość od łokcia do nadgarstka

#define GRIPPER 200 //chwytak (wraz z mechanizmem obracania nadgarstka o dużej wytrzymałości) długość"

#define ftl(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) //konwersja float na long

/* Nazwy/numery serwo *

* Serwo bazowe HS-485HB */

#define BAS_SERVO 4

/* Serwo naramienne HS-5745-MG */

#definiuj SHL_SERVO 5

/* Serwo łokciowe HS-5745-MG */

#define ELB_SERVO 6

/* Serwomechanizm nadgarstkowy HS-645MG */

#define WRI_SERVO 7

/* Serwo obrotu nadgarstka HS-485HB */

#define WRO_SERVO 8

/* Serwo chwytaka HS-422 */

#define GRI_SERVO 9

/* obliczenia wstępne */

float hum_sq = HUMERUS*HUMERUS;

float uln_sq = ULNA*ULNA;

int servoSPeed = 10;

//ServoShield serwa; //Obiekt ServoShield

VarSpeedServo serwo1, serwo2, serwo3, serwo4, serwo5, serwo6;

int licznik pętli=0;

int pulseWidth = 6,6;

int microsecondsToDegrees;

pusta konfiguracja()

{

servo1.attach(BAS_SERVO, 544, 2400);

servo2.attach(SHL_SERVO, 544, 2400);

servo3.attach(ELB_SERVO, 544, 2400);

servo4.attach(WRI_SERVO, 544, 2400);

servo5.attach(WRO_SERVO, 544, 2400);

servo6.attach(GRI_SERVO, 544, 2400);

opóźnienie (5500);

//serwo.start(); //Uruchom osłonę serwa

servo_park();

opóźnienie (4000);

Serial.początek(9600);

Serial.println("Start");

}

pusta pętla()

{

Licznik pętli +=1;

//set_arm(-300, 0, 100, 0, 10); //

//opóźnienie(7000);

//zero_x();

//linia();

//okrąg();

opóźnienie (4000);

if (licznik pętli > 1) {

servo_park();

//set_arm (0, 0, 0, 0, 10); // park

opóźnienie(5000);

wyjście(0); }//pause program - naciśnij reset, aby kontynuować

//wyjdź(0);

}

/* procedura pozycjonowania ramienia z wykorzystaniem kinematyki odwrotnej */

/* z to wysokość, y to odległość od środka podstawy na zewnątrz, x to bok do boku. y, z mogą być tylko dodatnie */

//unieważnij set_arm(uint16_t x, uint16_t y, uint16_t z, uint16_t grip_angle)

void set_arm(float x, float y, float z, float grip_angle_d, int servoSpeed)

{

float grip_angle_r = radiany(grip_angle_d); //kąt uchwytu w radianach do wykorzystania w obliczeniach

/* Kąt bazowy i odległość promieniowa od współrzędnych x, y */

float bas_angle_r = atan2(x, y);

float rdist = sqrt((x * x) + (y * y));

/* rdist jest współrzędną y ramienia */

y = rdist;

/* Przesunięcia uchwytu obliczone na podstawie kąta uchwytu */

float grip_off_z = (sin(grip_angle_r)) * CHWYTAK;

float grip_off_y = (cos(grip_angle_r)) * CHWYTAK;

/* Pozycja nadgarstka */

float wrist_z = (z - grip_off_z) - BASE_HGT;

float nadgarstek_y = y - grip_off_y;

/* Odległość od ramienia do nadgarstka (AKA sw) */

float s_w = (nadgarstek_z * nadgarstek_z) + (nadgarstek_y * nadgarstek_y);

float s_w_sqrt = sqrt(s_w);

/* kąt s_w względem podłoża */

float a1 = atan2(nadgarstek_z, nadgarstek_y);

/* kąt s_w do kości ramiennej */

float a2 = acos(((hum_sq - uln_sq) + s_w) / (2 * HUMERUS * s_w_sqrt));

/* kąt barku */

pływak shl_angle_r = a1 + a2;

float shl_angle_d = stopnie(shl_angle_r);

/* kąt łokcia */

float elb_angle_r = acos((hum_sq + uln_sq - s_w) / (2 * HUMERUS * ULNA));

float elb_angle_d = stopnie(elb_angle_r);

float elb_angle_dn = -(180,0 - elb_angle_d);

/* kąt nadgarstka */

float wri_angle_d = (grip_angle_d - elb_angle_dn) - shl_angle_d;

/* Impulsy serwo */

float bas_servopulse = 1500.0 - ((stopnie(bas_angle_r)) * pulseWidth);

float shl_servopulse = 1500,0 + ((shl_angle_d - 90,0) * pulseWidth);

float elb_servopulse = 1500,0 - ((elb_angle_d - 90,0) * pulseWidth);

//float wri_servopulse = 1500 + (wri_angle_d * pulseWidth);

//float wri_servopulse = 1500 + (wri_angle_d * pulseWidth);

float wri_servopulse = 1500 - (wri_angle_d * pulseWidth);// zaktualizowane 2018/2/11 przez jimrd - zmieniłem plus na minus - nie jestem pewien, jak ten kod działał dla nikogo wcześniej. Możliwe, że serwomechanizm łokciowy został zamontowany z 0 stopni skierowany w dół, a nie w górę.

/* Ustaw serwa */

//servos.setposition(BAS_SERVO, ftl(bas_servopulse));

microsecondsToDegrees = map(ftl(bas_servopulse), 544, 2400, 0, 180);

servo1.write(mikrosekundy do stopni, servoSpeed); // użyj tej funkcji, aby ustawić prędkość serwa //

//servos.setposition(SHL_SERVO, ftl(shl_servopulse));

microsecondsToDegrees = map(ftl(shl_servopulse), 544, 2400, 0, 180);

servo2.write(mikrosekundy do stopni, servoSpeed);

//servos.setposition(ELB_SERVO, ftl(elb_servopulse));

microsecondsToDegrees = map(ftl(elb_servopulse), 544, 2400, 0, 180);

servo3.write(mikrosekundy do stopni, servoSpeed);

//servos.setposition(WRI_SERVO, ftl(wri_servopulse));

microsecondsToDegrees = map(ftl(wri_servopulse), 544, 2400, 0, 180);

servo4.write(mikrosekundy do stopni, servoSpeed);

}

/* przestaw serwa do pozycji parkowania */

nieważne servo_park()

{

//servos.setposition(BAS_SERVO, 1500);

servo1.write(90, 10);

//servos.setposition(SHL_SERVO, 2100);

servo2.write(90, 10);

//servos.setposition(ELB_SERVO, 2100);

servo3.write(90, 10);

//servos.setposition(WRI_SERVO, 1800);

servo4.write(90, 10);

//servos.setposition(WRO_SERVO, 600);

servo5.write(90, 10);

//servos.setposition(GRI_SERVO, 900);

servo6.write(80, 10);

powrót;

}

nieważne zero_x()

{

for(podwójna oś y = 250,0; oś y < 400,0; oś y += 1) {

Serial.print("yaxis=: ");Serial.println(yaxis);

set_arm(0, oś y, 200.0, 0, 10);

opóźnienie(10);

}

for(podwójna oś y = 400,0; oś y > 250,0; oś y -= 1) {

set_arm(0, oś y, 200.0, 0, 10);

opóźnienie(10);

}

}

/* porusza ramieniem w linii prostej */

pusta linia()

{

for(podwójna oś x = -100,0; oś x < 100,0; oś x += 0,5) {

set_arm(xaxis, 250, 120, 0, 10);

opóźnienie(10);

}

for(zmienna oś x = 100,0; oś x > -100,0; oś x -= 0,5) {

set_arm(xaxis, 250, 120, 0, 10);

opóźnienie(10);

}

}

puste koło()

{

#define PROMIEŃ 50,0

//kąt pływania = 0;

pływak zaxis, yaxis;

for(kąt pływania = 0,0; kąt < 360,0; kąt += 1,0) {

oś y = PROMIEŃ * sin(radiany(kąt)) + 300;

zaxis = PROMIEŃ * cos(radiany(kąt)) + 200;

set_arm(0, oś y, oś z, 0, 50);

opóźnienie(10);

}

}

Krok 4: Fakty, problemy i tym podobne…

Fakty, problemy i tym podobne…
Fakty, problemy i tym podobne…

1. Kiedy uruchamiam podprogram circle(), mój robot porusza się bardziej po eliptyce niż po okręgu. Myślę, że dzieje się tak dlatego, że moje serwa nie są skalibrowane. Przetestowałem jeden z nich i 1500 mikrosekund to nie to samo co 90 stopni. Popracuję nad tym, aby spróbować znaleźć rozwiązanie. Nie wierz, że jest coś nie tak z algorytmem, a raczej z moimi ustawieniami. Aktualizacja 2018/2/11 - właśnie odkryłem, że jest to spowodowane błędem w oryginalnym kodzie. Nie rozumiem, jak działał jego program Poprawiony kod za pomocą tego: float wri_servopulse = 1500 - (wri_angle_d * pulseWidth); (oryginalny kod był dodawany)

2. Gdzie mogę znaleźć więcej informacji na temat działania funkcji set_arm(): Strona internetowa Olega Mazurova wyjaśnia wszystko lub zawiera linki do dalszych informacji:

3. Czy jest sprawdzanie warunków brzegowych? Nie. Kiedy moje ramię robota mija nieprawidłową współrzędną xyz, wykonuje ten zabawny rodzaj ruchu łukowego, jak rozciągający się kot. Uważam, że Oleg sprawdza w swoim najnowszym programie, który używa USB do programowania ruchów ramion. Zobacz jego film i link do jego najnowszego kodu.

4. Kod musi zostać oczyszczony i można usunąć kod mikrosekundowy.

Zalecana: