亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

DIY 自动追踪奈夫炮塔:基于步进电机、摄像头与 Arduino 的智能发射装置

元器件清单

元件数量备注
OpenBuilds NEMA 17 步进电机1偏航轴驱动
DFRobot 带减速箱步进电机1俯仰轴驱动
DFRobot DRV8825 双路步进驱动板1驱动两个步进电机
DFRobot Pixy2 智能摄像头1识别霓虹粉色目标
Arduino Mega 25601主控板,引脚丰富
HC-SR04 超声波测距模块1测量目标距离
Nerf Nitron 电动发射枪1发射主体

所需工具

软件与在线服务

项目全记录

创意起源

几年前看到一个半自动炮塔项目,启发我用 Pixy2 实现全自动捕获-瞄准-发射。目标颜色设为霓虹粉,便于视觉锁定。

核心组件选型

CAD 设计

在 Fusion 360 中导入 Nerf 枪轮廓图建模,设计带轴承支撑的旋转平台,侧装偏航电机。俯仰机构采用丝杠+光轴线性滑台,一端固定滑块,另端铰接枪尾,实现精准俯仰。

零件制造

绝大多数零件 3D 打印;旋转底盘用 Fusion 360 生成 CAM 刀路,CNC 从胶合板切割。

组装调试

  1. 轴承座安装旋转盘。
  2. 组装俯仰线性机构:穿 6 mm 光轴与丝杠。
  3. 用钢销和铝型材支架固定 Nerf 枪。
  4. 接线:步进驱动板接 Mega 数字口,舵机控制扳机,MOSFET 控制发射电机供电,超声波模块测距,限位开关回零。

固件逻辑(状态机)

状态流转:
ACQUIRE(捕获目标) → POSITION(定位枪口) → SPOOL(发射电机加速 5s) → FIRE(舵机扣扳机) → WIND_DOWN(关电机延时 2s) → RETURN(回初始态)

捕获目标:Pixy2 追踪粉色色块,云台运动直到色块中心落在画面中心死区(±15 像素)内,记录俯仰步数换算当前角度。
定位:超声波测距得斜距,结合当前角度三角函数解算水平/垂直距离,get_angle() 计算抛物线弹道所需仰角(初速 21.3 m/s,重力 9.8),驱动俯仰电机转至目标角度。
发射:MOSFET 导通发射电机 5 秒加速,舵机推杆扣动扳机 400 ms,复位 2 秒后关电机,激光指示灯熄灭,回到捕获状态。

实测效果

墙面贴粉色卡片测试,程序自动标定不同距离仰角,命中率高。附视频演示。

核心代码(Arduino C++)

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

// 引脚定义
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; // m/s
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: position_gun(); state = SPOOL; break;
    case SPOOL: digitalWrite(spool_pin,HIGH); delay(5000); state = FIRE; break;
    case FIRE: fire_gun(); state = WIND_DOWN; break;
    case WIND_DOWN: digitalWrite(spool_pin,LOW); delay(2000); state = RETURN; digitalWrite(laser_pin,LOW); state = ACQUIRE; break;
  }
}

void fire_gun(){
  trigger.write(108); delay(400); trigger.write(90); delay(2000);
}

void position_gun(){
  hyp_distance = ping()/100.0; // 转米
  while(!hyp_distance) hyp_distance = ping()/100.0;
  float x = cos(current_angle) * hyp_distance;
  float y = sin(current_angle) * hyp_distance;
  float target_angle = get_angle(x,y)/100.0;
  move_pitch(target_angle - current_angle);
  current_angle = target_angle;
}

void acquire_target(){
  long steps_taken=0; bool lock=false;
  while(!lock){
    pixy.ccc.getBlocks();
    if(pixy.ccc.numBlocks){
      int x=pixy.ccc.blocks[0].m_x, y=pixy.ccc.blocks[0].m_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; current_angle = steps_taken/STP_PER_DEG_PITCH; }
    }
  }
}

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 deg){ yaw_stepper.move(deg*STP_PER_DEG_YAW*32); }
void move_pitch(float deg){ current_angle+=deg; pitch_stepper.move(deg*STP_PER_DEG_PITCH); }

float get_angle(float dist, float h){
  float i = 2*h*velocity_squared + G*dist*dist;
  float j = G*i;
  i = sqrt(pow(velocity_squared,2) - j);
  return atan((velocity_squared-i)/(G*dist))*(180/PI);
}

float ping(){
  digitalWrite(distance_trig,LOW); delayMicroseconds(5);
  digitalWrite(distance_trig,HIGH); delayMicroseconds(10);
  digitalWrite(distance_trig,LOW);
  long dur = pulseIn(distance_echo,HIGH);
  return dur/2/29.1; // cm
}

void home_pitch(){
  if(!digitalRead(limit_switch)) pitch_stepper.rotate(720);
  while(digitalRead(limit_switch)) pitch_stepper.move(-32);
  pitch_stepper.rotate(2880*2);
}

3D 打印模型

Thingiverse 仓库:项目文件下载

原理图

见项目附件原理图(接线示意)。

制造工艺

  1. Raspoulette:太阳能自主鸡舍门控制系统原型
  2. Simple Pi Robot:用树莓派打造 2WD 自主巡航车
  3. Arduino 通用双极性步进电机控制库——精准控制转速、角度、圈数与方向
  4. Arduino 步进电机自动刷 Tinder/Bumble:小时 800+ 次滑动神器
  5. 自主家庭助理机器人 O'nine - ROS + Alexa 语音控制 + 机械臂 + 麦克纳姆轮全向移动
  6. SmartWay:基于 Arduino MKR Fox 1200 的儿童上学路径监护系统
  7. Arduino 串口控制步进电机旋转台:28BYJ-48 精准定位
  8. 线性电机原理与演进:从电能到精密直线运动的技术演变
  9. 伺服电机深度解析:工作原理、分类与核心价值
  10. 伺服与步进电机:打破认知边界的现代灰色地带
  11. 步进电机:类型、特性与实际应用
  12. 集成驱动器简化大功率步进电机设计