Project tutorial

Laser Shootin' Robot © GPL3+

Use a DFRobot MiniQ chassis with Raspberry Pi Zero W to create a robot that can shoot a laser at anything you choose! (Not at eyes, please.)

  • 4,236 views
  • 0 comments
  • 12 respects

Components and supplies

DFRobot MiniQ Chassis
×1
475267 240424 01 front zoom kankcmvqdh
Raspberry Pi Zero Wireless
×1
Ard nano
Arduino Nano R3
×1
Texas instruments l293dne image
Texas Instruments Dual H-Bridge motor drivers L293D
×1
NPN Transistor
×1
5V Regulator 1.5A output
×1
3 Terminal, 2 Position SPDT Switch
×1
61pby065esl  sx679  tnr8syww5d
HC-05 Bluetooth Module
×1
Joystick
×1
1800 mAh LiPo Battery 11.7V
×1

Necessary tools and machines

09507 01
Soldering iron (generic)

Apps and online services

About this project

Introduction

Ever wanted to make a robot? How about one that is controlled via Bluetooth? Still not exciting enough for you? This robot can fire lasers, basically becoming a mobile artillery piece that shoots light! Now you can tease your cat, make a presentation more exciting, and even shine it at people (just not at their eyes please)! This project will document how I went about creating a robot capable of such epic fun!

Video

Parts Needed

DFRobot was generous to me by sending out a couple of their 2WD MiniQ Robot Chassis. These things are great! Each chassis came with 2 50:1 geared motors, nice sturdy tires, and plenty of mounting holes. Next, I got a Raspberry Pi Zero; it is small, yet very capable, due to its on board Wifi and Bluetooth. I also got an Arduino Nano and an HC-05 for the controller. See the BoM for the full list of parts needed.

Assembly

I began by assembling the 2WD MiniQ chassis kit from DFRobot. I slid the wheels onto the motor shafts, then inserted them into brackets and attached them to the chassis. Finally, I added the metal supports.

Now it was time to build the main board. The L293d motor driver got soldered in place, along with wires running to the Raspberry Pi's GPIO pins. Next, I soldered a connector for the battery, as that will provide the main power. After the power source was added, I installed a 5V regulator along with an NPN transistor. The regulator provides the right voltage for the Pi and laser diode, and the transistor allows the Pi to safely control the laser without blowing up.

Motor Control

This was actually one of the trickiest parts of this project. I had to decide the way I should transmit information to drive the wheels. I was faced with two options: tank or arcade drive. Tank drive operates like a.. tank, of course. Left makes right wheel go forwards and the left wheel goes backwards, turning the robot left. Here is a table for movements:

Joystick Position | Left Wheel | Right Wheel
Left | -1 | 1 
Right | 1 | -1
Up | 1 | 1
Down | -1 | -1
Neutral | 0 | 0

But that gives you very limited control. Plus, when working with a large voltage, the robot tends to get zippy. A better option was to use PWM to variably control the motor speeds. Now, it isn't as simple as using an Arduino, there isn't any analogWrite(motor_pin, value) abstraction, which can get frustrating. Luckily, the RPi GPIO library has a PWM class. To use it, I first made each motor pin into an output with GPIO.setup(motor_pin, GPIO.OUT) . Then I made an object for each motor pin with motor_pwm = GPIO.PWM(motor_pin, 100) . Make sure to change the motor_pwm variable name for each object. Now that I had variable motor speeds, could focus on getting the values from the joystick translated into motor values.

The Controller

The basic analog joystick is made of two potentiometers that give a 10-bit value ranging from 0-1023 on the Arduino. I set up the Arduino Nano to take a reading from each analog pin that the joystick was connected to (in my case it was A1 and A2). After that, the code maps x and y to values between -50 and 50, like this:

int x = map(A1_reading, 0, 1023, -50, 50); 
int y = map(A2_reading, 0, 1023, -50, 50); 

Then, I added a constrain call to capture any outliers:

x = constrain(x, -100, 100); 
y = constrain(y, -100, 100); 

Sparkfun recently did a tutorial on how to use an RC controller for DC motors, which was perfect for what I needed. You can find that blog post here. The way to determine the way each motor goes is pretty simple. Just do:

int motor1 = x+y; 
int motor2 = y-x; 

And then:

motor1 = constrain(motor1, -100, 100); 
motor2 = constrain(motor2, -100, 100); 

...to ensure it stays within -100 and 100. And you may be asking, "How do I make it come to a stop?" Well, that is where a deadzone comes into play. By adding this as a global variable:

int deadzone = 10;

...and then:

if(abs(motor1) <= deadzone){ 
   motor1 = 0; 
 } 
 if(abs(motor2) <= deadzone){ 
   motor2 = 0; 
 } 

...you can effectively stop a motor whenever you aren't pushing the joystick. Lastly, I was wondering how to efficiently send this motor data to the Raspberry Pi. It needed to be easily readable and have good decoding support. Then this idea popped into my head: JSON! I could send a string that conveys the motor data to the Pi, then the Pi can decode it into variables, and lastly control the motors accordingly. So I added these lines:

String json_string = "{\"motor\":[" + String(motor1)+","+String(motor2)+"]}";
  Serial.println(json_string); 

which send the motor data as a JSON string, where "motor" is the key, and an array containing the motors values is its value. There is also an interrupt that will send "Fire" to the Pi if the button is pushed. Now for the last part: having fun with it!

Using the Robot

Before I began to use this new machine of light beams, I had to somehow get the HC-05 module talking to the Pi. Here is the condensed version. First, power on the HC-05 and Raspberry Pi, then click on the Bluetooth icon on the Raspberry Pi and pair your HC-05. The password should be: "1234" without the quotes.

On the Raspberry Pi Zero W, enter these commands:

hcitool scan

This will scan for bluetooth devices and return their MAC addresses. Now enter:

sudo rfcomm /dev/rfcomm0 mac_address

...where mac_address is the address of the HC-05. Download the code for this project and transfer the Python files to a directory. REMEMBER THAT DIRECTORY; you will need it soon. Now open up the rc_car_main.py python script with a text editor, and where you see BT_addr , enter in "/dev/rfcomm0". Also, enter in the motor pins for the motors in:

car.config_motors(pin1, pin2, pin3, pin4, invert=False)

Run the script and see if the robot moves the proper way. If it goes left when it should be going right, set invert=False to invert=True .

Have fun with your new laser firing bot!

Code

Controller CodeC/C++
int JS_VALS[2] = {};

const int button_pin = 2;
const int deadzone = 8;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode(button_pin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(button_pin), fire_laser, FALLING);
}

void loop() {
  // put your main code here, to run repeatedly:
  JS_VALS[0] = analogRead(A1);
  JS_VALS[1] = analogRead(A2);
  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;
  }
  //Serial.println("X: "+String(JS_VALS[0])+", Y: "+String(JS_VALS[1]));
  String json_string = "{\"motor\":[" + String(motor1)+","+String(motor2)+"]}";
  Serial.println(json_string);
  delay(30);
}

void fire_laser(){
  String json_string = "{\"shoot\":\"1\"}";
  Serial.println(json_string);
}
Python Robot ClassPython
import RPi.GPIO as GPIO
from time import sleep
from serial import Serial
import json

class Car(object):

	def __init__(self, BT_Port, laser_pin):
		GPIO.setmode(GPIO.BCM)
		self.ser = Serial(BT_Port, baudrate=9600)
                self.laser_pin = laser_pin
                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 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
			
	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 fire_laser(self):
            GPIO.output(self.laser_pin, GPIO.HIGH)
            sleep(2)
            GPIO.output(self.laser_pin, GPIO.LOW)

	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.fire_laser()
            except TypeError:
                pass
Python Robot Main Script (run this one)Python
import car

bt_port = "/dev/rfcomm0"
laser_pin = pin5
rc_car = car.Car(bt_port, laser_pin)

rc_car.configMotors(pin1,pin2,pin3,pin4, invertLR=False)

while 1:
    rc_car.update()
        

Custom parts and enclosures

Battery Platform

Schematics

Robot Schematic
Schematic1 bb r8pynudf5o
Controller Schematic
Controller schematic1 bb nncvdoczdb

Comments

Similar projects you might like

WW2 Tank Laser Tag Sherman & Panther

Project tutorial by Arduino “having11” Guy

  • 15,440 views
  • 1 comment
  • 57 respects

Laser Pointer Panther Tank

Project tutorial by Arduino “having11” Guy

  • 4,801 views
  • 1 comment
  • 10 respects

Otto DIY+ Arduino Bluetooth Robot Easy to 3D Print

Project tutorial by Team Otto builders

  • 48,199 views
  • 117 comments
  • 162 respects

MeArm Robot Arm - Your Robot - V1.0

Project tutorial by Benjamin Gray

  • 19,302 views
  • 3 comments
  • 34 respects

Wolf: Search and Rescue Multi-Terrain Robot

Project tutorial by Husky Mai

  • 7,426 views
  • 3 comments
  • 46 respects

Controlling a Robot with a PlayStation Controller

Project tutorial by Andrew R Gross and Jonathan Gross

  • 2,836 views
  • 0 comments
  • 7 respects
Add projectSign up / Login