• Sonuç bulunamadı

Bu çalışma ile değişik/bozuk yol ve arazi şartlarında hareket halinde olan bir silah sistemini kullanan nişancıların vuruş yüzdesi yüksek olan atışlar yapabilmeleri için tank namlusu stabilizasyon sisteminin Arduino Uno ile uygulanması ve deneysel düzeneğinin hazırlanması, bu düzenek ile tank topu namlusunun sürekli hedef bölgesinde ve sabit bir şekilde durması amaçlanmıştır. Söz konusu deneysel düzenek model tank üzerinde hazırlanmış model tank 150 sola döndüğünde namlu 150 sağa dönerek referans noktasında kalmıştır. Aynı test model tank 150 sağa döndüğünde namlu 150 sola dönerek aynı başarıya ulaşmıştır. Model tanktaki namlu hareketi aşağı ve yukarı yönde de test edilmiştir. Model tank 50’lik bir meyilden aşağı inerken namlu 50’lik yukarı hareketle referans noktasında kalmayı başarmıştır.

Çalışmada kullanılan algoritmanın bazı zamanlarda (çok yüksek hızlı hareketlerde) kararsız davrandığı tespit edilmiştir. Bu kapsamda filtreleme programı ve yazılım algoritması geliştirilebilir. Ayrıca MPU-6050 sensöründen elde edilen ham verilerin mikroişlemci üzerinde hesaplanması mikroişlemcinin işlem yükünü artırmaktadır. Elde edilen ham verilerin mikroişlemci üzerinde değil MPU-6050 sensöründe yerleşik olan Dijital Hareket İşlemci™ (DMP™) ile hesaplanması sağlanabilir.

Çalışmada kullanılan model tankın kulesinin hareketi 3300 ile sınırlı olduğu için sisteme bunun dışında hareket verilememektedir. Oluşturulan sistemin daha kapsamlı ve etkin olarak kullanılabilmesi maksadı ile 3600 dönebilen kuleye sahip model tankta kullanılabilir.

41

EKLER

EK-A: Tank Namlusu Stabilizasyon Sisteminin Yazılım Tasarımında Yer Alan Kodlar

#include <Wire.h> // I2C iletişimi için "Wire" kütüphanesi eklenir.

int stabled=10; // 10 numaralı pin stabled isimli değişken olarak tanımlanır. volatile int stab = LOW; // "stab" isimli değişken tanımlanır ve ilk durumunu "0"

olarak atanır.

volatile int stabledstat = LOW; // "stabledstat" isimli değişken tanımlanır ve ilk durumunu "0" olarak atanır.

long LastDebounceTime=0; // Son Debounce zamanı tanımlanır.

long DebounceTime=300; // Debounce zamanı 300 ms olarak ayarlanır. float targetPosKule, targetPosNam; // Hedef açı ve şimdiki açı değişkenleri tanımlanır. const int // DC motor sabit pini tanımlanır.

PWM_A = 3, // Kule motoru için darbe genişlik modülasyonu pin 3’e tanımlanır.

DIR_A = 12, // Kule motoru için motor yönü kontrolü pin 12’ye tanımlanır BRAKE_A = 9, // Kule motoru için motor freni pin 9a’ tanımlanır.

R_A = A0, // Kumandadan gelen kule motoru sağa dön sinyani A0 pinine atanır.

L_A = A1, // Kumandadan gelen kule motoru sola dön sinyani A1 pinine atanır.

PWM_B = 11, // Namlu motoru için darbe genişlik modülasyonu pin11’e tanımlanır.

DIR_B = 13, // Namlu motoru için motor yönü kontrolü pin 13’e tanımlanır.

BRAKE_B = 8, // Namlu motoru için motor freni pin 8’e tanımlanır. U_B = A2, // Kumandadan gelen namlu motoru yukarı dön sinyali A2

pinine atanır.

D_B = A3; // Kumandadan gelen namlu motoru aşağı dön sinyali A3 pinine atanır.

42

//MPU6050'nin register adresleri birer etiket ismi olarak tanımlanarak bu registerlar adresler yerine etiketleri ile kullanılırlar.

#define MPU6050_ACCEL_XOUT_H 0x3B // Oku #define MPU6050_ACCEL_XOUT_L 0x3C // Oku #define MPU6050_ACCEL_YOUT_H 0x3D // Oku #define MPU6050_ACCEL_YOUT_L 0x3E // Oku #define MPU6050_ACCEL_ZOUT_H 0x3F // Oku #define MPU6050_ACCEL_ZOUT_L 0x40 // Oku #define MPU6050_PWR_MGMT_1 0x6B // Oku/Yaz #define MPU6050_PWR_MGMT_2 0x6C // Oku/Yaz #define MPU6050_WHO_AM_I 0x75 // Oku #define MPU6050_I2C_ADDRESS 0x68 // Oku/Yaz

// MPU6050den gelen baytların sırası derleyici ve AVR çipi bayt sıralamasıyla eşleşmemektedir. Arduino üzerindeki AVR çip, düşük adreste düşük bayt bilgisi bulundurmaktadır. Fakat MPU-6050 faklı sıralamaya sahip yüksek bayt düşük adrestedir, o nedenle düzeltilmesi gerekmektedir.

typedef union accel_t_gyro_union {

struct {

uint8_t x_accel_h; // İvmeölçer X ekseni yüksek bayt uint8_t x_accel_l; // İvmeölçer X ekseni düşük bayt uint8_t y_accel_h; // İvmeölçer Y ekseni yüksek bayt uint8_t y_accel_l; // İvmeölçer Y ekseni düşük bayt uint8_t z_accel_h; // İvmeölçer Z ekseni yüksek bayt uint8_t z_accel_l; // İvmeölçer Z ekseni düşük bayt uint8_t t_h; // Sıcaklık yüksek bayt

uint8_t t_l; // Sıcaklık düşük bayt

uint8_t x_gyro_h; // Jiroskop X ekseni yüksek bayt uint8_t x_gyro_l; // Jiroskop X ekseni düşük bayt uint8_t y_gyro_h; // Jiroskop Y ekseni yüksek bayt uint8_t y_gyro_l; // Jiroskop Y ekseni düşük bayt uint8_t z_gyro_h; // Jiroskop Z ekseni yüksek bayt uint8_t z_gyro_l; // Jiroskop Z ekseni düşük bayt } reg;

43 struct

{

int x_accel; // Yeni değişkenler tanımlanır. int y_accel; int z_accel; int temperature; int x_gyro; int y_gyro; int z_gyro; } value; };

// Sensörün tüm dönüş açılarının kaydedilmesi için aşağıda tanımlanan küresel (global) değişkenler fonksiyonları kullanılır.

unsigned long last_read_time; // Okunan son zaman.

float last_x_angle; // Okunan son filtrelenmiş açılar. float last_y_angle;

float last_z_angle;

float last_gyro_x_angle; // Jiroskop açıları (kayma karşılaştırılması için) float last_gyro_y_angle;

float last_gyro_z_angle; float angles[2]={0,0};

//Son okunan açı verilerinin değişkenlere atama fonksiyonu;

void set_last_read_angle_data(unsigned long time, float x, float y, float z, float x_gyro, float y_gyro, float z_gyro) { last_read_time = time; last_x_angle = x; last_y_angle = y; last_z_angle = z; last_gyro_x_angle = x_gyro; last_gyro_y_angle = y_gyro; last_gyro_z_angle = z_gyro; }

44 // Geçen zaman tanımlanır.

inline unsigned long get_last_time() {return last_read_time;} inline float get_last_x_angle() {return last_x_angle;}

inline float get_last_y_angle() {return last_y_angle;} inline float get_last_z_angle() {return last_z_angle;}

inline float get_last_gyro_x_angle() {return last_gyro_x_angle;} inline float get_last_gyro_y_angle() {return last_gyro_y_angle;} inline float get_last_gyro_z_angle() {return last_gyro_z_angle;} // Kalibrasyon yapabilmek için küresel (global) değişkenler tanımlanır. float base_x_accel; float base_y_accel; float base_z_accel; float base_x_gyro; float base_y_gyro; float base_z_gyro;

// Ham değerler okunur. 14 bayt tek seferde okunur. (3 eksen ivmeölçer = 6 bayt, sıcaklık 2 bayt, 3 eksen jiroskop = 6 bayt). MPU-6050 varsayılan ayarlarına göre filtrelenmemiş veri gönderir ve kararlı veriler değildirler, hata değeri oluştururlar.

int read_gyro_accel_vals(uint8_t* accel_t_gyro_ptr) { // Jiroskop ve ivmeölçer ham değerleri okunur. accel_t_gyro_union* accel_t_gyro = (accel_t_gyro_union *) accel_t_gyro_ptr;

int error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) accel_t_gyro, sizeof(*accel_t_gyro));

// Tüm yüksek ve düşük baytlar değiştirilir. Daha sonra register değerleri değiştirilir, artık "x_accel_l" isimli yapıda düşük bayt yoktur.

uint8_t swap;

#define SWAP(x,y) swap = x; x = y; y = swap // Değiştirme fonksiyonu tanımlanır. SWAP ((*accel_t_gyro).reg.x_accel_h, (*accel_t_gyro).reg.x_accel_l); // İvmeölçer X ekseni düşük ve

yüksek baytlar değiştirilir. SWAP ((*accel_t_gyro).reg.y_accel_h, (*accel_t_gyro).reg.y_accel_l); // İvmeölçer Y ekseni düşük ve

yüksek baytlar değiştirilir. SWAP ((*accel_t_gyro).reg.z_accel_h, (*accel_t_gyro).reg.z_accel_l); // İvmeölçer Z ekseni düşük ve

yüksek baytlar değiştirilir. SWAP ((*accel_t_gyro).reg.t_h, (*accel_t_gyro).reg.t_l); // Sıcaklık düşük ve yüksek

baytlar değiştirilir.

SWAP ((*accel_t_gyro).reg.x_gyro_h, (*accel_t_gyro).reg.x_gyro_l); // Jiroskop X ekseni düşük ve yüksek baytlar değiştirilir.

45

SWAP ((*accel_t_gyro).reg.y_gyro_h, (*accel_t_gyro).reg.y_gyro_l); // Jiroskop Y ekseni düşük ve yüksek baytlar değiştirilir. SWAP ((*accel_t_gyro).reg.z_gyro_h, (*accel_t_gyro).reg.z_gyro_l); // Jiroskop Z ekseni düşük ve

yüksek baytlar değiştirilir. return error;

}

// Kalibrasyon fonksiyonu tanımlanır. Kalibrasyon yapılırken sensör yatay pozisyonda hareketsiz durmalıdır. void calibrate_sensors() { int num_readings = 10; float x_accel = 0; float y_accel = 0; float z_accel = 0; float x_gyro = 0; float y_gyro = 0; float z_gyro = 0; accel_t_gyro_union accel_t_gyro;

// IMU sıfır konumunu belirlemezse sistem uzay boşluğunda gibi davranır.

read_gyro_accel_vals((uint8_t *) &accel_t_gyro); // IMU’dan okunan değerlerin ilk setini yok say. // Sensörden ham değerler okunur ve ortalamasını alınır. Bunun için ilk açılışta bir miktar veri okunur ve ortalamasını alıp sıfır kabul edilir.

for (int i = 0; i < num_readings; i++) { // 10 tane değeri topla. read_gyro_accel_vals((uint8_t *) &accel_t_gyro); x_accel += accel_t_gyro.value.x_accel; y_accel += accel_t_gyro.value.y_accel; z_accel += accel_t_gyro.value.z_accel; x_gyro += accel_t_gyro.value.x_gyro; y_gyro += accel_t_gyro.value.y_gyro; z_gyro += accel_t_gyro.value.z_gyro; delay(100); }

x_accel /= num_readings; // Ortalama al. y_accel /= num_readings;

z_accel /= num_readings; x_gyro /= num_readings; y_gyro /= num_readings; z_gyro /= num_readings;

46

// Ham kalibre değerleri küresel (global) değişkenlere kaydedilmelidir. base_x_accel = x_accel; base_y_accel = y_accel; base_z_accel = z_accel; base_x_gyro = x_gyro; base_y_gyro = y_gyro; base_z_gyro = z_gyro; } void setup() { int error; uint8_t c;

// Motor Sürücüsüde A ve B isimli motorlar için tanımlamalar yapılmalıdır.

pinMode(BRAKE_A, OUTPUT); // A motorunun fren pini çıkış olarak tanımlanır. pinMode(DIR_A, OUTPUT); // A motorunun yön pini çıkış olarak tanımlanır. pinMode(L_A, INPUT); // A motorunun sola dön sinyali giriş olarak

tanımlanır.

pinMode(R_A, INPUT); // A motorunun sağa dön sinyali giriş olarak tanımlanır.

digitalWrite(BRAKE_A, LOW); //A motorunun freni serbest bırakılır.

pinMode(BRAKE_B, OUTPUT); // B motorunun fren pini çıkış olarak tanımlanır. pinMode(DIR_B, OUTPUT); // B motorunun yön pini çıkış olarak tanımlanır. pinMode(U_B, INPUT); // B motorunun yukarı dön sinyali giriş olarak

tanımlanır.

pinMode(D_B, INPUT); // B motorunun aşağı dön sinyali giriş olarak tanımlanır.

digitalWrite(BRAKE_B, LOW); // B motorunun freni serbest bırakılır. attachInterrupt(0, stabilization, RISING); //Stabilizayon için yükselen kenar "0" pinine

"stabilization" adında kesme fonksiyonu tanımlanır. pinMode(stabled,OUTPUT); //stabled değişkenini(10. pini) çıkış olarak tanımlanır Serial.begin(19200); //Seri port 19200bps olarak tanımlanır ve başlatılır. Wire.begin(); // I2C haberleşmesini tanımlanır ve başlatılır. error = MPU6050_read (MPU6050_WHO_AM_I, &c, 1); // MPU-6050 tespit edilemezse hata ver. error = MPU6050_read (MPU6050_PWR_MGMT_2, &c, 1); // MPU-6050 uyku modunda ise hata ver. MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0); // MPU-6050’yi uyku modundan çıkar.

47 //Kalibrasyonu başlatılıp, ilk değerler atanmalıdır.

delay(2000); // Jiroskopun kalibre edilmesi için 2000 mili sn. bekletilir. (Model tankın altındaki ana akım düğmesini açıp elimizi çekmek içi zaman tanınmalı.)

calibrate_sensors();

set_last_read_angle_data(millis(), 0, 0, 0, 0, 0, 0); // ilk açı değerleri 0 atanmalıdır. }

// loop’da kullanmak üzere jiroskoptan açıları okumak için fonksiyon oluşturulur.

void sensPos(){ //sensPos isimli fonksiyon oluşturulur.

int error; // error değişkeni tanımlanır.

double dT; // Zaman değişkeni tanımlanır.

accel_t_gyro_union accel_t_gyro; // Ham değerler okunur.

error = read_gyro_accel_vals((uint8_t*) &accel_t_gyro);

unsigned long t_now = millis(); // Dönüş hesaplamalarının okunmasındaki zaman elde edilir.

// Jiroskop değerleri alınır ve derece/saniye formatına dönüştürülür.

float FS_SEL = 131; // MPU-6050 datasheetine göre ham değerler sırasıyla 131'e bölünerek derece/sn değeri elde edilir.

float gyro_x = (accel_t_gyro.value.x_gyro - base_x_gyro)/FS_SEL; float gyro_y = (accel_t_gyro.value.y_gyro - base_y_gyro)/FS_SEL; float gyro_z = (accel_t_gyro.value.z_gyro - base_z_gyro)/FS_SEL; // İvmeölçer değerleri alınır.

float accel_x = accel_t_gyro.value.x_accel; float accel_y = accel_t_gyro.value.y_accel; float accel_z = accel_t_gyro.value.z_accel; // İvmeölçerden alınan değerler ile açılar hesaplanır.

float RADIANS_TO_DEGREES = 180/3.14159; // Radyan dereceye çevrilir. float accel_angle_y = atan(-1*accel_x/sqrt(pow(accel_y,2) +

pow(accel_z,2)))*RADIANS_TO_DEGREES;

float accel_angle_x = atan(accel_y/sqrt(pow(accel_x,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES; float accel_angle_z = 0;

48 // Filtrelenmiş jiroskop açıları hesaplanır.

float dt =(t_now - get_last_time())/1000.0; // Zamandaki değişimi hesaplanır. float gyro_angle_x = gyro_x*dt + get_last_x_angle(); // Tamamlayıcı filtre formülü float gyro_angle_y = gyro_y*dt + get_last_y_angle(); // açı = omega x delta t + son açı float gyro_angle_z = gyro_z*dt + get_last_z_angle();

// Jiroskopun kayma açıları hesaplanmalıdır. Burada filtrelenmiş veri kullanılarak açıdaki kayma hesaplanır.

float unfiltered_gyro_angle_x = gyro_x*dt + get_last_gyro_x_angle(); float unfiltered_gyro_angle_y = gyro_y*dt + get_last_gyro_y_angle(); float unfiltered_gyro_angle_z = gyro_z*dt + get_last_gyro_z_angle();

// Tamamlayıcı Filtre algoritması uygulanır. Alfa örnekleme hızına bağlıdır ve kestirim (0.98) yapılır. float alpha = 0.98;

float angle_x = alpha*gyro_angle_x + (1.0 - alpha)*accel_angle_x; float angle_y = alpha*gyro_angle_y + (1.0 - alpha)*accel_angle_y;

float angle_z = gyro_angle_z; // İvmeölçer "Z" açısı vermez. Bu yüzden jiroskoptan alınan "Z" açısına eşitlenir. // Hafızadaki veriler elde edilen son verilerle güncellenmelidir.

set_last_read_angle_data(t_now, angle_x, angle_y, angle_z, unfiltered_gyro_angle_x, unfiltered_gyro_angle_y, unfiltered_gyro_angle_z);

angles[1] = angle_y; angles[2] = angle_z; }

// PID Kontrol Algoritması tanımlanır.

float K = 1.4; // error kat sayısı

int Kp = 3; // Oransal kat sayı (Hedef noktasına ulaşma zamanı ayarlanır.)

int Ki = 1; // İntegral katsayısı (Hedef noktası etrafındaki salınım ayarlanır.) int Kd =6; // Türevsel katsayı (Hedef noktasına oturma

zamanını ayarlanır.)

int last_err = 0; // Hatanın son hali için değişken atanır. int integrated_err = 0; // Hata toplamları için değişken atanır. int pTerm = 0, iTerm = 0, dTerm = 0; // PID için tek tek değişken atanır. int GUARD_GAIN=1; // Hata toplamı sınırı 1 olarak tanımlanır.

49 // PWM değeri hesaplama fonksiyonu tanımlanır.

int updatePid(int targetPosition, int currentPosition) {

int err = targetPosition - currentPosition; // Hata= kule pozisyonu - şimdiki pozisyon if (abs(err)>=3){ // Eğer hata mutlak 3 ise

pTerm = Kp * err; // Hatayı Kp ile çarp.

integrated_err += err; // Hataları topla. iTerm = Ki * constrain(integrated_err, -GUARD_GAIN, GUARD_GAIN); // Hataların sınırları

belirlenir. (-1 ile +1 arası)(constrain sınırlama yapan fonksiyon)

dTerm = Kd * (err - last_err); // Hatadaki değişim Kd ile çarpılır. (Hatanın azalıp azalmadığı kontrol edilir yani motorlar doğru yönemi dönüyor kontrol edilir.)

last_err = err; // Hata güncellenir.

return -constrain(K*(pTerm + iTerm + dTerm), -255, 255);} // Heseplanan PWM sonucuna uygun sinyal üretilir ve bu sonuç ±255 ile sınırlandır. }

// Stabilizasyo sisteminin çalışması veya çalışmaması için "stabilization" adında kesme fonksiyonu tanımlanmalıdır.

void stabilization() {

if ((millis()-LastDebounceTime)>DebounceTime){ // Bu koşul ile düğmenin debounce etkisi filtrelenir.(millis komutu o anki zamanı saate bakarak oluşturur.)

// Düğmye ikinci kez basılma 300 ms'den önce yapılırsa sistem tarafından işleme alınmaz. (300=debounce time yukarıda tanımlandı.) stab = !stab; // Düğmeye basılınca mevcut çalışma durumunun

tersini uygulanır.

LastDebounceTime=millis(); // En son düğmeye basılan zaman tespit edilir. if (stab == HIGH) // Stabilizasyon aktif ise sensörün yönelimi

referans alınır. {

digitalWrite (stabled,HIGH); // Led yakılır. }

else if (stab == LOW) // Stabilizasyon aktif değilse {

50 }

} }

// Kule ve namlu motorlarının hareket fonksiyonları tanımlanmalıdır.

void kuleMotYon(int tork){ // Kule motorunu döndürmek için fonksiyon tanımlanır. if (tork >= 0){ // Kule motoru için sağa dönüş koşulu belirlenir.(tork = PWM

değeri)

digitalWrite(DIR_A, LOW); // Kule motoru için sağa dönüş yönü belirlenir.

} else if ( tork < 0){ // Kule motoru için sola dönüş koşulu belirlenir.(tork = PWM değeri)

digitalWrite(DIR_A, HIGH); } // Kule motoru için sola dönüş yönü belirlenir.

tork=abs(tork); // PWM değeri pozitif olmalıdır. Bunun için mutlağı alınır. if (tork>=10){ // Çok küçük PWM değerleri motora hareket vermeye

yetmeyebilir o yüzden bu değer 10’un üzerinde olduğunda uygulanmalıdır.

tork=map(tork, 0,255,150,255); // PWM motoru döndürebilecek seviyeye yeniden eşlenir. analogWrite(PWM_A, tork);} // Motoru döndür komutu gönderilir.

else{

analogWrite(PWM_A, 0);} }

void namMotYon(int tork){ // Namlu motorunu döndürmek için fonksiyon tanımlanır. if (tork >= 0){ // Namlu motoru için aşağı dönüş koşulu belirlenir.

(tork = PWM değeri)

digitalWrite(DIR_B, HIGH); // Namlu motoru için aşağı dönüş yönü belirlenir. } else if ( tork < 0){ // Namlu motoru için yukarı dönüş koşulu belirlenir.

(tork = PWM değeri)

digitalWrite(DIR_B, LOW); } // Namlu motoru için yukarı dönüş yönü belirlenir

tork=abs(tork); // PWM değeri pozitif olmalıdır. Bunun için mutlağı alınır. if (tork>=10){ // Çok küçük PWM değerleri motora hareket vermeye

yetmeyebilir o yüzden bu değer 10’un üzerinde olduğunda uygulanmalıdır.

tork=map(tork, 0,255,200,255); // PWM motoru döndürebilecek seviyeye yeniden eşlenir. analogWrite(PWM_B, tork);} // Motoru döndür komutu gönderilir.

else{

analogWrite(PWM_B, 0);} }

51 // Kumandadan kontrol için aşağıdaki fonksiyonlar tanımlanır.

void kuleMotSol(){ // Kule motorunu sola döndürmek için fonksiyon tanımlanır. digitalWrite(DIR_A, HIGH);

analogWrite(PWM_A, 255); }

void kuleMotSag(){ // Kule motorunu sağa döndürmek için fonksiyon tanımlanır. digitalWrite(DIR_A, LOW);

analogWrite(PWM_A, 255); }

void namMotYkr(){ // Namlu motorunu yukarı döndürmek için fonksiyon tanımlanır. digitalWrite(DIR_B, LOW);

analogWrite(PWM_B, 255); }

void namMotAsg(){ // Namlu motorunu aşağı döndürmek için fonksiyon tanımlanır. digitalWrite(DIR_B, HIGH);

analogWrite(PWM_B, 255); }

void kuleMotDur() { // Kule motorunu durdurmak için fonksiyon tanımlanır. analogWrite(PWM_A, 0);

}

void namMotDur() { // Namlu motorunu durdurmak için fonksiyon tanımlanır. analogWrite(PWM_B, 0);

}

// Ana program fonksiyonu oluşturulur. void loop(){

sensPos(); // Yukarıda tanımlanmış olan jiroskoptan açıları okuma fonksiyonu çağırılır. (Her loop’ta yeniden açıları okumak üzere)

// Ana programda kule motoru kontrolü için fonksiyon oluşturulur.

if (analogRead(R_A) >= 500){ // Kumandadan gelen R_A sinyali 500’den büyük ise kule sağa döndürülür.

while(analogRead(R_A) >= 500)

{kuleMotSag(); } //while kodu ile sinyal geldiği müddetçe kule motoru sağa döndürülür. kuleMotDur(); // Sinyal kesildiğinde kule motoru durdurulur.

sensPos(); // Kulenin yeni açısı okunur.

targetPosKule=angles[2];} // Tespit edilen yeni açı yeni z0 değeri olarak atanır.

else if (analogRead(L_A) >=500){ // Kumandadan gelen L_A sinyali 500’den büyük ise kule sola döndürülür.

52 while(analogRead(L_A) >= 500)

{kuleMotSol();} // while kodu ile sinyal geldiği müddetçe kule motoru sola döndürülür. kuleMotDur(); // Sinyal kesildiğinde kule motoru durdurulur.

sensPos(); // Kulenin yeni açısı okunur.

targetPosKule=angles[2];} // Tespit edilen yeni açı yeni z0 değeri olarak atanır.

else if (stab==HIGH){ // Kulenin stabilizasyonda kalması sağlanır.

kuleMotYon(updatePid(targetPosKule, angles[2])); // PID fonksiyonu çalıştırılır. Çıkan PWM sonucu kule motorunun hareketi için girdi olarak alındıktan sonra kule motoru fonksiyonu çalıştırılır.

}

// Ana programda namlu kontrolü için fonksiyon oluşturulur.

if (analogRead(U_B) >= 400){ // Kumandadan gelen U_B sinyali 400’den büyük ise namlu aşağı indirilir.

while(analogRead(U_B) >= 400)

{namMotYkr();} // while kodu ile sinyal geldiği müddetçe namlu aşağı indirilir. namMotDur(); // Sinyal kesildiğinde namlu motoru durdurulur.

sensPos(); // Namlunun yeni açısı okunur.

targetPosNam=angles[1];} // Tespit edilen yeni açı yeni y0 değeri olarak atanır.

else if (analogRead(D_B) >= 400){ // Kumandadan gelen D_B sinyali 400’den büyük ise namlu yukarı kaldırılır.

while(analogRead(D_B) >= 400)

{namMotAsg();} // while kodu ile sinyal geldiği müddetçe namlu yukarı kaldırılır. namMotDur(); // Sinyal kesildiğinde namlu motoru durdurulur.

sensPos(); // Namlunun yeni açısı okunur.

targetPosNam=angles[1];} // Tespit edilen yeni açı yeni y0 değeri olarak atanır.

else if (stab==HIGH){ // Namlunun stabilizasyonda kalması sağlanır.

namMotYon(updatePid(targetPosNam, angles[1])); // PID fonksiyonu çalıştırılır. Çıkan PWM sonucu namlu motorunun hareketi için girdi olarak alındıktan sonra namlu motoru fonksiyonu çalıştırılır.

} }

// “MPU6050_read” fonksiyonu I2C iletişim protokolünden çoklu bayt okumak için kullanılan genel bir fonksiyondur. Sadece veri okumak için kullanılabilir. Tek bayt okumak için fonksiyon barındırmaz. int MPU6050_read(int start, uint8_t *buffer, int size) // Arduino ile MPU-6050 sensörü arasında iletişim kurmak için gerekli olan I2C protokolü tanımlanır.

{

53 Wire.beginTransmission(MPU6050_I2C_ADDRESS); n = Wire.write(start);

if (n != 1) return (-10);

n = Wire.endTransmission(false); // I2C veri yolunu beklet.

if (n != 0) return (n);

Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true); // Veri okunduktan sonra I2C veri yolu boşaltılır.

i = 0;

while(Wire.available() && i<size) {

buffer[i++]=Wire.read(); }

if ( i != size) return (-11);

return (0); // Hata yok bilgisi kontrol edilir ve geri besleme sağlanır.

}

//“MPU6050_write” fonksiyonu I2C cihazına çoklu bayt yazmak için kullanılan genel bir fonksiyondur.

// Sadece tek register yazılacaksa “MPU_6050_write_reg()” isimli fonksiyon kullanılmalıdır. // Parametreleri:

// start: Başlangıç adresini belirtir (register için tanımlama kullanılır). // pData: Veri yazmak için kullanılan işaretleyicidir.

// size: Yazılacak bayt sayısıdır.

// Tek registera veri yazılacaksa veriye bir işaretleyici kullanılmalıdır ve “size” tek bir bayt olmalıdır. int MPU6050_write(int start, const uint8_t *pData, int size) // Çoklu bayt gönderebilmek için gerekli

olan fonksiyondur. {

int n, error;

Wire.beginTransmission(MPU6050_I2C_ADDRESS);

n = Wire.write(start); // Yazımın yapılacağı başlangıç adresi. if (n != 1)

return (-20);

n = Wire.write(pData, size); // Veri baytları adrese yazılır. if (n != size)

54

error = Wire.endTransmission(true); // I2C veri yolu boşaltılır. if (error != 0)

return (error);

return (0); // Hata yok bilgisi kontrol edilir ve geri besleme sağlanır.

}

// “MPU6050_write_reg” fonksiyonu tek register yazabilmek için kullanılan ilave bir fonksiyondur. “MPU_6050_write()” fonksiyonuna ek olarak çalışan bir pakettir, sadece tek register yazmayı kolaylaştırmak için pratik bir fonksiyondur. Örnek: MPU-6050 sensörünün uyku modundan çıkartılması için sıfır yazılması.

int MPU6050_write_reg(int reg, uint8_t data) {

int error;

error = MPU6050_write(reg, &data, 1); return (error);

55

KAYNAKLAR

1. Teoman ENGİN, Türk Ordusunda Zırhlı Birlikler, Yüksek Lisans Tezi, Kırıkkale, 2007

2. Ufuk SUADİYE, Sıtkı ÖZTÜRK, İsmet KANDİLLİ, Tank Namlu Stabilizasyon Uygulaması, Fırat Üniversitesi Elektrik-Elektronik ve Bilgisayar Sempozyumu, Elazığ, 2011

3. http://www.aselsan.com.tr/content.aspx?mid=119&oid=639, Erişim Tarihi: 23.09.2013

4. Binroth, W., Cornell, G. A., & Presley, R. W., Closed-Loop Optimization Program for the M60A1 Tank Gun Stabilization System, Bendix Research Labs, Southfield Mi, 1975

5. Pastrick, H. L., An Analysis and Simulation of the M60AIE2 Tank Main Gun's Elevation Control System, Army Missile Research Development And Engineering Lab, Redstone Arsenal Al, 1969

6. http://hilmi.trakya.edu.tr/ders_notlari/Otomatik_kontrol/Otomatik_Kontrol_2.pdf, Erişim Tarihi: 19.11.2013

7. Benjamin C.KUO, Otomtik Kontol, Literatür Yayıncılık, İstanbul, 1999

8. Prof.Dr. İbrahim Deniz AKÇALI, Otomatik Kontrol, Karahan Kitabevi, Adana, 2011

9. Türker KARAYUMAK, Modelıng And Stabılızatıon Control Of A Maın Battle Tank, ODTÜ Ankara, 2011

10. http://arduino.cc/en/Main/ArduinoBoardUno, Erişim Tarihi: 05.09.2013 11. http://arduino.cc/en/Guide/Windows, Erişim Tarihi: 10.09.2013

12. http://arduino.cc/en/Reference/HomePage, Erişim Tarihi: 11.09.2013

13. MPU-6000/MPU-6050 Product Specification, Document Number: PS-MPU-

6000A-00, Revision: 3.1, U.S.A., 2011

14. http://playground.arduino.cc/Main/MPU-6050 Erişim Tarihi: 05.09.2013 15. http://www.starlino.com/imu_guide.html, Erişim Tarihi: 11.10.2013 16. http://www.starlino.com/dcm_tutorial.html, Erişim Tarihi: 11.10.2013

17. T.C. Millî Eğitim Bakanlığı, Elektriiiik Elektroniiiik Teknolojiisi ii i i i Elektriiiikli i i i Ev

56

18. http://www.elektrikrehberiniz.com/elektrik-motorlari/dc-motor-nedir-454/, Erişim Tarihi: 05.01.2014

19. http://arduino.cc/en/Main/ArduinoMotorShieldR3, Erişim Tarihi: 15.01.2014 20. L298 Dual Full-Bridge Driver Product Specification, STMicroelectronics, Italy,

2000

21. İsmail ARSLAN, L298 Motor Sürücü Entegresinin Kullanımı, Hunrobotx – Makaleler, Hacettepe Üniversitesi Robot Topluluğu, Ankara, 2009

22. http://www.vstank.com/vspro/product_M1A2_desert/product_M1A2_desert.html, Erişim Tarihi: 12.02.2014

Benzer Belgeler