Başa dön
Arduino ve Raspberry Pi ile Tank Yapımı

Arduino ve Raspberry Pi ile Tank Yapımı (Kablosuz)

 

Donanım Bileşenleri

 

Yazılım Uygulamaları

 

El Aletleri ve İmalat Makineleri

 

Giriş

Oyun

Oyunun kuralları oldukça basit. Lazer ile rakip tankı vurun (4 sensörden birine lazer tutmalısınız). Her sensör bir mürettebat üyesine karşılık gelir: nişancı, sürücü, komutan ve makineli tüfek. Mürettebatın 4’de 3’ü vurulursa kaybedersiniz. Bir nişancı veya şoför vurulursa, yeterli mürettebatınız varsa bunlar değiştirilebilir. Vurulma durumları için cezalar mevcut. Nişancı vurulursa, tank 6 saniye ateşleyemez ve yeniden yükleme süresi artar. Ayrıca, sürücü vurulursa, tankın hızını azaltır ve 6 saniye boyunca hareketi önler. Bu oyun kuralları War Thunder video oyunu na dayanmaktadır.

Tank Şasesi Yapımı

Şasi, braket eklemenize izin veren birçok montaj deliğine sahiptir. İki motor ve tekerleğin yanı sıra güç eklemek için iki set tekerleği ile birlikte geliyor. Montaj kolay ve basittir. Tek yapmanız gereken, her motora ve tekerlek topuna 2 vida takmak.

Sonra, 3 mm vida ve somunu kullanarak kasaya vidalanan 8 çubuk destekçiyi 3D yazıcıda yazdırdım. Her çift, bir pirinç çubuğun bunları kapsamasına izin vererek şasi boyunca sıralanır.

Tankların Tasarımı

Fusion 360 ile tank gövdelerini tasarladım. Sonra temel katı modelin etrafında parçalar tasarladım. Bu işlem, M4A3E8 Sherman Tank’ı oluşturmak için bir kez daha yapıldı.

Tank Elektroniği Bölüm 1: Motorlar ve Beyinler

Tankları oluşturmanın en zorlu adımı elektronik bölümdür.

Raspberry Pi, motorları sürmek için gerekli akımı ve voltajı sağlayamaz, bu nedenle bir motor sürücüsü gereklidir. Raspberry Pi sadece 4 pim kullandığı için boyutu ve sadeliği ön planda tutarak L293d H-köprü sürücüsünü seçtim. Bu sürücü, motorlara 1 amper 12v’ye kadar güç sağlayabilir ve mükemmel bir seçimdir.

İkincisi, onlara çarpan ışık miktarına göre bir değer veren 4 LDR’yi (değişken ışık dirençleri) ölçmek için bir yola ihtiyacım vardı. Düşük miktarda ışık direnci arttırır ve yüksek miktarda ışık da azaltarak dijital olarak okunmasını imkansız hale getirir. Raspberry Pi’nin ADC girişi yok, bu yüzden bunu yapabilen bir çip bulmak zorunda kaldım. ADS1115, I2C üzerinden iletişim kuran şaşırtıcı, küçük, 4 kanallı bir analogdan dijitale dönüştürücüdür ve sadece birkaç kablo kullanır. Bu da birkaç değerli GPIO pimini boşa çıkarır. ADS1115, Adafruit tarafından yapılan ve dört kanalın her birinin ayarlanmasına ve okunmasına izin veren bir Python kütüphanesine de sahiptir. İsteğe bağlı olarak, ses efektleri istiyorsanız bir lm386n ekleyebilirsiniz. Sadece IN 18 pinini ve VCC‘yi + 5v’ye bağlayın.

Tank Elektroniği Bölüm 2: Güç ve Servolar

Aklımda “Buna nasıl güç verebilirim?” sorusu vardı. 2 servo, bir Raspberry Pi Zero, bir ADC, bir lazer diyot ve 2 motor için güç sağlamak zor iş. İlk önce her bileşeni voltaj gereksinimlerine ayırdım. Pi, lazer ve servolar için 5V; ADC ve servo sürücü için 3.3V; Motorlar için 6 ~ 12V.

5V regülatörler, tüm 5V bileşenlerine güç sağlamak için yeterli akım (3 amper) sağlayabilir. Bir güç kaynağı için, 30C 11.7V sağlayabilen ve 1800mAh kapasiteye sahip genel bir RC LiPo pil kullanmayı seçtim.

Artık güç ve güç dağıtımı yapıldığından servo sürüşüne geçebiliriz. İlk başta servoları doğrudan Pi’nin GPIO pinlerinden kontrol etmek için GPIO PWM sınıfını kullanmaya çalıştım, ancak bir mikroişlemci özel bir çipin aksine gerekli tam zamanlamaları sağlayamıyor. Bu yüzden aramaya gittim ve sonunda bir I2C 16 kanal servo sürücüsü olan PCA9685’e, tam da ihtiyacım olana rastladım. Ayrıca I2C protokolünü kullandığından, ADS1115’e kolayca bağlayabilirim.

Adafruit ayrıca her kanalı belirli bir nabızla kontrol eden yararlı bir kütüphane sağlar.

ADS1115 kütüphanesini burada bulabilirsiniz: PYTHON ADS1x15

PCA9685 kütüphanesini burada bulabilirsiniz: PYTHON PCA9685

Programlama

Programlara ihtiyaç duyan iki pano vardır. Biri Python kullanan bir Raspberry Pi, diğeri C ++ kullanan bir Arduino Nano. Python kodu için, motor ve servo kurulumunu işleyen, seri veri alan ve tankın tüm elektroniklerini kontrol eden bir sınıf oluşturdum. Geriye kalan tek şey GPIO pin numaralarını girip seri arabelleği güncelleyen bir ana dosya oluşturmaktı. Denetleyicinin beyni, bir Arduino Nano, dört analog giriş alır, I2C verileri gönderir ve 4 LED’i kontrol eder.

Yeniden yükleme hızlarını ve lazer ateşleme süresini kontrol etmenin yanı sıra analog verilerin ne sıklıkta örnekleneceğini kontrol etmek için Arduino Zamanlayıcı kitaplığını kullanır. Daha fazlasını görmek için ekteki kodu görüntüleyin.

 

Kurulum

Her tankı ve denetleyiciyi titizlikle inşa ettikten sonra, nihayet onları bir oyunda kullanma zamanı geldi. Önce her tankı ilgili denetleyiciyle eşleştirmek zorunda kaldım. Bunu yapmak için, bir denetleyiciyi açtım ve daha sonra bluetoothctl yazdıktan sonra default-agent yazdım ve ardından denetleyici HC-05 olarak göründükten sonra scan yazdım ve MAC_ADDR çiftine girdim; burada MAC_ADDR HC-05 modülü için ortaya çıkan MAC adresidir. PIN’in eşleşmesini isteyecektir. Şifre 1234’tür. Şimdi sadece exit yazın ve ardından programı önce sudo rfcomm bind / dev / rfcomm1 MAC_ADDR yazarak çalıştırın. Bu, Bluetooth bağlantı noktasını bir seri bağlantı noktasına bağlar ve pyserial kütüphanesinin HC-05’ten veri okumasına izin verir.

 

Oynanış

Ve bu kadar! Bu eğlenceli lazer oyunu için hepinize teşekkür etmek istiyorum. Eğlenceli bir makale oldu.

Özel Parçalar ve Muhafazalar

Thingiverse Bağlantısı

 

Şemalar

having11 / tankları-in-gerçek yaşam

Zip olarak indir

 

KOD

Robot Kodu Python Sınıfı (Python)        İndir

from __future__ import division
import RPi.GPIO as GPIO
from time import sleep
from serial import Serial
import json

import Adafruit_PCA9685

class Car(object):

    def __init__(self, BT_Port, laser_pin):
        GPIO.setmode(GPIO.BCM)
        self.ser = Serial(BT_Port, baudrate=9600,timeout=0)
        self.laser_pin = laser_pin
        self.laser_state = False
        GPIO.setup(self.laser_pin, GPIO.OUT)
        
    def configMotors(self, mL1, mL2, mR1, mR2, invertLR=False):
        self.motor_array = [mL1, mL2, mR1, mR2]
        self.invert = invertLR
        for pin in self.motor_array:
            GPIO.setup(pin, GPIO.OUT)
        #self.motor_pwm.append(GPIO.PWM(pin, 490))
        self.motorL1_pwm = GPIO.PWM(mL1, 100)
        self.motorL2_pwm = GPIO.PWM(mL2, 100)
        self.motorR1_pwm = GPIO.PWM(mR1, 100)
        self.motorR2_pwm = GPIO.PWM(mR2, 100)
        self.motorL1_pwm.start(0)
        self.motorL2_pwm.start(0)
        self.motorR1_pwm.start(0)
        self.motorR2_pwm.start(0)
        
    def configServos(self):
        self.pwm = Adafruit_PCA9685.PCA9685()
        self.servo_min = 150
        self.servo_max = 600
        self.pwm.set_pwm_freq(60)
        
    def deg_to_pulse(self, degree):
        pulse = (degree - 0) * (self.servo_max - self.servo_min) / (180 - 0) + 150 
        print('Pulse: '+str(pulse))
        return int(pulse)
        
    def receive_command(self):
        self.cmd = ""
        if  self.ser.inWaiting():
            self.cmd = self.ser.readline()
            if self.cmd != None:
                try:
                    data = self.cmd.decode('utf-8')
                    data = json.loads(data.strip())
                    print data
                    if data != "":
                        return data
                    else:
                        return ""
                except ValueError:
                    pass
        #except IOError:
            #pass
            
    def turn_wheel(self, motor1, motor2):
            if self.invert:
                temp = motor1
                motor1 = motor2
                motor2 = temp
            motor1 = (motor1 / 2)
            motor2 = (motor2 / 2)
            if motor1<0:
                self.motorL2_pwm.ChangeDutyCycle(motor1*-1)
                self.motorL1_pwm.ChangeDutyCycle(0)#make positive if negative
            else:
                self.motorL1_pwm.ChangeDutyCycle(motor1)
                self.motorL2_pwm.ChangeDutyCycle(0)
        
            if motor2<0: self.motorR2_pwm.ChangeDutyCycle(motor2*-1) self.motorR1_pwm.ChangeDutyCycle(0)#make positive if negative else: self.motorR1_pwm.ChangeDutyCycle(motor2) self.motorR2_pwm.ChangeDutyCycle(0) def move_turret(self, turret_deg, barrel_deg): self.pwm.set_pwm(0, 0, self.deg_to_pulse(turret_deg)) self.pwm.set_pwm(1, 0, self.deg_to_pulse(barrel_deg)) def fire_laser(self, state): GPIO.output(self.laser_pin, state) def update(self): #Run to make the robot work self.json_obj = self.receive_command() print self.json_obj try: if "motor" in self.cmd: if self.json_obj["motor"] != None: val1 = self.json_obj["motor"][0] # if val1 > 0:
                 #    val1 += 10
                    val2 = self.json_obj["motor"][1]
            # if val2 <0:
            #   val2 += 4
                    self.turn_wheel(val1, val2)
            elif "shoot" in self.cmd:
                self.laser_state = self.json_obj["shoot"]
                self.fire_laser(self.json_obj["shoot"])
            elif "turret" in self.cmd:
                val1 = self.json_obj["turret"][0]
                val2 = self.json_obj["turret"][1]
                self.move_turret(val1, val2)
        
        except TypeError:
            pass
    sleep(.01)

Robot Kodu Python Main (Python) İndir       

import car

bt_port = "/dev/rfcomm3"
laser_pin = 20
rc_car = car.Car(bt_port, laser_pin)

rc_car.configMotors(6,5,19,13, invertLR=True)
rc_car.configServos() #Turret drive servo, barrel servo

while 1:
    rc_car.update()

 

Denetleyici Kodu (C / C ++)  İndir     

#include "Timer.h"
#include 
#include 

int JS_VALS[2] = {};
int JS_VALS_R[2] = {};

const int JS_PINS[4] = {A0, A1, A2, A3}; //L_X, L_Y, R_X, R_Y
const int led_pins[4] = {4,5,6,7};

const int button_pin = 3;
const int deadzone = 8;
bool laser = false;

const int servo_limits[5] = {0, 180, 50, 95, 75}; //Left, Right, Lower, Upper, Middle limits for the turret
int turret_positions[2] = {90, servo_limits[4]}; //Initial positions

unsigned long last_time = 0;
long motor_delay = 30; //Delay 30 ms between motor control polls
long turret_delay = 150; //Delay 150 ms between turret control polls

long reloadSpeed = 8000;
float driveSpeed = 1.0;
int crewValues[4] = {3,3,2,1};
bool crewLeft[4] = {true,true,true,true};
int crewLeftNum = 4;
int reloadTimer, crewReplaceTimer, fireTimer;
bool is_reloaded= true;
bool can_move = true;
bool can_fire = true;

LiquidCrystal_I2C lcd(0x3F, 16, 2);

Timer t;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
lcd.init();
lcd.backlight();
lcd.print("Begin fighting!");
delay(2000);
lcd.clear();
lcd.home();
pinMode(button_pin, INPUT_PULLUP);
Serial.println("Begin");

t.every(motor_delay, control_motors);
t.every(turret_delay, control_turret);
t.every(50, checkButton);
for(int i=0;i<4;i++){
    pinMode(led_pins[i], OUTPUT);
}
updateCrew();

}

void loop() {
  /*control_motors();
  control_turret();
  delay(150);*/
  t.update();
  if(Serial.available()>0){
      String data = Serial.readStringUntil('\n');
      if(data=="HG"){
          crewLeft[0] = false;
          crewLeftNum -= 1;
          reloadSpeed += 2000;
          can_fire = false;
          crewReplaceTimer = t.after(6000, replaceCrew);
      }
      else if(data=="HD"){
          crewLeft[1] = false;
          crewLeftNum -= 1;
          driveSpeed -= .2;
          can_move = false;
          crewReplaceTimer = t.after(6000, replaceCrew);
      }
      else if(data=="HC"){
          crewLeft[2] = false;
          crewLeftNum -= 1;
          driveSpeed -= .1;
          reloadSpeed += 1500;
          crewReplaceTimer = t.after(6000, replaceCrew);
      }
      else if(data=="HM"){
          crewLeft[3] = false;
          crewLeftNum -= 1;
          crewReplaceTimer = t.after(6000, replaceCrew);
      }
      updateCrew();
  }
  if(crewLeftNum<=1){
      lcd_clear();
      lcd.print("You lose");
      while(1);
  }
}

void checkButton(){
    if(digitalRead(button_pin)==0){
        fire_laser();
    }
}

void replaceCrew(){
    if(crewLeft[0]==false){
        if(crewLeft[2]==true){
            crewLeft[2] = false;
            crewLeft[0] = true;
            can_fire = true;
        }
        else if(crewLeft[3]==true){
            crewLeft[3] = false;
            crewLeft[0] = true;
            can_fire = true;
        }
    }
    else if(crewLeft[1]==false){
        if(crewLeft[2]==true){
            crewLeft[2] = false;
            crewLeft[1] = true;
            can_move = true;
        }
        else if(crewLeft[3]==true){
            crewLeft[3] = false;
            crewLeft[1] = true;
            can_move = true;
        }
    }
    updateCrew();
    t.stop(crewReplaceTimer);
}

void updateCrew(){
    for(int i=0;i<4;i++){
        digitalWrite(led_pins[i],crewLeft[i]);
    }
}

void lcd_clear(){
    lcd.clear();
    lcd.home();
}

void fire_laser(){
  if(is_reloaded){
      if(can_fire){
        lcd.clear();
        lcd.print("Firing laser");
        is_reloaded = false;
        String json_string = "{\"motor\":[" + String(0)+","+String(0)+"]}"; //Stop tank before firing
        Serial.println(json_string);
        laser = true;
        fireTimer = t.after(2000, stopLaser);
        
      }
    }
}

void stopLaser(){
    t.stop(fireTimer);
    laser = false;
    lcd_clear();
    lcd.print("Reloading");
    reloadTimer = t.after(reloadSpeed, reloadGun);
}

void reloadGun(){
    lcd_clear();
    lcd.print("Reloaded");
    is_reloaded = true;
    t.stop(reloadTimer);
}

void control_motors(){
  JS_VALS[0] = analogRead(JS_PINS[0]);
  JS_VALS[1] = analogRead(JS_PINS[1]);
  int x = map(JS_VALS[0], 0, 1023, -50, 50);
  x = constrain(x, -100, 100);
  int y = map(JS_VALS[1], 0, 1023, -50, 50);
  y = constrain(y, -100, 100);
  int motor1 = x+y;
  int motor2 = y-x;
  motor1 = constrain(motor1, -100, 100);
  motor2 = constrain(motor2, -100, 100);
  if(abs(motor1) <= deadzone){
    motor1 = 0;
  }
  if(abs(motor2) <= deadzone){
    motor2 = 0;
  }
  
  motor1 = int(float(motor1)*driveSpeed);
  motor2 = int(float(motor2)*driveSpeed);
  
  if(can_move==false){
      motor1 = 0;
      motor2 = 0;
  }
  
  String json_string = "{\"motor\":[" + String(motor1)+","+String(motor2)+"]}";
  Serial.println(json_string);
  String json_string2;
  if(laser){
    json_string2 = "{\"shoot\":1}";
    Serial.println(json_string2);
  }
  else if(!laser){
    json_string2 = "{\"shoot\":0}";
    Serial.println(json_string2);
  }
}

void control_turret(){
  JS_VALS_R[0] = analogRead(JS_PINS[2]); //Get X values
  JS_VALS_R[1] = analogRead(JS_PINS[3]); //Get Y values
  int x = map(JS_VALS_R[0]+10, 0, 1023, 5, -5);
  x = constrain(x, -5, 5); //Catch outliers
  int y = map(JS_VALS_R[1], 0, 1023, 2, -2);
  y = constrain(y, -2, 2);

  turret_positions[0] += x;
  turret_positions[1] += y;

  if(turret_positions[0] <= servo_limits[0]){
    turret_positions[0] = servo_limits[0];
  }
  else if(turret_positions[0] >= servo_limits[1]){
    turret_positions[0] = servo_limits[1];
  }
  if(turret_positions[1] <= servo_limits[2]){
    turret_positions[1] = servo_limits[2];
  }
  else if(turret_positions[1] >= servo_limits[3]){
    turret_positions[1] = servo_limits[3];
  }
  
  String json_string = "{\"turret\":[" + String(turret_positions[0])+","+String(turret_positions[1])+"]}";
  Serial.println(json_string);
  
}

 
 

Hepsi bu kadar. Umarım makalemizi beğenmiş ve yeni bir şeyler öğrenmişsinizdir.

Memnun kaldıysanız aşağıda bulunan “yukarı ok” işaretine tıklayarak +1 puan verebilirsiniz. 

Diğer Güncel Arduino Projeleri için BURAYA TIKLAYABİLİRSİNİZ.

Sizde Robotlara ve Maker’lığa Meraklıysanız Robotik Marketimiz ROBOCOMBO‘yu Ziyaret Edebilirsiniz.

 

Robot El Yapımı – İlginç Arduino Projeleri

Videodaki Robot El Ürünümüzü Satın Almak İsterseniz Bağlantıya Göz Atabilirsiniz.

Okuduğunuz İçin Teşekkürler.

 

Kaynak: dfrobot.com/blog-1378.html