Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Zelfbouw autonom Nerf Sentry-turret – Slimme Nerf-pistool met stappenmotoren, camera en Arduino

Onderdelen en benodigdheden

OnderdeelAantal
OpenBuilds NEMA 17 Stappenmotor1
DFRobot Stappenmotor met tandwielkast1
DFRobot Stappenmotor Driver (DRV8825 dual board)1
DFRobot Pixy 2 Camera1
Arduino Mega 25601
Ultrasonische sensor HC-SR041
Nerf Nitron pistool1

Benodigde tools en machines

  • 3D-printer (generiek)
  • Soldeerbout (generiek)
  • CNC-freesmachine

Apps en online diensten

  • Arduino IDE
  • Autodesk Fusion 360

Over dit project

Idee

Een paar jaar geleden zag ik een project van een semi-autonome turret die zelf kon vuuren na aansturing. Dat gaf me het idee om een Pixy 2-camera te gebruiken voor doelexherkenning en de Nerf-pistool automatisch te richten, wat vervolgens zelfstandig kan vergrendelen en vuren.

De componenten

De pistol had 'ogen' nodig, dus koos ik de Pixy 2 vanwege de eenvoudige interfacing met de hoofdbord. Als microcontroller gekozen voor Arduino Mega 2560 vanwege de veelheid aan pinnen. Voor twee assen (gieren en kantelen) zijn twee stappenmotoren nodig; DFRobot leverde hun dubbele DRV8825 motor driver bord.

CAD-ontwerp

Begon in Fusion 360 met een canvas van de Nerf-pistool, maakte een vast lichaam. Daarna een platform met lagerondersteuningen voor links/rechts rotatie. Een stappenmotor naast het platform om dit aan te drijven. Voor op/neer kanteling (pitch) werd een lineaire aandrijving ontworpen: een punt op het bewegende blok, een punt aan de achterkant van de pistool, verbonden door een staaf zodat de pistool om zijn centrale as kan kantelen.

Fabricatie van de onderdelen

Bijna alle onderdelen 3D-geprint (twee printers). Het bewegende platform gefabriceerd met CNC-freesmachine: toolpaths gegenereerd in Fusion 360, schijf uitgezaagd uit multiplex.

Montage

Na fabricatie: montagelagerondersteuningen op draaiende schijf. Lineaire pitch-assemblage: 6 mm aluminium stangen en draadstang door de stukken. Tenslotte de Nerf-pistool bevestigen met een staalstang en twee pijlen van aluminium profielen.

Programmeren

Meest uitdagende deel: programmeren. Een projectiel-vurende machine is complex, de wiskunde erachter kan verwarrend. Begon met programma-stroom en logica stap voor stap, met toestanden:

  1. Doel verwerven (acquire target)
  2. Pistool positioneren
  3. Motoren op spoelen (spool up)
  4. Vuren
  5. Motoren afspoelen (wind down)
  6. Terugkeren naar zoekmodus

Doelverwerving: Pixy ingesteld op neon roze objecten als doelen. Pistool beweegt tot doel gecentreerd in Pixy-beeld; afstand van loop naar doel gemeten. Met deze afstand horizontale en verticale afstand berekend via basis trigonometrie. Functie get_angle() berekent benodigde hoek om doel te raken.

Pistool beweegt naar positie, zet motoren aan via MOSFET. Na 5 seconden op spoelen beweegt servomotor de trekker. MOSFET schakelt motoren uit, pistool keert terug naar zoekmodus.

Plezier beleven

Neon roze indexkaart aan muur als doelteken. Programma calibreert en corrigeert hoek voor gemeten afstand. Werkt goed. Video demonstratie beschikbaar.

Code

Schematisch (C/C++)

Upload naar Arduino Mega

#include <math.h>
#include <Arduino.h>
#include "BasicStepperDriver.h"
#include <Servo.h>
#include <Pixy2I2C.h>
// X is pitch, Y is yaw
const int pins[] = {6,7,8,5,4,12}; // MX STEP, DIR, EN, MY STEP, DIR, EN
const int limit_switch = 26, laser_pin = 11, spool_pin = 10, servo_pin = 13, distance_trig = 29, distance_echo = 30;
double velocity = 21.336;
double velocity_squared = 455.225;
float current_angle = 0.0;
float hyp_distance; // afstand van pistool tot doel in meters
#define X_MID 164
#define Y_MID 150
#define DEADZONE 15
#define G 9.8
#define STP_PER_DEG_YAW 3.333
#define STP_PER_DEG_PITCH 184859
#define MICROSTEPS 32
#define RPM 120
#define MOTOR_STEPS_Y 200
#define MOTOR_STEPS_X 1036 // 17.7777 stappen / graad
BasicStepperDriver pitch_stepper(MOTOR_STEPS_X, pins[1], pins[0]);
BasicStepperDriver yaw_stepper(MOTOR_STEPS_X, pins[4], pins[3]);
Servo trigger;
Pixy2I2C pixy;
enum States { ACQUIRE, POSITION, SPOOL, FIRE, WIND_DOWN, RETURN };
States state = ACQUIRE;
void setup() {
  Serial.begin(115200);
  init_pins();
  delay(1000);
  // home_pitch();
  pixy.init();
  Serial.println("Ready...");
}
void loop() {
  switch(state){
    case ACQUIRE:
      acquire_target();
      state = POSITION;
      digitalWrite(laser_pin,HIGH);
      break;
    case POSITION:
      Serial.println("positioning");
      position_gun();
      state = SPOOL;
      break;
    case SPOOL:
      Serial.println("spooling");
      digitalWrite(spool_pin,HIGH);
      delay(5000);
      state = FIRE;
      break;
    case FIRE:
      fire_gun();
      state = WIND_DOWN;
      break;
    case WIND_DOWN:
      Serial.println("winding down");
      digitalWrite(spool_pin,LOW);
      delay(2000);
      state = RETURN;
      digitalWrite(laser_pin,LOW);
      state = ACQUIRE;
      break;
  }
}
void fire_gun(){
  Serial.println("Firing gun!");
  trigger.write(108);
  delay(400);
  trigger.write(90);
  delay(2000);
}
void position_gun(){
  float x, y;
  hyp_distance = ping();
  hyp_distance /= 100;
  while(!hyp_distance){
    hyp_distance = ping();
    hyp_distance /= 100;
  }
  Serial.println(hyp_distance);
  x = cos(current_angle) * hyp_distance;
  y = sin(current_angle) * hyp_distance;
  float target_angle = get_angle(x,y);
  target_angle /= 100;
  Serial.println(target_angle);
  move_pitch(target_angle - current_angle);
  current_angle = target_angle;
}
void acquire_target(){
  int x=0, y=0;
  long steps_taken=0;
  bool lock = false;
  while(!lock){
    pixy.ccc.getBlocks();
    if(pixy.ccc.numBlocks){
      x = pixy.ccc.blocks[0].m_x;
      y = pixy.ccc.blocks[0].m_y;
      Serial.print("Target seen at location X: ");Serial.print(x);Serial.print(", Y: ");Serial.println(y);
      if(x <= (X_MID - DEADZONE)){
        move_yaw(1);
      } else if(x >= (X_MID + DEADZONE)){
        move_yaw(-1);
      } else if(y <= (Y_MID - DEADZONE)){
        pitch_stepper.move(33152);
        steps_taken += 33152;
      } else if(y >= (Y_MID + DEADZONE)){
        pitch_stepper.move(33152);
        steps_taken += 33152;
      } else {
        lock = true;
        Serial.print("Target locked at location X: ");Serial.print(x);Serial.print(", Y: ");Serial.println(y);
        Serial.print("Steps taken: ");Serial.println(steps_taken);
      }
    }
  }
  current_angle = steps_taken / STP_PER_DEG_PITCH;
  Serial.print("Current angle: ");Serial.println(current_angle);
}
void init_pins(){
  pinMode(pins[2],OUTPUT);
  pinMode(pins[5],OUTPUT);
  pinMode(limit_switch, INPUT_PULLUP);
  pinMode(laser_pin, OUTPUT);
  pinMode(spool_pin, OUTPUT);
  pinMode(distance_echo, INPUT);
  pinMode(distance_trig, OUTPUT);
  digitalWrite(pins[2],LOW);
  digitalWrite(pins[5],LOW);
  digitalWrite(laser_pin,LOW);
  digitalWrite(spool_pin,LOW);
  trigger.attach(servo_pin);
  pitch_stepper.begin(RPM, MICROSTEPS);
  yaw_stepper.begin(5, MICROSTEPS);
  trigger.write(90);
}
void move_yaw(float degrees){
  yaw_stepper.move(degrees*STP_PER_DEG_YAW*32);
}
void move_pitch(float degrees){
  current_angle += degrees;
  pitch_stepper.move(degrees*STP_PER_DEG_PITCH);
}
float get_angle(float distance, float height){
  float i = 2 * height * 455.225;
  float j = G * distance * distance;
  i += j;
  j = 9.8 * i;
  i = sqrt(pow(velocity_squared,2) - j);
  return atan((velocity_squared-i) / (G * distance))*(180/PI);
}
float ping(){
  Serial.println("Getting distance...");
  long duration;
  digitalWrite(distance_trig, LOW);
  delayMicroseconds(5);
  digitalWrite(distance_trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(distance_trig, LOW);
  duration = pulseIn(distance_echo, HIGH);
  return duration / 2 / 29.1; // afstand in meters
}
void home_pitch(){
  Serial.println(digitalRead(limit_switch));
  if(!digitalRead(limit_switch)){
    pitch_stepper.rotate(720);
  }
  while(digitalRead(limit_switch)){
    pitch_stepper.move(-32);
  }
  pitch_stepper.rotate(2880*2);
}

Aangepaste onderdelen en behuizingen

Thingiverse Repository: CAD-bestanden op thingiverse.com

Schema's

Schema-afbeelding beschikbaar in origineel.

Productieproces

  1. Raspoulette: Zonnestroom-gevoede Autonome Koeienpoort Systeem Prototype
  2. Simple Pi Robot – Bouw een 2-WD Autonome Rover met Raspberry Pi
  3. Uitgebreide bibliotheek voor bipolaire stappenmotoren met Arduino
  4. Geautomatiseerde Tinder & Bumble Swiper met Arduino UNO en Stappenmotor
  5. Bouw een Autonome Thuisassistent Robot: Complete Onderdelenlijst & Opzetgids
  6. SmartWay: Complete kit voor trilmotor, RGB LED, GPS-module & Arduino MKR Fox 1200 projecten
  7. Lineaire motoren begrijpen: Van elektrische energie naar nauwkeurige lineaire beweging
  8. Servomotoren Uitgelegd: Hoe Ze Werken en Waarom Ze Belangrijk Zijn
  9. Servo vs Stappenmotors: De Moderne Grijze Zone Verhelderd
  10. Stapelmotoren: typen, kenmerken en praktische toepassingen
  11. Geïntegreerde drivers vereenvoudigen high-power steppermotor-ontwerp