Little_french_kev
Published © GPL3+

Bluetooth Nerf Turret

Blast your enemies from a safe distance!

IntermediateFull instructions provided10 hours20,421

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
HC-05 Bluetooth module
×1
LM2596 buck converter
×1
MG-90s servos
×3
type 130 dc motors
×2
FR207 rectifier diode
×1
RFP30N06LE mosfet
×1
2.1x5.5mm jack plug
×1
resistors 10kΩ
×1
resistors 330Ω
×1
resistors 680Ω
×1
M2x10 self taping screws
×30
M5*20 countersunk screw
×4
dupont connectors
×15
1.5mm metal rod
×1
wires
×1
heatshrink tubing
×1
20mm rubber band
×1
9V power supply (2.5 amps minimum)
×1

Software apps and online services

Windows 10
Microsoft Windows 10

Hand tools and fabrication machines

screwdriver
wire stripper
pliers
soldering iron
multimeter
crimping tool
3D printer

Story

Read more

Schematics

wiring main diagram

Here is the main wiring diagram .
The wiring is divided small sectionS linked together using dupont connectors . This is for ease of assembly .

HC-05 Bluetooth module wiring

Here is the HC-05 Bluetooth wiring .
This piece of wiring include a voltage divider to allow the 5V coming out of the arduino to be stepped down to about 3.3V for the HC-05 Receiver pin .

Code

Arduino code

Arduino
code to upload to the arduino . The code remain the same whether you choose to control the turret via the android app or a PC .
#include <Servo.h>

//-----Declare servos and variables
Servo recoil_servo;
Servo pan_servo;
Servo tilt_servo;

const byte pan_limit_1 = 0;
const byte pan_limit_2 = 180;
const byte tilt_limit_1 = 65;
const byte tilt_limit_2 = 180;
const byte recoil_rest = 180;    // Angle of the servo when at rest
const byte recoil_pushed = 125;  // Angle the servo need to reach to push the dart

//-----Variables related to serial data handling
byte byte_from_app;
const byte buffSize = 30;
byte inputBuffer[buffSize];
const byte startMarker = 255;
const byte endMarker = 254;
byte bytesRecvd = 0;
boolean data_received = false;

//-----Variable related to motor timing and firing
bool is_firing =  false;
bool can_fire =  false;
bool recoiling = false;

unsigned long firing_start_time = 0;
unsigned long firing_current_time = 0;
const long firing_time = 150;

unsigned long recoil_start_time = 0;
unsigned long recoil_current_time = 0;
const long recoil_time = 2 * firing_time;

const byte motor_pin =  12;
boolean motors_ON = false;

//8===========================D

void setup()
{
  //-----define motor pin mode
  pinMode(motor_pin, OUTPUT);
  digitalWrite(motor_pin, LOW);

  //-----attaches servo to pins
  recoil_servo.attach(9);
  pan_servo.attach(10);
  tilt_servo.attach(11);

  //-----starting sequence
  recoil_servo.write(recoil_rest);
  pan_servo.write(90);
  delay(1000);
  tilt_servo.write(105);


  Serial.begin(9600);  // begin serial communication
}

//8===========================D

void loop()
{
  getDataFromPC();
  set_motor();
  if (data_received) {
    move_servo();
    set_recoil();
    set_motor();
  }
  fire();
}

//8===========================D

void getDataFromPC() {

  //expected structure of data [start byte, pan amount, tilt amount, motor on, firing button pressed, end byte]
  //start byte = 255
  //pan amount = byte between 0 and 253
  //tilt amount = byte between 0 and 253
  //motor on = 0 for off - 1 on
  //firing button pressed = 0 for not pressed - 1 for pressed
  //end byte = 254

  if (Serial.available()) {  // If data available in serial

    byte_from_app = Serial.read();   //read the next character available

    if (byte_from_app == 255) {     // look for start byte, if found:
      bytesRecvd = 0;                   //reset byte received to 0(to start populating inputBuffer from start)
      data_received = false;
    }

    else if (byte_from_app == 254) {    // look for end byte, if found:
      data_received = true;                // set data_received to true so the data can be used
    }

    else {                            // add received bytes to buffer
      inputBuffer[bytesRecvd] = byte_from_app;     //add character to input buffer
      bytesRecvd++;                                // increment byte received (this act as an index)
      if (bytesRecvd == buffSize) {    // just a security in case the inputBuffer fills up (shouldn't happen)
        bytesRecvd = buffSize - 1;    // if bytesReceived > buffer size set bytesReceived smaller than buffer size
      }
    }
  }
}

//8===========================D

void move_servo() {
  
  byte pan_servo_position = map(inputBuffer[0], 0, 253, pan_limit_2, pan_limit_1);//convert inputbuffer value to servo position value
  pan_servo.write(pan_servo_position); //set pan servo position
  byte tilt_servo_position = map(inputBuffer[1], 0 , 253, tilt_limit_2, tilt_limit_1); //convert inputbuffer value to servo position value
  tilt_servo.write(tilt_servo_position); //set pan servo position
}

//8===========================D

void set_recoil() {

  if (inputBuffer[3] == 1) {        //if fire button pressed
    if (!is_firing && !recoiling) { //and not already firing or recoiling
      can_fire = true;              //set can fire to true (see effect in void fire())
    }
  }
  else {                  // if fire button not pressed
    can_fire = false;     //set can fire to false (see effect in void fire())
  }
}

//8===========================D

void set_motor() {
  //-----start and stop motors using MOSFET transisitor .

  if (inputBuffer[2] == 1) {                //if screen touched
    digitalWrite(motor_pin, HIGH);          //turn motor ON
    motors_ON = true;
  }
  else {                                   //if screen not touched
    digitalWrite(motor_pin, LOW);          //turn motor OFF
    motors_ON = false;

  }
}

//8===========================D

void fire() { //if motor byte on, turn motor on and check for time it has been on

  if (can_fire && !is_firing && motors_ON) {
    //if (can_fire && !is_firing) {
    firing_start_time = millis();
    recoil_start_time = millis();
    is_firing = true;
  }

  firing_current_time = millis();
  recoil_current_time = millis();

  if (is_firing && firing_current_time - firing_start_time < firing_time) {
    recoil_servo.write(recoil_pushed);
  }
  else if (is_firing && recoil_current_time - recoil_start_time < recoil_time) {
    recoil_servo.write(recoil_rest);
  }
  else if (is_firing && recoil_current_time - recoil_start_time > recoil_time) {
    is_firing = false;
  }

}

python files

The executable and android app can be found here : https://www.littlefrenchkev.com/bluetooth-nerf-turret

Credits

Little_french_kev

Little_french_kev

2 projects • 60 followers
3D modeller by trade . I got into hardware as a mean to give life to my 3D models . Loving it more and more as I progress!!!!

Comments