Arduino Kendinden Dengeleyici Robot

Herkese merhaba!

Bu talimatta, engellerden kaçınmak için hareket edebilecek küçük bir kendini dengeleyen robotun nasıl oluşturulacağını göstereceğim. Bu, 4 inç genişliğinde ve 4 inç yüksekliğinde küçük bir robottur ve Arduino Pro Mini geliştirme kartı ve MPU6050 ivmeölçer-jiroskop modülüne dayanmaktadır.

Takip eden adımlarda, MPU6050'nin Arduino ile nasıl arayüzleneceğini, robotun eğim açısının nasıl ölçüleceğini, robotun dengeli kalmasını sağlamak için PID'in nasıl kullanılacağını göreceğiz. Robotun etrafına dolanırken engellere çarpmasını önleyen bir ultrasonik telemetre de eklenir.

Parça listesi

Bu parçaların çoğunu aliexpress'den aldım, ancak bunları başka bir elektronik mağazasında da bulabilirsiniz.

1. Arduino Pro Mini

2. MPU-6050 ile GY-521 modülü

3. DRV8833 Pololu motor sürücüsü

4. 2, 5V boost dönüştürücü

5. US-020 ultrasonik mesafe sensörü

6. NCR18650 pil ve tutucu

7. çift mikro metal dişli motorlar (N20, 6V, 200 rpm) ve destekleri

8. 42x19mm tekerlek çifti

9. 3, Çift taraflı prototip PCB (4cm x 6cm)

10. 8, 25cm Naylon ara parçaları ve 4, naylon somunlar

Yukarıdakilerin dışında, bazı kablolara, berg konektörlerine ve bir açma / kapama anahtarına ihtiyacınız olacaktır.

Adım 1: Biraz Teori

Ellerimizi kirletmeden önce bazı temel ilkelerle başlayalım.

Kendi kendini dengeleyen robot baş aşağı bir sarkaça benzer. Bir dürtme verildiğinde sallanmaya devam eden normal bir sarkaçtan farklı olarak, bu ters sarkaç kendi başına dengeli kalamaz. Sadece düşecek. Öyleyse nasıl dengeliyoruz? Ters bir sarkaç dengelemenin klasik bir örneği olan işaret parmağımızdaki bir süpürgeyi dengelemeyi düşünün. Parmağımızı çubuğun düştüğü yönde hareket ettiriyoruz. Kendi kendini dengeleyen bir robot için de benzerdir, sadece robot ileri veya geri düşecektir. Tıpkı parmağımızdaki bir çubuğu nasıl dengelediğimiz gibi, tekerleklerini düştüğü yönde sürerek robotu dengeleriz. Burada yapmaya çalıştığımız şey, robotun ağırlık merkezini tam olarak pivot noktasının üzerinde tutmak.

Motorları sürmek için robotun durumu hakkında bazı bilgilere ihtiyacımız var. Robotun düşme yönünü, robotun ne kadar eğildiğini ve düşme hızını bilmemiz gerekir. Tüm bu bilgiler MPU6050'den elde edilen okumalardan elde edilebilir. Tüm bu girdileri birleştiriyoruz ve motorları çalıştıran ve robotu dengede tutan bir sinyal üretiyoruz.

2. Adım: İnşaata Başlayalım

İlk olarak robotun devresini ve yapısını tamamlayacağız. Robot, naylon ayırıcılar kullanılarak 25 mm aralıklı üç kat perfboard üzerine inşa edilmiştir. Alt tabaka iki motoru ve motor sürücüsünü içerir. Orta katman kontrolör, IMU ve 5V boost regülatör modüllerine sahiptir. En üstteki katmanın pili, bir açma / kapama düğmesi ve ultrasonik mesafe sensörü vardır (robotun dengelenmesini sağladıktan sonra bunu sonuna doğru kuracağız).

Bir perfboard üzerinde prototip üretmeye başlamadan önce, her parçanın nereye yerleştirileceği hakkında net bir resmimiz olmalıdır. Prototip oluşturmayı kolaylaştırmak için, tüm bileşenlerin fiziksel düzenini çizmek ve bunu bileşenleri yerleştirmek ve jumperları perfboard üzerinde yönlendirmek için bir referans olarak kullanmak her zaman daha iyidir. Tüm parçalar yerleştirilip lehimlendikten sonra, naylon ayırıcılar kullanarak üç kartı birbirine bağlayın.

Her ikisi de 5V kaynak gerektirse de motorları ve denetleyiciyi çalıştırmak için iki ayrı voltaj regülatörü modülü kullandığımı fark etmiş olabilirsiniz. Bu çok önemli. İlk tasarımımda, kontrol cihazını ve motorları çalıştırmak için tek bir 5V güç regülatörü kullandım. Robotu açtığımda program aralıklı olarak donuyor. Bunun nedeni, denetleyiciye ve IMU'ya etki eden motor devresinden kaynaklanan gürültüden kaynaklanıyordu. Bu, voltaj regülatörünü kontrolöre ve motora ayırarak ve motor güç kaynağı terminallerine 10 uF kapasitör ekleyerek etkili bir şekilde ortadan kaldırıldı.

Adım 3: İvmeölçer Kullanarak Eğim Açısını Ölçme

MPU6050, 3 eksenli bir ivmeölçer ve 3 eksenli jiroskopa sahiptir. İvmeölçer üç eksen boyunca ivmeyi ölçer ve jiroskop üç eksen etrafında açısal hızı ölçer. Robotun eğim açısını ölçmek için y ve z eksenleri boyunca ivme değerlerine ihtiyacımız var. Atan2 (y, z) işlevi, bir düzlemin pozitif z ekseni ile o düzlemdeki koordinatların (z, y) verdiği nokta arasındaki radyan cinsinden, saat yönünün tersine açıların (sağ yarım- düzlem, y> 0) ve saat yönünde açılar için negatif işaret (sol yarım düzlem, y <0). MPU6050'den veri okumak için Jeff Rowberg tarafından yazılan bu kütüphaneyi kullanıyoruz. Aşağıda verilen kodu yükleyin ve eğim açısının nasıl değiştiğini görün.

#include "Wire.h"
#include "I2Cdev.h" #include "MPU6050.h" #include "math.h"

MPU6050 mpu;

int16_t accY, accZ; şamandıra accAngle;

void setup () {mpu.initialize (); Serial.begin (9600); }

void loop () {accZ = mpu.getAccelerationZ (); accY = mpu.getAccelerationY (); accAngle = atan2 (accY, accZ) * RAD_TO_DEG; Eğer (isnan (accAngle)); başka Serial.println (accAngle); }

Robotu belirli bir açıda eğik tutarken ileri ve geri hareket ettirmeyi deneyin. Seri monitörünüzde gösterilen açının aniden değiştiğini göreceksiniz. Bunun nedeni, y ve z eksenlerinin ivme değerlerine müdahale eden ivme yatay bileşenidir.

Adım 4: Jiroskop Kullanarak Eğim Açısının Ölçülmesi

MPU6050'nin 3 eksenli jiroskopu, üç eksen boyunca açısal hızı (dönme hızı) ölçer. Kendi kendini dengeleyen robotumuz için, yalnızca x ekseni boyunca açısal hız, robotun düşme hızını ölçmek için yeterlidir.

Aşağıda verilen kodda, x ekseni hakkındaki jiroskop değerini okuduk, saniyede dereceye dönüştürdükten sonra açıdaki değişikliği elde etmek için döngü süresi ile çarpıyoruz. Mevcut açıyı elde etmek için bunu önceki açıya ekliyoruz.

#include "Wire.h"
#include "I2Cdev.h" #include "MPU6050.h"

MPU6050 mpu;

int16_t gyroX, gyroRate; yüzer jiroskopAngle = 0; unsigned long currTime, prevTime = 0, loopTime;

void setup () {mpu.initialize (); Serial.begin (9600); }

void loop () {currTime = millis (); loopTime = currTime - prevTime; prevTime = currTime; gyroX = mpu.getRotationX (); gyroRate = harita (gyroX, -32768, 32767, -250, 250); gyroAngle = gyroAngle + (şamandıra) gyroRate * loopTime / 1000; Serial.println (gyroAngle); }

Program çalışmaya başladığında MPU6050'nin konumu sıfır eğim noktasıdır. Eğim açısı bu noktaya göre ölçülecektir.

Robotu sabit bir açıda sabit tutun, açının kademeli olarak artacağını veya azalacağını gözlemleyeceksiniz. Sabit kalmayacak. Bu jiroskopun doğasında olan kaymadan kaynaklanmaktadır.

Yukarıda verilen kodda, döngü süresi Arduino IDE'de yerleşik olan millis () işlevi kullanılarak hesaplanır. Sonraki adımlarda, kesin örnekleme aralıkları oluşturmak için zamanlayıcı kesmelerini kullanacağız. Bu örnekleme periyodu aynı zamanda bir PID kontrolörü kullanılarak çıkış üretilmesinde kullanılacaktır.

Adım 5: Sonuçları Tamamlayıcı Bir Filtreyle Birleştirme

Google, birbirini tamamlayıcı nitelikleri "birbirlerinin niteliklerini artıracak veya vurgulayacak şekilde birleştirmek " olarak tanımlamaktadır.

İki farklı kaynaktan açının iki ölçümü var. İvmeölçerden gelen ölçüm ani yatay hareketlerden etkilenir ve jiroskoptan yapılan ölçüm yavaş yavaş gerçek değerden uzaklaşır. Başka bir deyişle, ivmeölçer okuması kısa süreli sinyallerden ve jiroskop okumasında uzun süreli sinyallerden etkilenir. Bu okumalar bir bakıma birbirini tamamlayıcı niteliktedir. Her ikisini de Tamamlayıcı Filtre kullanarak birleştirin ve açının kararlı ve doğru bir ölçümünü elde ediyoruz. Tamamlayıcı filtre esas olarak jiroskop üzerinde etkili bir yüksek geçiş filtresi ve ölçümden sapmayı ve gürültüyü filtrelemek için ivmeölçer üzerinde etkili bir düşük geçiş filtresidir.

currentAngle = 0.9934 * (öncekiAngle + gyroAngle) + 0.0066 * (accAngle)

0, 9934 ve 0, 0066, 0, 75 saniyelik bir filtre zaman sabiti için filtre katsayılarıdır. Düşük geçiş filtresi, bu süreden daha uzun sinyallerin içinden geçmesine izin verir ve yüksek geçiş filtresi, bu süreden daha kısa sinyallerin geçmesine izin verir. Filtrenin yanıtı, doğru zaman sabiti seçilerek değiştirilebilir. Zaman sabitinin düşürülmesi daha fazla yatay ivmenin geçmesine izin verecektir.

İvmeölçer ve jiroskop ofset hatalarını ortadan kaldırma
MPU6050'nin ofsetlerini kalibre etmek için bu sayfada verilen kodu indirin ve çalıştırın. Ofsetten kaynaklanan herhangi bir hata, aşağıda gösterildiği gibi setup () rutininde ofset değerleri tanımlanarak ortadan kaldırılabilir.

mpu.setYAccelOffset (1593);
mpu.setZAccelOffset (963); mpu.setXGyroOffset (40);

Adım 6: Çıktı Üretmek için PID Kontrolü

PID, Oransal, İntegral ve Türev anlamına gelir. Bu terimlerin her biri, kendi kendini dengeleyen robotumuza benzersiz bir yanıt sağlar.

Orantılı terim, adından da anlaşılacağı gibi, hatayla orantılı bir yanıt oluşturur. Sistemimiz için hata, robotun eğim açısıdır.

İntegral terimi, biriken hataya göre bir yanıt üretir. Bu, esasen örnekleme periyodu ile çarpılan tüm hataların toplamıdır. Bu, sistemin geçmişteki davranışlarına dayanan bir yanıttır.

Türev terimi hatanın türevi ile orantılıdır. Bu, mevcut hata ile önceki hata arasındaki farkın örnekleme dönemine bölümüdür. Bu, robotun bir sonraki örnekleme döngüsünde nasıl davranabileceğine yanıt veren öngörücü bir terim olarak işlev görür.

Bu terimlerin her birini karşılık gelen sabitleriyle (yani, Kp, Ki ve Kd) çarpıp sonucu toplayarak, daha sonra motoru çalıştırmak için komut olarak gönderilen çıktıyı üretiriz.

Adım 7: PID Sabitlerini Ayarlama

1. Ki ve Kd'yi sıfıra ayarlayın ve robotun sıfır konumu etrafında salınmaya başlaması için Kp'yi kademeli olarak artırın.

2. Ki'yi, robotun dengesiz olduğunda tepkisinin daha hızlı olması için artırın. Ki, eğim açısı artmayacak kadar büyük olmalıdır. Robot eğimli ise sıfır pozisyonuna geri dönmelidir.

3. Salınımları azaltmak için Kd'yi artırın. Şimdiye kadar aşma değerleri de azaltılmalıdır.

4. En iyi sonucu elde etmek için her bir parametreye ince ayar yaparak yukarıdaki adımları tekrarlayın.

Adım 8: Mesafe Sensörünü Ekleme

Kullandığım ultrasonik mesafe sensörü US-020. Vcc, Trig, Echo ve Gnd olmak üzere dört iğnesi vardır. 5V kaynak ile çalışır. Tetikleyici ve yankı pimleri sırasıyla Arduino'nun dijital pimleri 9 ve 8'e bağlanır. Sensörden uzaklık değerini almak için NewPing kütüphanesini kullanacağız. Mesafeyi her 100 milisaniyede bir okuyacağız ve değer 0 ila 20 cm arasındaysa, robota bir dönüş yapmasını emredeceğiz. Robotu engelden uzaklaştırmak için bu yeterli olmalıdır.

9. Adım: Kodun Tamamı

 #include "Wire.h" 

#include "I2Cdev.h" #include "MPU6050.h" #include "math.h" #include

#define leftMotorPWMPin 6 #define leftMotorDirPin 7 #define rightMotorPWMPin 5 #define rightMotorDirPin 4

#define TRIGGER_PIN 9 #define ECHO_PIN 8 #define MAX_DISTANCE 75

#define Kp 40 #define Kd 0.05 #define Ki 40 #define sampleTime 0.005 #fine targetAngle -2.5

MPU6050 mpu; NewPing sonar (TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);

int16_t accY, accZ, gyroX; uçucu int motorGüç, gyroRate; uçucu şamandıra accAngle, gyroAngle, currentAngle, prevAngle = 0, hata, prevError = 0, errorSum = 0; uçucu bayt sayısı = 0; int distanceCm;

void setMotors (int leftMotorSpeed, int rightMotorSpeed) {if (leftMotorSpeed> = 0) {analogWrite (leftMotorPWMPin, leftMotorSpeed); digitalWrite (leftMotorDirPin, DÜŞÜK); } else {analogWrite (leftMotorPWMPin, 255 + leftMotorSpeed); digitalWrite (leftMotorDirPin, YÜKSEK); } if (rightMotorSpeed> = 0) {analogWrite (rightMotorPWMPin, rightMotorSpeed); digitalWrite (rightMotorDirPin, DÜŞÜK); } else {analogWrite (rightMotorPWMPin, 255 + rightMotorSpeed); digitalWrite (rightMotorDirPin, YÜKSEK); }}

void init_PID () // Timer1'i başlat cli (); // genel kesintileri devre dışı bırak TCCR1A = 0; // TCCR1A kaydının tamamını 0 olarak ayarlayın TCCR1B = 0; // TCCR1B için aynı // set örnekleme zamanını ayarlamak için karşılaştırmalı kayıt kaydet 5ms OCR1A = 9999; // CTC modunu aç TCCR1B

void setup () {// motor kontrolünü ve PWM pimlerini pinMode (leftMotorPWMPin, OUTPUT) çıkış moduna ayarlayın; pinMode (leftMotorDirPin, OUTPUT); pinMode (rightMotorPWMPin, ÇIKIŞ); pinMode (rightMotorDirPin, OUTPUT); // durum LED'ini pinMode (13, OUTPUT) çıkış moduna ayarlayın; // MPU6050'yi başlatın ve ofset değerlerini ayarlayın mpu.initialize (); mpu.setYAccelOffset (1593); mpu.setZAccelOffset (963); mpu.setXGyroOffset (40); // PID örnekleme döngüsünü başlat init_PID (); }

void loop () {// okuma ivmesi ve jiroskop değerleri accY = mpu.getAccelerationY (); accZ = mpu.getAccelerationZ (); gyroX = mpu.getRotationX (); // motor gücünü sınırladıktan sonra ayarlayın motorPower = kısıt (motorPower, -255, 255); setMotorlar (motorPower, motorPower); // eğer ((sayı% 20) == 0) {distanceCm = sonar.ping_cm (); } if ((distanceCm <20) && (distanceCm! = 0)) {setMotors (-motorPower, motorPower); }} // ISR her 5 milisaniyede bir ISR çağrılır (TIMER1_COMPA_vect) {// eğim açısını hesaplayın accAngle = atan2 (accY, accZ) * RAD_TO_DEG; gyroRate = harita (gyroX, -32768, 32767, -250, 250); gyroAngle = (şamandıra) gyroRate * sampleTime; currentAngle = 0.9934 * (öncekiAngle + gyroAngle) + 0.0066 * (accAngle); error = currentAngle - targetAngle; errorSum = errorSum + hatası; errorSum = kısıtlama (errorSum, -300, 300); // P, I ve D değerlerinden çıkışı hesapla motorPower = Kp * (hata) + Ki * (errorSum) * sampleTime - Kd * (currentAngle-prevAngle) / sampleTime; prevAngle = currentAngle; // pin13 üzerindeki led'i her saniye sayım + eğer (count == 200) {count = 0; digitalWrite (13;! digitalRead (13)); }}

Adım 10: Son Düşünceler

PID sabitlerini ayarlamak için biraz daha zaman harcamak bize daha iyi bir sonuç verecektir. Robotumuzun büyüklüğü de elde edebileceğimiz stabilite seviyesini sınırlar. Tam boyutlu bir dengeleme robotu oluşturmak bizimki gibi küçük bir robot yapmaktan daha kolaydır. Yine de, sanırım, robotumuz videoda gösterildiği gibi çeşitli yüzeylerde dengeleme konusunda oldukça iyi bir iş çıkarıyor.

Şimdilik bu kadar.

Zaman ayırdığınız için teşekkürler. Düşüncelerinizi yorumlar bölümünde bırakmayı unutmayın.

İlgi̇li̇ Makaleler