Plama
Jak zbudować ramię robota? Prototyp (1/3)

Problem

Jednym z naszych ostatnich zadań było przetestowanie sensorów ruchu w warunkach brzegowych. Zmierzyliśmy żywotność baterii specjalistycznego sensora w zależności od ruchu jaki wykonuje oraz szybkości transmisji danych.

W uproszczeniu: sprawdziliśmy po jakim czasie rozładuje się bateria urządzenia, gdy będziemy z niego intensywnie korzystać.

Wyzwanie dotyczyło wykonywania tych samych ruchów nieustannie przez kilka godzin. Tak właśnie powstała idea stworzenia mechanicznego i programowalnego ramienia robota.

Koncept

Swój pomysł oparliśmy o znaną i lubianą platformę Arduino – to “mikrokomputer”, który świetnie sprawdza się w podobnych projektach.

Kurs budowy ramienia robota podzieliliśmy na 3 części:

  1. Prototyp
  2. Ramię
  3. Sterowanie

Do skonstruowania ramienia użyliśmy znaleziony Thingiverse model 3D, który wydrukowaliśmy na drukarce Ender 3. Ramię “ożywiliśmy” za pomocą naszego prototypu. Konsolę do sterowania zaprojektowaliśmy od podstaw i wydrukowaliśmy za pomocą drukarki 3D.

Budujemy prototyp

W tej części kursu zajmiemy się stworzeniem prototypu elektroniki. Dzięki fazie prototypowania pozbędziemy się problemów, które zazwyczaj pochłaniają mnóstwo czasu na różnych etapach projektu.

Co będzie nam potrzebne?

  • 2 x Płytka stykowa
  • 1 x Arduino UNO
  • 3 x Servo motor M955
  • 1 x Servo motor SG90
  • 4 x Potencjometr B10K
  • 1 x Buzzer module
  • 1 x OLED Display 128X64
  • 1 x Przełącznik dźwigniowy
  • 2 x Microswitch
  • 3 x Rezystor 1k
  • Kable połączeniowe

Buzzer (generator dźwięku) jest opcjonalny. Będzie służył jako potwierdzenie naciśnięcia przycisków.

Podzespoły dostaniemy praktycznie w każdym sklepie dla elektroników lub na portalach aukcyjnych.

Schemat

Poniższy schemat przedstawia podłączenie elektroniki, która będzie podstawą działania ramienia robota.

Pobierz schemat w wysokiej rozdzielczości.

Podłączenie

Każdy z podzespołów schematu należy połączyć z płytką Arduino (UNO) za pomocą pinów znajdujących się na samej płytce.

  • Potencjometry: A0 – A3
  • Servo motor M955: D8 – D10
  • Servo motor SG90: D11
  • Buzzer module: D5
  • OLED Display: SDA – A4, SCL – A5
  • Przycisk 1: D8
  • Przycisk 2: D2
  • Przełącznik dźwigniowy: D4

A – analog pin
D – digital pin

Oczywiście musimy pamiętać o podłączeniu zasilania i masy.

Gotowy prototyp.

Zasilanie

Nasze Arduino UNO podłączamy do zasilacza (lub baterii) 9V. Potencjometry, wyświetlacz, buzzer oraz przyciski będziemy zasilać bezpośrednio z płytki, napięciem 5V. Do tego samego układu możemy bezpiecznie podpiąć jedno servo SG90. Nie wymaga ono dużego napięcia więc z powodzeniem możemy zasilić je naszym Arduino.

Natomiast serva M955 wymagają niezależnego zasilania! Podpięcie ich bezpośrednio pod płytkę może uszkodzić nasz układ! Servo M955 pracuje w zakresie 4.7V – 6V. W przypadku naszego prototypu użyliśmy zasilacza laboratoryjnego. Oczywiście można użyć innych form źródła prądu (np. baterie, zasilacz).

Ważne by napięcie prądu mieściło się w zalecanym zakresie (im wyższe tym nasze servo pracuje szybciej)

Działanie serwomechanizmów.

Piszemy kod!

Jak ożywić nasz układ? Oczywiście musimy go zaprogramować! W tym celu skorzystamy ze środowiska Arduino IDE, które jest przeznaczone jest do tworzenia oprogramowania na mikrokontrolery jednoukładowe typu Arduino, ESP32 itp.

Arudino IDE pobieramy stąd. Instalacja jest bardzo prosta.

Jak piszemy kod, który będzie zrozumiały dla naszej płytki? Używamy języka C. Poniżej przedstawiamy kod, który służy do sprawdzenia czy nasz układ działa prawidłowo.

Do dzieła!

Program rozpoczynamy od dołączenia bibliotek:

#include <Servo.h>
#include <OLED_I2C.h>
  1. Servo.h – obsługa serwomechanizmów. Biblioteka jest jedną ze standardowych bibliotek Arduino. Nie musisz jej instalować.
  2. OLED_I2C.hdo pobrania biblioteka, która obsłuży nasz wyświetlacz.

Inicjujemy wyświetlacz oraz rozmiar czcionki:

OLED  myOLED(SDA, SCL);
extern uint8_t SmallFont[];

Deklarujemy piny do których podłączyliśmy nasze urządzenia:

const int buzzer_pin = 5; // buzzer

const int button_1 = 2; // przycisk 1
const int button_2 = 3; // przycisk 2
const int button_3 = 4; // przełącznik dźwigniowy

const int joy1 = 0; // potencjometr 1
const int joy2 = 1; // potencjometr 2
const int joy3 = 2; // potencjometr 3
const int joy4 = 3; // potencjometr 4

const int servo_pin_1 = 8; // Servo 1 M955
const int servo_pin_2 = 9; // Servo 2 M955
const int servo_pin_3 = 10; // Servo 3 M955
const int servo_pin_4 = 11; // Servo 4 SG90

Deklarujemy zmienne do przechowywania pozycji naszych serwomechanizmów. Dodaliśmy kontrolne zmienne “old_” by zapamiętywać ostatnią pozycję naszych serv.

unsigned int servoVal1;
unsigned int servoVal2;
unsigned int servoVal3;
unsigned int servoVal4;

unsigned int old_servoVal1;
unsigned int old_servoVal2;
unsigned int old_servoVal3;
unsigned int old_servoVal4;

Servo servo1; // inicjacja serva 1
Servo servo2; // inicjacja serva 2
Servo servo3; // inicjacja serva 3
Servo servo4; // inicjacja serva 4

Zadeklarowaliśmy zmienne. Pora na deklarację startu programu. Do tego używamy funkcji “setup”. Wszystko co teraz napiszemy powinno znaleźć się wewnątrz tej funkcji.

void setup()
{
	// instrukcje
}

Deklarujemy który PIN ma być wejściem (INPUT) a który wyjściem (OUTPUT). W naszym przypadku wejściem są przyciski i przełącznik (odbieramy dane) a wyjściem buzzer (wysyłamy dane).

pinMode(button_1, INPUT);
pinMode(button_2, INPUT);
pinMode(button_3, INPUT);
pinMode(buzzer_pin, OUTPUT);

Pora przypisać piny do naszych serwomechanizmów:

servo1.attach(servo_pin_1);
servo2.attach(servo_pin_2);
servo3.attach(servo_pin_3);
servo4.attach(servo_pin_4);

Sugerujemy wskazać prędkość portu szeregowego (baud) za pomocą którego możemy komunikować się z naszą płytką. Jest to bardzo przydatne rozwiązanie gdy chcemy debugować nasz kod.

Serial.begin(9600);

Przykład testowania naszych potencjometrów:

Serial.println("Analog 1: " + String(analogRead(joy1)) + " / Analog 2: " + String(analogRead(joy2)) + " / Analog 3: " + String(analogRead(joy3)) + " / Analog 4: " + String(analogRead(joy4)));
Monitor portu szeregowego.

Odbieramy aktualną pozycję potencjometrów i przypisujemy ją do zmiennych:

servoVal1 = analogRead(joy1);
servoVal2 = analogRead(joy2);
servoVal3 = analogRead(joy3);
servoVal4 = analogRead(joy4);

Inicjujemy wyświetlacz OLED:

if (!myOLED.begin(SSD1306_128X32))
while (1); // zabezpieczenie przed przeciążeniem ramu

myOLED.setFont(SmallFont); // wielkość czcionki
myOLED.clrScr(); // czyszczenie ekranu

Prezentujemy na wyświetlaczu aktualne wartości dla potencjometrów:

myOLED.print("A: " + String(servoVal1), LEFT, 1);
myOLED.print("B: " + String(servoVal2), LEFT, 9);
myOLED.print("C: " + String(servoVal3), LEFT, 17);
myOLED.print("D: " + String(servoVal4), LEFT, 25);
myOLED.update();

Objaśnienia:

  • Funkcja String() – przekształca wartość w formę tekstową, zrozumiałą dla wyświetlacza.
  • LEFT – położenie tekstu na wyświetlaczu.
  • 1,9,17,25 – nr wiersza / linii od której zaczynamy wyświetlać tekst
Działanie wyświetlacza OLED.

Obsługa buzzera:

void buzzer(String type) {
	digitalWrite(buzzer_pin, HIGH);
	int delay_buzzer = 10;
	if (type == "long") {
		delay_buzzer = 100;
	}
	digitalWrite(buzzer_pin, LOW);
	delay(delay_buzzer);
	digitalWrite(buzzer_pin, HIGH);
}

Jest to bardzo prosta funkcja, która w zależności od parametru “type” aktywuje i dezaktywuje głośniczek na czas (10ms lub 100ms)

Co dalej?

Mamy zadeklarowany start programu teraz pora by układ zaczął działać! Służy do tego funkcja “loop()”. W niej będziemy pisać kolejną część naszego kodu.

void loop()
{
	// instrukcje
}

Obsługa potencjometrów i serwomechanizmów.

  1. Odbieramy wartość z potencjometra 1.
  2. Za pomocą funkcji map() zmieniamy jego wartość by mieściła się w zakresie tolerancji serva (0 -180).
  3. Sprawdzamy czy obecna wartość potencjometra jest inna od poprzednio odebranej / zapisanej.
  4. Jeśli jest to zmieniamy położenie serva.
// SERVO 1
servoVal1 = analogRead(joy1);
servoVal1 = map(servoVal1, 0, 1023, 0, 180);
if (servoVal1 != old_servoVal1) {
	old_servoVal1 = servoVal1;
	servo1.write(servoVal1);
}

Model ten powielamy analogicznie dla pozostałych serv.

Obsługa przycisków.
Gdy dany przycisk zostanie aktywowany wyświetlamy odpowiedni napis na wyświetlaczu oraz wydajemy sygnał dźwiękowy za pomocą buzzera.

if (digitalRead(button_1) == HIGH) {
	myOLED.print("ON", RIGHT, 1);
	buzzer("short");
} else {
	myOLED.print("BUTTON 1", RIGHT, 1);
}

Wyświetlanie wartości potencjometrów na wyświetlaczu:

myOLED.print("A: " + String(servoVal1), LEFT, 1);
myOLED.print("B: " + String(servoVal2), LEFT, 9);
myOLED.print("C: " + String(servoVal3), LEFT, 17);
myOLED.print("D: " + String(servoVal4), LEFT, 25);
myOLED.update();

delay(50); // opóźnienie każdej iteracji pętli

I to wszystko. Cały kod do pobrania tutaj: https://gitlab.akanza.pl/mgolan/akanzaarm

Zobacz film z procesu budowy i działania prototypu.

Zapraszamy wkrótce na kolejne części kursu “Jak zbudować ramię robota?“.

Kategorie
Inne posty