Project tutorial
Fido's Automated Laser Pointer

Fido's Automated Laser Pointer © GPL3+

Want your dog to play while you're gone? Is he getting enough exercise while you're away? Or do you just want your pooch to have more fun?

  • 5,087 views
  • 0 comments
  • 11 respects

Components and supplies

A000066 iso both
Arduino UNO & Genuino UNO
×1
R8326274 01
Raspberry Pi 2 Model B
×1
11026 02
Jumper wires (generic)
×8
Screws
×4
12002 04
Breadboard (generic)
×1
Wi Fi Adaptor Raspberry Pi
Ours plugs into the USB port. It's just used to give the Pi Wi-Fi access.
×1

Necessary tools and machines

3drag
3D Printer (generic)
Used custom 3D printer designed and built by Eric Sarellana. Most 3D printers should work.
Screw Driver

About this project

Luna chasing the automated laser pointer

What are we Making?

Let's get ready to make our very own automated laser pointer (pictured above).  This laser pointer can be activated remotely from your computer.  In this tutorial, we'll be grabbing the software needed to make this work and installing it on the Raspberry PI and Arduino.  We'll also be setting up the IoT service in AWS.  The CAD files are also included so you can 3D print the case.

Slides

The associated slides from my presentation on AWS IoT & Lambda can be found here for reference. They contain additional details about creating a Lambda function and the IoT service.

http://www.slideshare.net/LisaKester/aws-iot-lambda

Getting Started

First, gather all the materials.  There's a listing of them below.

Steps Overview

  •  Install servo program on Arduino
  •  Setup Raspberry Pi
  •   Install ARM 7 libraries
  •   Install pip
  •   Install AWS Cli
  •   Install AWS IoT Node.js SDK
  •  Create Thing on AWS IoT
  •  Create policy
  •  Get certificates
  •  Create configuration.json file
  •  3D print laser device cover and assemble it
  •  Connect the various devices with the jumper wires
  •  Run the main program on the Pi
  •  Send start message with the AWS console

The Arduino Program

Download the source code and open the Arduino IDE from your computer. Install it if you need to. Connect your Arduino via a USB cable to the computer. Then compile and send the program to your computer.

How to setup the Raspberry PI

First, you need to install NodeJS if it isn't already installed. Here's how:

  •  Go to The NodeJS website and download the ARM 7 binaries for linux
  •  Remote into the pi via WinSCP and copy the ARM 7 binaries to the root folder on the pi
  •  Use Putty to terminal into the PI. (You can activate Putty through WinSCP if you point to it in the settings. Then you won't have to setup the login twice).
  •  Install NodeJS: http://blog.wia.io/installing-node-js-v4-0-0-on-a-raspberry-pi/

Install the NodeJS SDK for AWS

  • Download the AWS IoT Node.js SDK.
  •  Set up the SDK using the instructions from GitHub: https://github.com/aws/aws-iot-device-sdk-js#install
  • Download the root-CA.crt from the documentation. You'll need it later.

There's also some good documentation about the configuration.json file in the Certificate Configuration section, but I'll give you an example to work with so you don't have to read it all.

Install AWS Cli

http://docs.aws.amazon.com/cli/latest/userguide/installing.html

You may need to install pip before you install the cli. Here's the command for that:

sudo apt-get install python-pip

Install the aws cli:

sudo pip install awscli

Setup Device on AWS IoT

Create a Thing on AWS IoT

  • Log in to the AWS console
  • Go to the IoT service
  • Click on "Create Resource"
  • Click on "Create a thing"
  • Name it "Laser"

Create a Certificate for your Device

Go to "Create a certificate" and use 1 click to certificate.

Download ALL the certificates that were just created. You can't access some of them after this!

Create a Policy

Go to create policy and enter in the information below.

Click Add Statement and then click Create.

Create configuration.json File

Example:

{
	"host": "A3RFJD6U2VK2IZ.iot.us-east-1.amazonaws.com",
	"port": 8883,
	"clientId": "Laser",
	"thingName": "Laser",
	"caCert": "./lib/keys/rootCA.pem",
	"clientCert": "./lib/keys/a09a5452f3-certificate.pem.crt",
	"privateKey": "./lib/keys/a09a5452f3-private.pem.key"
}
  • Replace the host with the information in the IoT console.  If you go to your "Thing," some details should show up on the right and your should be able to get the host information from there.  
  • ClientId and thingName should be the same - the name you used for your "Thing"
  • The caCert is something you download from the github page for the JavaScript Node IoT SDK.
  • The other two certificates were downloaded when you created your "Thing" earlier.
  • You'll need to access this file when you run the main program JavaScript program.

3D Print the Laser Case

You'll need to 3D print the laser case.  The CAD files are in multiple formats so you should be able to print them.  There's a number of pieces.  You can superglue most of them together.  You'll probably need some screws for the servos.

Once you've assembled the case, just snap in the laser.  If you want the laser to stay on (and it's like mine), you can hold down the button and rotate it just until the clasp holds the button down.

Connect the Various Devices with Jumper Wires

The Raspberry Pi connects to the Arduino to send the control signals.  I used pin 11 on the Raspberry Pi.  That hooked up to the Arduino with pin 2.  The servos were connected to the Arduino with pins 9 and 10. 

If you look up the Arduino uno and Raspberry Pi 2, you should be able to find some images of the pins.  Be careful with the Raspberry Pi as you might burn it out if you plug in the wrong wires.  The Arduino is more forgiving.  Additionally, for the servos, there is a bread board between the laser case and the Arduino.  This was used because of the (lack of) available power slots.

Finally, plug the Arduino into the computer via USB (or to a good power source).  If you don't have enough power, the device will die when it starts to move the servos.

Run the Main Program on the PI

Next you need to grab the python script, your certificates, configuration.json file, and the JavaScript program.  Put them all on your Raspberry Pi.  The easiest place to run them from is the example folder for the AWS IoT SDK, because that has all the dependencies already installed and accessible.  Just put them in the same directory as the echo-example.js file.

To run the program, use this command at the command prompt:

 sudo node laserListener.js -F ./lib/keys/configuration.json --thing-name Laser

If the paths are all correct in your configuration.json file, this should setup the laser to receive commands. 

Login to the AWS IoT console again.  Click on your thing, go to the details, and update the state of your thing.  You need to set the state to "on" like this:


Code

Raspberry Pi Script (runLazer.py)Python
This script is used to tell the Arduino to start the layer program. It activates pin 11 by setting it to HIGH. If you want to test the functionality, you can run this on the command line by typing "sudo python runLazer.py". Normally, this script is run automatically via the node JavaScript program I've included.
# Author: Lisa Kester
# Twitter: @injectgeek

# IMPORTANT: This file MUST be named runLazer.py because the other program calls it.

# This python script is used to send a signal to 
# the aduino uno to start running the lazer pointer device.

# Import raspberry pi library so we can access the general purpose IO pins.
import RPi.GPIO as gpio

# Import time so we can delay an action
import time

# This is the pin that the Raspberry Pi uses to tell the Arduino to start moving the lazer.
pin = 11;

# Ignore warnings (optional)
gpio.setwarnings(False);

# Cleanup previous gpio library usage 
gpio.cleanup();

# This specifies the naming convention we're using for the  pins on the raspberry pie.  I'm using plain old numbers.
gpio.setmode(gpio.BOARD);

# Setting up pin 11 to use as an output.  Replace this number if you want to use a different pin.
gpio.setup(pin,gpio.OUT);

# This sends power to pin 11.  It's considered to be in a HIGH state.
gpio.output(pin,True);  

# Wait 5 seconds
time.sleep(5);

# Turn the power back off on pin 11.  That was enough time for the arduino to get a turn on signal from the PI.
gpio.output(pin,False); 
Arduino Servo Program Arduino
This program moves the two servos in the Arduino. To use it, you need to install it onto your Arduino. You also need to hook your servos up to pins 9 and 10 to use the program as is. It also connects to the Raspberry PI via a jumper wire. The PI uses pin 11 and the Arduino uses pin 2 for this connection. If you need to use different pins, just change the pin variables defined in the code. There is one for each servo.
/*
Author: Lisa Kester
Twitter: @injectgeek

This program controls the servos for a lazer pointer IOT device.
Now your dog can chase the lazer pointer without you!

How it works:
This program waits to recieve a HIGH signal from a pin.
When it recieves a the signal change, it triggers 
the servo movement.  It basically moves back and forth
in a loop.

 */

#include <Servo.h> 

// This will control the upper servo for the lazer pointer casing
Servo myservo;

// This will control the lower servo for the lazer pointer casing
Servo myservobase;

// This is the pin I'll be using like an on/off switch.  
// When the PI gives it power, then I want the arduino to move the servo.
const int  buttonPin = 2;    
const int  servoPin = 9;
const int  servoBasePin = 10;

// Variables will change:
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

// The position of the servo
int pos = 0;      

void setup() {
  // initialize the button pin as an input:
  pinMode(buttonPin, INPUT);
  
  // Tell the upper servo object to use the specified pin (servoPin)
  myservo.attach(servoPin); 
  
  // Tell the lower servo object to use the specified pin (servoPin)
  myservobase.attach(servoBasePin); 

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

// This function adds variation to the lazer pointer path by adding pauses in different places.  
// My pooch likes the lazer pointer to pause here and there so she can try to catch it.
void AddPauses(){
      if(pos > 150 && pos < 160 ||  pos > 0 && pos < 10){
        delay(15); 
      }
      if(pos == 180 || pos == 0){
        delay(75);
      }
}

// This returns a position for the lower servo based 
// on the value passed in for the upper servo.  You might need to add
// tape on the bottom of your device so it won't fall over.
int getBasePos(int upperpos){
   if(upperpos > 10 && upperpos < 30){
     return 90;     
   }
   else if(upperpos >= 30 && upperpos < 40){
     return 80;     
   }
   else if(upperpos >= 40 && upperpos < 80){
     return 90;     
   }
   else if(upperpos >= 80 && upperpos < 90){
     return 65;     
   }
   else if(upperpos >= 90 && upperpos < 100){
     return 80;     
   }

  return 90;     
}

// This contains the algorithm to move the lazer pointer.
void runServo(){
  
  // Repeat the lazer pointer path 15 times.
  for (int i = 0; i < 15; i++){  
   
   // Move the lazer pointer from 0 to 180 degrees
   for(pos = 0; pos <= 180; pos += 1)  
    {        
    
      // Add pauses for puppy interest
      AddPauses();
      
      // Move the base
      myservobase.write(getBasePos(pos));
      
      // Move the upper servo
      myservo.write(pos);   
      
      // Make sure the lazer isn't moving too fast for the puppy      
      delay(20);                       
    } 
    // This is the return arc.  The lazer moves from 180 degrees to 0.
    for(pos = 180; pos>=0; pos-=1)     
    {
      myservobase.write(getBasePos(pos));
      AddPauses();      
      myservo.write(pos);              
      delay(15);                       
    } 
  }
}

// The main loop for the arduino.  This is like a main() function.  
// The program starts here and continues forever.
void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed to HIGH, then start moving the servo
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
    runServo();
    
    // Switch the button to low
    digitalWrite(buttonPin, LOW);
    }    
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;

}
Raspberry Pi Lazer Main ProgramJavaScript
This is the main program you need to run for the lazer pointer to work with the cloud. The easiest way to run it, is to install the JavaScript AWS SDK and navigate to the examples. Put this script and the python script in the same folder. You'll also need to setup a configuration.json file with the parameters given to you when you create the device. Additionally, you'll need the three certificates specified in the configuration.json file. I'll include an example configuration.json file so you'll know what those are. Example command to run the program from the command line: sudo node lazerListener.js -F ./lib/keys/configuration.json --thing-name Lazer
/*
* Author: Lisa Kester
* Twitter: @injectgeek

* This file is part of the Lazer Pointer IoT device.  
* It moves a lazer pointer for your dog whenever
* you activate it from the AWS console.

  This file is a modification of the echo-example.js file 
  that comes with the JavaScriptSDK.
*/

/*
 * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

//app deps
const thingShadow = require('..').thingShadow;
const isUndefined = require('../common/lib/is-undefined');
const cmdLineProcess   = require('./lib/cmdline');
const execFile = require('child_process').execFile;

function processTest( args ) {

if (isUndefined( args.thingName ))
{
   console.log( 'thing name must be specified with --thing-name' );
   process.exit(1);
}
//
// The thing module exports the thing class through which we
// can register and unregister interest in thing shadows, perform
// update/get/delete operations on them, and receive delta updates
// when the cloud state differs from the device state.
//
const thingShadows = thingShadow({
  keyPath: args.privateKey,
  certPath: args.clientCert,
  caPath: args.caCert,
  clientId: args.clientId,
  region: args.region,
  reconnectPeriod: args.reconnectPeriod
});

//
// Register a thing name and listen for deltas.  Whatever we receive on delta
// is echoed via thing shadow updates.
//
thingShadows
  .on('connect', function() {
    console.log('connected to things instance, registering thing name');

    thingShadows.register( args.thingName, { persistentSubscribe: true } );
    });

thingShadows 
  .on('close', function() {
    thingShadows.unregister( args.thingName );
    console.log('close');
  });

thingShadows 
  .on('reconnect', function() {
    thingShadows.register( args.thingName, { persistentSubscribe: true } );
    console.log('reconnect');
  });

thingShadows 
  .on('offline', function() {
    console.log('offline');
  });

thingShadows
  .on('error', function(error) {
    console.log('error', error);
  });

thingShadows
  .on('delta', function(thingName, stateObject) {
      console.log('received delta on '+thingName+': '+
                  JSON.stringify(stateObject));
	  thingShadows.update( thingName, { state: { reported: stateObject.state } } );		  
	  
	  // Check to see if the lazer pointer state is on.  It's expecting an object like: { state: 'on'}
	  // NOTE: You'll have to manually switch it to off, then on again.
	  if(stateObject.state.state === 'on'){
		  console.log('Lazer pointer state changed to :' + stateObject.state.state);
		  // Run the lazer pointer program when a delta is recieved		  	  
		  const child = execFile('python', ['runLazer.py'], (error, stdout, stderr) => {
			if (error) {
			  console.log(error);
			}
			console.log(stdout);
		  });
	  }      
  });

thingShadows
  .on('timeout', function(thingName, clientToken) {
      console.warn( 'timeout: '+thingName+', clientToken='+clientToken);
  });
}

module.exports = cmdLineProcess;

if (require.main === module) {
  cmdLineProcess('connect to the AWS IoT service and perform thing shadow echo',
                 process.argv.slice(2), processTest, ' ', true );
}
Configuration.json fileJSON
This is the information passed to the main program. It's the same format as what you'd send to the echo-example.js file. You'll need to replace all the parameters with information from your AWS IoT "Thing." The caCert is something I downloaded externally; I found a download on the Javascript AWS IoT SDK documentation for it. The other certs are given to you when you create the "Thing" in the console.
{
	"host": "A3RFJD6U2VK2IZ.iot.us-east-1.amazonaws.com",
	"port": 8883,
	"clientId": "Lazer",
	"thingName": "Lazer",
	"caCert": "./lib/keys/rootCA.pem",
	"clientCert": "./lib/keys/a09a5452f3-certificate.pem.crt",
	"privateKey": "./lib/keys/a09a5452f3-private.pem.key"
}

Custom parts and enclosures

Lazer Pointer Casing
These are the 3D modeled files that are assembled to create the lazer pointer housing. They come in multiple formats to make it easier to print.
toy.rar

Comments

Similar projects you might like

How to Make a Cat Laser Pointer

Project tutorial by circuito.io team

  • 2,229 views
  • 3 comments
  • 6 respects

Leap Motion Laser Tanks!

Project tutorial by Sean McCormick

  • 8,831 views
  • 5 comments
  • 47 respects

Laser Pointer Panther Tank

Project tutorial by Arduino “having11” Guy

  • 5,535 views
  • 1 comment
  • 12 respects

WW2 Tank Laser Tag Sherman & Panther

Project tutorial by Arduino “having11” Guy

  • 16,909 views
  • 1 comment
  • 57 respects

Arduino Laser Tripwire

Project tutorial by Ian Cumming

  • 14,612 views
  • 9 comments
  • 47 respects

Automated Garden

Project tutorial by Thomas sxt

  • 19,953 views
  • 15 comments
  • 67 respects
Add projectSign up / Login