工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

DIY自律型ナーフセントリーガン:ステッピングモーター、カメラ、Arduinoでスマートナーフガンを自作

部品と用品

部品数量
OpenBuilds NEMA 17 ステッピングモーター1
DFRobot ギアボックス付きステッピングモーター1
DFRobot ステッピングモータードライバー (DRV8825デュアル)1
DFRobot Pixy 2 カメラ1
Arduino Mega 25601
超音波距離センサー HC-SR041
Nerf Nitron ガン1

必要工具・機械

アプリ・オンラインサービス

プロジェクト概要

アイデア

数年前、自動照準・発射する半自律型タレットのプロジェクトを見て、Pixy 2カメラでターゲットを捕捉し、ナーフガンを自動照準・ロックオン・発射する完全自律化を思い立ちました。

コンポーネント選定

「目」としてPixy 2を採用(メインボードとのインターフェース容易)。マイコンはピン数豊富なArduino Mega 2560。ヨー(水平)とピッチ(垂直)の2軸制御にステッピングモーター2台必要。DFRobotからデュアルDRV8825ドライバーボード提供を受けました。

CAD設計 (Fusion 360)

ナーフガンのキャンバス画像を読み込みソリッドモデル化。ガン搭載用プラットフォームにベアリング支持を設け左右回転(ヨー)可能に。隣にステッピングモーター配置し駆動。ピッチ(上下)駆動はリニアドライブ機構:可動ブロックとガン後部をロッド連結、ガン中心軸でピボットさせる設計。

部品製作

ほぼ全パーツを3Dプリント(2台のプリンターで作成)。可動プラットフォームはFusion 360でCNCルーター用ツールパス生成、合板からディスク切削。

組み立て

ベアリング支持を回転ディスクに取付。リニアピッチアセンブリ:6mmアルミロッドとネジロッドをパーツに通し組立。ナーフガン本体をスチールロッドとアルミ押出柱2本で固定。

プログラミング

最も難易度高い部分。投射兵器の物理計算は複雑。ステートマシンでロジック構築:

  1. ターゲット捕捉
  2. ガン位置決め
  3. 発射モータースプールアップ
  4. 発射
  5. モーターワインドダウン

捕捉:Pixy 2をネオンピンク物体追跡設定。ガン移動でターゲットを画面中央に。超音波センサーで銃口-ターゲット距離測定。三角関数で水平・垂直距離算出。get_angle()関数で必要仰角計算。ガン移動、MOSFETで発射モーターON。5秒スプールアップ後、サーボでトリガー引く。MOSFET OFF、捜索モード復帰。

実験と遊び

壁にネオンピンクインデックスカード貼り精度テスト。距離に応じ角度校正し良好な命中。動画で動作確認可能。

ソースコード (Arduino Mega用)

#include <math.h>
#include <Arduino.h>
#include "BasicStepperDriver.h"
#include <Servo.h>
#include <Pixy2I2C.h>

// X=ピッチ, Y=ヨー
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;
const int distance_trig = 29, distance_echo = 30;

double velocity = 21.336;
double velocity_squared = 455.225;
float current_angle = 0.0;
float hyp_distance;

#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

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);
  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; // 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);
}

カスタムパーツ・エンクロージャ

ThingiverseリポジトリでCADファイル公開中。

回路図

回路図画像参照。

製造プロセス

  1. Raspoulette:太陽光発電自律コープドアシステムのプロトタイプ
  2. シンプルPiロボット - Raspberry Piで2WD自律ローバーを構築
  3. Arduino用バイポーラステッピングモーターライブラリ – 産業グレードの制御機能
  4. ArduinoとステッピングモーターでTinder/Bumbleを自動スワイプする装置
  5. 自律型ホームアシスタントロボット「O'nine」の構築 – ROS、Alexa、ロボットアーム完全ガイド
  6. SmartWay: GPS・振動モーター・RGB LED・Arduino MKR Fox 1200で子供の通学を見守り
  7. リニアモーター理解:電気エネルギーから精密直線運動へ
  8. サーボモーターの仕組みと重要性
  9. サーボモーター vs ステッピングモーター:現代のグレーゾーンを明確にする
  10. ステッピングモーター:種類、特性、実用応用
  11. 統合ドライバーが高出力ステッピングモーター設計を簡素化