Cześć, dziś pokaże wam jak zrobić Rękę sterowaną bezprzewodowo!
Założenia projektu:
- zdalne sterowanie, nadajnik w formie rękawicy
- naśladowanie ruchów
- gra w kamień, papier, nożyce
- wyświetlanie informacji na wyświetlaczu
Potrzebne elementy (ręka):
-elementy drukowane w 3d;
-5x serwomechanizmy MG996R;
-5x orczyki metalowe okrągły 25T;
-cienka, mocna linka;
-śrubki;
– arduino nano;
-moduł NRF24L01;
-kondensatory elektrolityczny 2x(min.1000uF), kondensator ceramiczny(100nF);
-przełącznik;
-płytka do lutowania;
-goldpiny męskie;
-goldpin żeńskie;
-trochę przewodów;
Potrzebne elementy (nadajnik):
-rękawica (np.ogrodowa);
-5x zgięcia 11,5cm;
-bateria 9v;
-kilka trytytek;
-płytka prototypowa;
-goldpiny żeńskie;
-goldpiny męskie kątowe potrójne;
-5x rezystor 47K;
-przetwornica step-down na 5v;
-arduino nano;
-moduł NRF24L01;
-enkoder;
-wyświetlacz oled (ssd1306 128×64);
-przewody, złącze do bateri 9v, złącze od płyty głównej;
Budowa Nadajnika:
Do rękawicy ogrodowej przy pomocy kilku trytytek przymocowałem 11 centymetrowe czujniki zgięcia. Należy zrobić to w ten sposób, aby zginana była tylko część do tego przeznaczona, w innym przypadku czujnik się uszkodzi. Do wyprowadzeń czujników zgięcia dolutowałem po dwa przewody, kabel ma 10 przewodów i na końcu wtyczkę 5×2 (kabel od kompa chyba);
Płytka z enkoderem i płytka główna oraz bateria 9v, przymocowane są do rękawicy trytytkami. Wyświetlacz trzymają dwa sztywne przewody przylutowane na stałe do płytki.
Płytka lutowałem sam, “na pająka”. Na płytce znajdują się rezystory(47kOhM), moduł komunikacji NRF24L01, przetwornica napięcia obniżająca napięcie baterii (9v na 5v dla Arduino), mózgiem nadajnika jest Arduino Nano. Wyświetlacz wyświetla dość podstawowe funkcję, takie jak:
-naśladowanie (rękawica wysyła informacje do ręki)
-kamień,papier,nożyce (rękawica losuje i szczytuję wartości z rękawicy oraz wysyła gotowe komendy do ręki)
-pokazywanie wybranych na rękawicy ułożeń palców
-informacje o autorze i wersji oprogramowania
Schemat Nadajnika
KOD Nadajnika:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
#include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> //biblioteki do obsługi wyświetlacz #include <Adafruit_SSD1306.h> #include <SPI.h> #include <nRF24L01.h> //biblioteki do obsługi nrf24L01 #include <RF24.h> #define outputA 4 #define outputB 3 //definicja pinów od enkodera #define selectButton 2 #define SCREEN_WIDTH 128 //wysokość i szerokość wyświetlacza #define SCREEN_HEIGHT 64 #define OLED_RESET -1 //linijka potrzebna do działania wyświetlacza Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //definicja wartości wyświetlacza const uint64_t pipe = 0x1CF8361637LL; //kod kanału RF24 radio(9, 10); //tworzymy instancje komunikacji int menu = 1; //strona menu int menu2 = 1; //strona podmenu int counter = 0; int aState; int aLastState; int dane[6]; //przechowuje dane do wysłania int odczyt[5]; int wybor; int wybor_u; int wybor_a; boolean plus = false; boolean minus= false; void setup() { pinMode(outputA,INPUT_PULLUP); pinMode(outputB,INPUT_PULLUP); //ustawienie pinów enkodera jako wejście pinMode(selectButton, INPUT_PULLUP); //podciągnięte do zasilania pinMode(A0, INPUT); pinMode(A1, INPUT); pinMode(A2, INPUT); //ustawienie pinów czujników zgięcia jako pinMode(A3, INPUT); //wejście pinMode(A6, INPUT); Serial.begin (9600); //rozpoczęcie komunikacji szeregowej if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { //sprawdzenie działania wyświetlacz Serial.println(F("SSD1306 problem z inicjacja wyswietlacza")); //jeżeli błąd z inicja- //cją wyświetlacz, wypisz na serial porcie komunikat for(;;); //czekaj ciągle } randomSeed(analogRead(A7)); //ustaw "ziarno" do losowania na nie używany port A0 display.display(); //zainicjuj wyświetlacz display.clearDisplay(); //wyczyść wyświetlacz radio.begin(); //uruchom moduł radio.setDataRate(RF24_2MBPS); //ustaw prędkość transmisji na 2Mb/s radio.setPALevel(RF24_PA_HIGH); //ustaw wzmocnienie modułu radiowego na wysokie radio.openWritingPipe(pipe); //rozpocznij transmisję aLastState = digitalRead(outputA); //odczytaj stan pinu enkodera narysujMenu(); //pokaż menu } void loop() { aState = digitalRead(outputA); //odczytaj stan pinu enkodera if (aState != aLastState){ //jeżeli odczytany stan jest różny od poprzedniego stanu if (digitalRead(outputB) != aState) { plus = true; //plus ustawiamy na 1 } else { minus = true; //minus ustawiamy na 1 } /* Serial.print("Position: "); Serial.print(counter); Serial.print("Last Position: "); Serial.println(aLastState);*/ } aLastState = aState; //poprzedni stan = stan // if (!digitalRead(downButton)){ // menu++; // narysujMenu(); // delay(100); // while (!digitalRead(downButton)); // } if(plus == true){ //jeżeli plus = 1 menu++; //kolejna strona menu narysujMenu(); //pokaż menu na ekranie delay(100); //czekaj 0,1s while(!plus); //czekaj do póki !plus plus=false; //ustaw plus na 0 } /* if(minus == true){ menu--; narysujMenu(); delay(100); while(!minus); minus=false; }*/ if (!digitalRead(selectButton)){ delay(200); display.clearDisplay(); do{ executeAction(); } while(digitalRead(selectButton) == HIGH); narysujMenu(); while (!digitalRead(selectButton)); } display.display(); } void narysujMenu() { display.clearDisplay(); dane[0] = 0; //Jeden, oznacza wybraną stronę. potrzebną odbiornikowi dane[1] = 0; dane[2] = 0; //mapowanie odczytów z pinów dane[3] = 0; //analogowych na ruch serw. dane[4] = 0; dane[5] = 0; radio.write(dane, sizeof(dane)); switch (menu) { case 0: menu = 1; break; case 1: display.display(); display.setTextSize(1); display.setTextSize(1); display.setCursor(8,0); display.setTextColor(1,0); display.print("Wybierz Opcje !"); display.drawLine(0,9,128,9,1); display.display(); display.setTextColor(0,1); display.setCursor(5,10); display.print("Nasladowanie"); display.setTextColor(1,0); display.setCursor(5,20); display.print("Kamien,Papier,Nozyce"); display.setTextColor(1,0); display.setCursor(5,30); display.print("Figury"); display.setTextColor(1,0); display.setCursor(5,40); display.print("informacje"); display.display(); break; case 2: display.display(); display.setTextSize(1); display.setTextSize(1); display.setCursor(8,0); display.setTextColor(1,0); display.print("Wybierz Opcje !"); display.drawLine(0,9,128,9,1); display.display(); display.setTextColor(1,0); display.setCursor(5,10); display.print("Nasladowanie"); display.setTextColor(0,1); display.setCursor(5,20); display.print("Kamien,Papier,Nozyce"); display.setTextColor(1,0); display.setCursor(5,30); display.print("Figury"); display.setTextColor(1,0); display.setCursor(5,40); display.print("informacje"); display.display(); break; case 3: display.display(); display.setTextSize(1); display.setTextSize(1); display.setCursor(8,0); display.setTextColor(1,0); display.print("Wybierz Opcje !"); display.drawLine(0,9,128,9,1); display.display(); display.setTextColor(1,0); display.setCursor(5,10); display.print("Nasladowanie"); display.setTextColor(1,0); display.setCursor(5,20); display.print("Kamien,Papier,Nozyce"); display.setTextColor(0,1); display.setCursor(5,30); display.print("Figury"); display.setTextColor(1,0); display.setCursor(5,40); display.print("informacje"); display.display(); break; case 4: display.display(); display.setTextSize(1); display.setTextSize(1); display.setCursor(8,0); display.setTextColor(1,0); display.print("Wybierz Opcje !"); display.drawLine(0,9,128,9,1); display.display(); display.setTextColor(1,0); display.setCursor(5,10); display.print("Nasladowanie"); display.setTextColor(1,0); display.setCursor(5,20); display.print("Kamien,Papier,Nozyce"); display.setTextColor(1,0); display.setCursor(5,30); display.print("Figury"); display.setTextColor(0,1); display.setCursor(5,40); display.print("informacje"); display.display(); break; case 5: menu = 0; break; } } void executeAction() { switch (menu) { case 1: display.clearDisplay(); action1(); break; case 2: action2(); break; case 3: action3(); break; case 4: action4(); break; } } void action1() { //Odczytanie wartości z pinów analogowych i wpisanie ich do zmiennych dane dane[0] = 1; //Jeden, oznacza wybraną stronę. potrzebną odbiornikowi dane[1] = map(analogRead(A6), 260, 320, 180, 50); dane[2] = map(analogRead(A3), 215, 360, 0, 180); //mapowanie odczytów z pinów dane[3] = map(analogRead(A0), 150, 250, 0, 180); //analogowych na ruch serw. dane[4] = map(analogRead(A1), 215, 345, 180, 0); dane[5] = map(analogRead(A2), 220, 345, 0, 180); //Wyświetlanie menu oraz wysyłanych danych Serial.print(analogRead(A6)); Serial.print(" || "); Serial.print(analogRead(A3)); Serial.print(" || "); Serial.print(analogRead(A0)); Serial.print(" || "); Serial.print(analogRead(A1)); Serial.print(" || "); Serial.println(analogRead(A2)); display.setTextSize(1); display.setCursor(8,0); display.setTextColor(1,0); display.print("Reka cie nasladuje !"); display.drawLine(0,9,128,9,1); display.display(); display.setCursor(0,20); display.print(dane[1]); display.setCursor(30,20); display.print(dane[2]); display.setCursor(55,20); display.print(dane[3]); display.setCursor(80,20); display.print(dane[4]); display.setCursor(105,20); display.print(dane[5]); display.display(); // Wysyłanie zczytanych danych do odbiornika /////////////////////////////////////////// /* if(!radio.begin()){ display.setCursor(0,40); display.print("Problem z modulem"); display.display(); }*/ radio.openWritingPipe(pipe); radio.write(dane, sizeof(dane)); } void action2() { display.clearDisplay(); delay(500); for(int i=3;i>-1;i--){ display.setTextSize(1); display.setCursor(8,0); display.setTextColor(1,0); display.print("Gra za: "); display.setCursor(55,0); display.setTextColor(1,0); display.print(i); display.drawLine(0,9,128,9,1); display.display(); delay(500); } odczyt[0] = 2; //Jeden, oznacza wybraną stronę. potrzebną odbiornikowi odczyt[1] = analogRead(A6); odczyt[2] = analogRead(A3); odczyt[3] = analogRead(A0); odczyt[4] = analogRead(A1); odczyt[5] = analogRead(A2); Serial.print(analogRead(A6)); Serial.print(" || "); Serial.print(analogRead(A3)); Serial.print(" || "); Serial.print(analogRead(A0)); Serial.print(" || "); Serial.print(analogRead(A1)); Serial.print(" || "); Serial.println(analogRead(A2)); if(odczyt[1] > 250 && odczyt[2] > 250 && odczyt[3] > 200 && odczyt[4] > 250 && odczyt[5] > 250){ //odczyt palców, wybrano KAMIEŃ Serial.println("kamien_renka"); wybor_u = 1; //przypisanie 1 do zmiennej wybór urzytkownika } else if(odczyt[1] < 250 && odczyt[2] < 250 && odczyt[3] < 200 && odczyt[4] < 250 && odczyt[5] < 250){//odczyt palców, wybrano PAPIER Serial.println("papier_renka"); wybor_u = 2; //przypisanie 2 do zmiennej wybór urzytkownika } else if(odczyt[1] > 250 && odczyt[2] < 250 && odczyt[3] < 200 && odczyt[4] > 250 && odczyt[5] > 250){//odczyt palców, wybrano NOŻYCE Serial.println("nozycze_renka"); wybor_u = 3; //przypisanie 3 do zmiennej wybór urzytkownika } /////////////////////////////////////////////////////////////////////////////////////////////////////// // display.clearDisplay(); display.setCursor(0,15); display.setTextColor(1,0); display.setTextSize(1); display.print("Ty:"); display.display(); switch(wybor_u){ case 1: display.setCursor(70,15); display.setTextColor(1,0); display.setTextSize(1); display.print(" Kamien"); display.display(); break; case 2: display.setCursor(70,15); display.setTextColor(1,0); display.setTextSize(1); display.print(" Papier"); display.display(); break; case 3: display.setCursor(70,15); display.setTextColor(1,0); display.setTextSize(1); display.print(" Nozyce"); display.display(); break; default: display.setCursor(70,15); display.setTextColor(1,0); display.setTextSize(1); display.print(" Zly Gest"); display.display(); break; } //////////////////////////////// display.setCursor(0,40); display.setTextColor(1,0); display.setTextSize(1); display.print("Automat:"); display.display(); int wybor_a = random(1,4); switch(wybor_a){ case 1: display.setCursor(70,40); display.setTextColor(1,0); display.setTextSize(1); display.print(" Kamien"); display.display(); break; case 2: display.setCursor(70,40); display.setTextColor(1,0); display.setTextSize(1); display.print(" Nozyce"); display.display(); break; case 3: display.setCursor(70,40); display.setTextColor(1,0); display.setTextSize(1); display.print("Papier"); display.display(); break; default: display.setCursor(70,40); display.setTextColor(1,0); display.setTextSize(1); display.print(" Zly Gest"); display.display(); break; } delay(5); dane[0] = 2; dane[1] = wybor_u; dane[2] = wybor_a; dane[3] = 0; dane[4] = 0; dane[5] = 0; radio.openWritingPipe(pipe); radio.write(dane, sizeof(dane)); delay(2500); display.display(); } void action3() { display.setTextSize(1); display.setCursor(8,0); display.setTextColor(1,0); display.print("Wybierz Figure"); display.drawLine(0,9,128,9,1); display.display(); aState = digitalRead(outputA); if (aState != aLastState){ if (digitalRead(outputB) != aState) { if(menu2 == 4){ menu2 = 1; } else { menu2++; } } } aLastState = aState; switch(menu2){ case 1: display.setCursor(15,20); display.setTextColor(0,1); display.setTextSize(2); display.print(" Kamien! "); display.display(); dane[0] = 3; //Jeden, oznacza wybraną stronę. potrzebną odbiornikowi dane[1] = 0; dane[2] = 0; //mapowanie odczytów z pinów dane[3] = 0; //analogowych na ruch serw. dane[4] = 0; dane[5] = 0; radio.write(dane, sizeof(dane)); break; case 2: display.setCursor(15,20); display.setTextColor(0,1); display.setTextSize(2); display.print(" Papier "); display.display(); dane[0] = 4; //Jeden, oznacza wybraną stronę. potrzebną odbiornikowi dane[1] = 0; dane[2] = 0; //mapowanie odczytów z pinów dane[3] = 0; //analogowych na ruch serw. dane[4] = 0; dane[5] = 0; radio.write(dane, sizeof(dane)); break; case 3: display.setCursor(15,20); display.setTextColor(0,1); display.setTextSize(2); display.print(" Nozyce "); display.display(); dane[0] = 5; //Jeden, oznacza wybraną stronę. potrzebną odbiornikowi dane[1] = 0; dane[2] = 0; //mapowanie odczytów z pinów dane[3] = 0; //analogowych na ruch serw. dane[4] = 0; dane[5] = 0; radio.write(dane, sizeof(dane)); break; case 4: display.setCursor(15,20); display.setTextColor(0,1); display.setTextSize(2); display.print(" Bay,Bay "); display.display(); dane[0] = 6; //Jeden, oznacza wybraną stronę. potrzebną odbiornikowi dane[1] = 0; dane[2] = 0; //mapowanie odczytów z pinów dane[3] = 0; //analogowych na ruch serw. dane[4] = 0; dane[5] = 0; radio.write(dane, sizeof(dane)); break; } } void action4() { display.setTextSize(1); display.setCursor(8,0); display.setTextColor(1,0); display.print("Informacje"); display.drawLine(0,9,128,9,1); display.display(); display.setCursor(15,15); display.setTextColor(1,0); display.setTextSize(1); display.print("Made by: Jakub G."); display.setCursor(15,30); display.setTextColor(1,0); display.setTextSize(1); display.print("Wersja: "); display.setCursor(70,30); display.setTextColor(0,1); display.setTextSize(1); display.print(" V.6 "); display.display(); } |
///////////////////////////////////////////////////////////////
Budowa odbiornika(ręka):
Części potrzebne do wykonania ręki zostały wydrukowane na drukarce 3d, link do dysku google z częściami do pobrania. Projekt ręki został pobrany z strony projektu InMoove, można tam pobrać i zobaczyć wszystkie części humanoidalnego robota InMoove wraz z ich szczegółowym opisem i poradnikami dotyczącymi budowy.
Po wydrukowania wszystkich części, należy je przygotować do składania wszystkie otwory przewiercić, a miejsca stawów wyszlifować (można też użyć smaru lub innego specyfiku, aby obie części ruszały się z mniejszymi oporami). Dwie największe części należy skleić klejem do wydruków 3d, w moim przypadku złączone zostały przy użyciu długopisu 3d oraz zapalniczki rozgrzewając miejsce łączenia, na koniec polałem mocno rozgrzanym klejem na gorąco.
Złożenie palców jest dość proste, odcinamy dwa odcinki z mocnej i cienkiej linki, około 40-50cm. Przeciągamy je przez otwory (pamiętaj aby linka górna, cały czas szła górnymi otworami i na odwrót). Palce skręcone zostały przy pomocy śrubek i nakrętek, pamiętaj aby nie były zbyt mocno dokręcone, uniemożliwi to ruch palca. Na tym etapie nie przyklejaj końcówki palców.
I tak każdy palec, dalej palce łączymy z dłonią. Pamiętaj o przeciągnięciu linek przez otwory, na każdy palec przypadają trzy otwory znajdujące się jeden nad drugim. Przez dolny przeciągnij linkę od prostowania palca, środkowy otwór służy do przewodów od czujników nacisku (zostawiamy je puste), przez górny otwór przeciągnij linkę od zginania palca.
Następnym etapem jest połączenie dłoni z resztą ręki, łączy się je przy pomocy wydrukowanej śruby. Pamiętaj, aby linki odpowiadające za zginanie były na górze, a linki od prostowania na dole śruby i nie plątały się.
Teraz wydrukowany element do trzymania serw przykręcamy do ręki w wyznaczonym miejscu, przykręcamy do niego także elementy podtrzymujące linki. Kolejnym krokiem będzie przykręcenie serw na odpowiednie miejsca i w odpowiedniej orientacji oraz wyprowadzenie od nich przewodów. Powinny wyglądać tak (nie zwracaj uwagi na linki) ;)
Kolejnym i zarazem najcięższym i najbardziej czasochłonnym procesem jest naciąganie i dostrajanie linek, przeciągnij wszystkie linki przez odpowiadające im otwory(pamiętaj, aby nie ocierały się, ani nie stykały ze sobą w żaden sposób). Teraz musisz przywiązać do śrub końcówki linek, teraz ustawiając serwo trochę przed skrajną pozycją przywiązać linkę na końcówce palca na śrubce tak, aby były możliwie zgięte lub wyprostowane w zależności od linki i tak z każdym palcem. Jest z tym trochę pracy, i ciężko jest to wytłumaczyć lecz z każdym kolejnym palcem wychodzi coraz lepiej. Ważne jest aby na każdej z skrajnych pozycji serwa tzn. 0 i 180 stopni palec był na maksa zgięty lub na maksa wyprostowany, a linka była mocno naprężona.
Teraz można przykleić końcówki palców przy pomocy gorącego kleju, powinno to wyglądać mniej więcej tak;
Kolejnym krokiem jest sprawdzenie, jaki maksymalny i minimalny kąt wychylenia ma każdy palec. Sprawdzić to można wgrywając ten kod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <Servo.h> Servo myservo; int potpin = 0; int val; void setup() { myservo.attach(9); Serial.begin(9600); } void loop() { val = analogRead(potpin); val = map(val, 0, 1023, 0, 180); myservo.write(val); Serial.println(val); delay(15); } |
Teraz przy pomocy serial monitora zapisz wartości minimalne i maksymalne dla każdego serwa, potem będą potrzebne.
KOD Odbiornika:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
#include <SPI.h> #include <nRF24L01.h> //biblioteki do obsługi nrf24L01 #include <RF24.h> #include <Servo.h> //biblioteka do obsługi serwomechanizmów Servo servo1; Servo servo2; Servo servo3; //definiowanie nazw poszczególnych serw Servo servo4; Servo servo5; #define serwo_min_1 180 #define serwo_min_2 0 #define serwo_min_3 0 //wartości minimalne dla każdego serwa #define serwo_min_4 180 #define serwo_min_5 0 #define serwo_max_1 0 #define serwo_max_2 180 #define serwo_max_3 180 //wartości maksymalne dla każdego serwa #define serwo_max_4 0 #define serwo_max_5 180 const uint64_t pipe = 0x1CF8361637LL; //kod kanału odbiornika RF24 radio(9, 10); //piny ce cs modułu nrf24L01 int odczyt[6]; //zmienne do przechowywania otrzymanych danych int dane[2]; long wybor, wybor_u, wybor_a; //przechowywanie wyboru urzytkownika i losowania ręki podczas gry void setup() { servo1.attach(2); servo2.attach(3); servo3.attach(4); //przypisywanie pinów serw do ich nazw servo4.attach(5); servo5.attach(6); delay(1000); //czekaj 1s radio.begin(); //włączenie komunikacji między arduino, a nrf24L01 radio.setDataRate(RF24_2MBPS); //prędkość transmisji danych na 2mbps radio.setPALevel(RF24_PA_HIGH); //siła nadawania/odbierania na max radio.openReadingPipe(1,pipe); //odbieraj/nadawaj na kanale pipe radio.startListening(); //zacznij nasłuchiwać Serial.begin(9600); //zacznij komunikację na porcie szeregowym randomSeed(analogRead(A0)); //ustaw "ziarno" do losowania na nie używany port A0 } void loop() { delay(5); radio.startListening(); //zacznij nasłuchiwać if ( radio.available() ) //jeśli coś przyszło { radio.read( odczyt, sizeof(odczyt) ); //odczytaj i włóż do każdej szufladki zmiennej odczyt } switch(odczyt[0]){ //wykonaj daną funkcję case 1: Serial.print(odczyt[0]); // wypisz dane na Serial porcie i Serial.print(" || "); // wpisz wartości do serw Serial.print(odczyt[1]); Serial.print(" || "); Serial.print(odczyt[2]); Serial.print(" || "); Serial.print(odczyt[3]); Serial.print(" || "); Serial.print(odczyt[4]); Serial.print(" || "); Serial.println(odczyt[5]); servo1.write(odczyt[1]); servo2.write(odczyt[2]); //ustaw serwo mechanizmy na danej pozycji servo3.write(odczyt[3]); servo4.write(odczyt[4]); servo5.write(odczyt[5]); break; case 2: Serial.println(odczyt[2]); switch(odczyt[2]){ //jeżeli wybrano daną funkcję w menu Figury case 1: kamien(); //wykonaj funkcję kamień delay(2000); //czekaj 0,5s break; case 2: nozyce(); //wykonaj funkcję nożyce delay(2000); //czekaj 0,5s break; case 3: papier(); //wykonaj funkcję papier delay(2000); //czekaj 0,5s break; } break; case 3: Serial.println(" Kamien "); //wypisz na serial porcie kamień kamien(); //wykonaj funkcję kamień delay(250); //czekaj 0,25s break; case 4: Serial.println(" papier "); //wypisz na serial porcie papier papier(); //wykonaj funkcję papier delay(250); //czekaj 0,25s break; case 5: Serial.println(" nozyce "); //wypisz na serial porcie nożyce nozyce(); //wykonaj funkcję nożyce delay(250); //czekaj 0,25s break; zeruj(); //wyzeruj pozycję serw } } /* Zdefiniowanie poszczegulnych funkcji do wykonania przez serwa || || || || || || || || || || || || || || || || || || || || || || || || || || \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ */ void zeruj(){ servo1.write(160); servo2.write(20); servo3.write(20); servo4.write(160); servo5.write(20); } void papier(){ servo1.write(serwo_min_1); servo2.write(serwo_min_2); servo3.write(serwo_min_3); servo4.write(serwo_min_4); servo5.write(serwo_min_5); } void kamien(){ servo2.write(serwo_max_2); servo3.write(serwo_max_3); servo4.write(serwo_max_4); servo5.write(serwo_max_5); delay(200); servo1.write(serwo_max_1); } void nozyce(){ servo1.write(serwo_min_1); delay(200); servo2.write(serwo_min_2); servo3.write(serwo_min_3); servo4.write(serwo_max_4); servo5.write(serwo_max_5); delay(300); servo1.write(serwo_max_1); delay(2000); } |
Podsumowanie projektu
Projekt uważam za udany, jest to na pewno fajny gadżet dla każdego majsterkowicza lub elektronika. W dodatku jest to to tylko jeden z wielu podzespołów jakie możemy wydrukować i wykonać w domu, więcej elementów oraz innych “robotycznych części ciała” możemy znaleźć na stronię projektu InMoov . W dodatku każdy, w łatwy sposób może rozwinąć mój kod o dodatkowe funkcję lub kolejne gry, zależy od waszych chęci. Co do kosztów i czasu wydruku, to są dość spore, efekt końcowy jest jednak tego wart.
W razie pytań piszcie w komentarzach pod spodem artykułu.
pliki do pobrania.
Cześć!
Pliki załączone do artykułu:
- nadajnik-1-1.png
- nadajnik-2-1.png
- odbiornik.png
- auriculaire_3.stl
- bolt_entretoise7.stl
- dc_motor_20mm.stl
- index_3.stl
- majeure_3.stl
- ringfinger_3.stl
- robcableback.stl
- robcablefront.stl
- robpart1.stl
- robpart2.stl
- robpart3.stl
- robpart5.stl
- robring.stl
- robservobed.stl
- thumb.stl
- wristlarge.stl
- wristsmall.stl
- img_20190103_132801.jpg
- img_20190103_132812.jpg
- img_20190103_132815.jpg
- img_20190103_133053-1.jpg
- img_20190103_133406.jpg
- img_20190103_140746.jpg
- img_20190103_140752.jpg
- img_20190103_140803.jpg
- img_20190103_141010.jpg
- img_20190103_141016.jpg
- img_20190103_141035.jpg
- img_20190103_141050.jpg
- img_20190103_141208-1.jpg
- img_20190103_141209.jpg
- img_20190103_141228.jpg
- img_20190103_141237.jpg
- img_20190103_141527.jpg
- img_20190103_141536.jpg
- img_20190103_141539.jpg
- img_20190103_141556-1.jpg
- img_20190103_141608-1.jpg
- img_20190103_141621.jpg
- img_20190103_141643.jpg
- img_20190103_143025.jpg
- img_20190103_143028.jpg
- img_20190103_143030.jpg
- img_20190103_143043.jpg
- img_20190103_170929-1.jpg
- img_20190103_171025-1.jpg
- img_20190103_171027.jpg
Wow, kawał niezłej roboty! Gratuluję samozaparcia w składaniu całości. Fajnie, że dodałeś czytelne komentarze w kodzie, duży plus za to bo ułatwia też innym nauczenie się czegoś :) 5/5!
Dzięki :)
Projekt bardo ciekawy. Zapytam się z ciekawości jak wyszedł cenowo?
Sama elektronika kosztowała około 450zł, nie licząc płytek drukowanych, baterii, mocowania do baterii oraz przewodów, które były pod ręką. Najdroższe okazały się czujniki zgięcia około 70 dych za sztukę, a jest ich pięć. Koszt wydruku trudno oszacować, zrobiona została z pla, na oko poszło z 500-600 gram. Rękawice, trytytki i śrubki też były pod ręką więc ich nie liczę. Całkowity koszt to około 600zł.
Dzięki
Efekt końcowy bomba, wykonanie jak dla mnie kosmos – gratuluje wiedzy i umiejętności.
70 dych za sztukę? cóś drogawo ;)
Świetny pomysł i fajne tryby :) Jak pozwolisz odrobinkę przyczepię się do kodu, ale nie traktuj tego jako krytykę ale jedynie jako dobre rady:
– masz dużo powtarzających się fragmentów np :
display.setCursor(15,20);
display.setTextColor(0,1);
display.setTextSize(2);
display.print(” Bay,Bay “);
display.display();
gdzie zmianiane jest tylko napis wyświetlany, lepiej utworzyć funkcję i do niej przekazywać ten jeden tekst do wyśweietlenia.
– podobnie:
dane[0] = 6; //Jeden, oznacza wybraną stronę. potrzebną odbiornikowi
dane[1] = 0;
dane[2] = 0; //mapowanie odczytów z pinów
dane[3] = 0; //analogowych na ruch serw.
dane[4] = 0;
dane[5] = 0;
tutaj tez funkcja z parametrem int co idzie do dane[1] a drugi parametr to wskaznik do tablicy czyli woalnie wyglada tak ustaw(6,dane);
– if(plus == true){ -> poprostu if (plus)
– while(!plus); to jest dla mnie nie zrozumiale (chyba pozostalosc po przerwaniach)
– poczytaj też o makrze F() – zaoszczedzisz duzo RAMu a dzieki temu też arduino będzie działać stabilniej ( zwłaszcza gdy RAM jest już na wyczerpaniu)
Powodzenia w dalszym programowaniu :)
Witam czy jest stl do tej obudowy aby przykryć serwa ?
Co prawda późno na to trafiłem, ale muszę przyznać, że Świetny projekt, gratuluję!
Projekt dla bardziej zaawansowanych. Jak dla minie bardzo fajny. Szkoda tylko, że części takie drogie.
Fantastyczny pomysł!! Muszę namówić szefa byśmy zrobili podobny w ramach warsztatów dla majsterkowiczów. Masz napraawdę niesamowite pomysły, przeglądam teraz bloga i jak to mawiają Francuzi – szapoba
6,
IMO masz błędy w schemacie – podłączenie czujników zgięcia: powinny razem z opornikiem dawać dzielnik napięcia.
5v–opornik-|-sensor–GND.
Na rysunku wygląda to inaczej.