Evan Rust
Published © GPL3+

IoT Camera Mover for Less Than $35

Build a machine that can move a camera perfectly using the power of a webpage and even the Google Assistant with Particle.

IntermediateWork in progress3 hours2,479
IoT Camera Mover for Less Than $35

Things used in this project

Hardware components

Photon
Particle Photon
×1
NEMA 17 Stepper Motor
OpenBuilds NEMA 17 Stepper Motor
×1
Driver DRV8825 for Stepper Motors for Theremino System
Driver DRV8825 for Stepper Motors for Theremino System
×1
Stepper Motor Mounting Plate NEMA 17
×1
1/2 inch PVC Pipe 5 feet
×1
1 inch x 4 inch x 4 foot lumber
×1

Software apps and online services

Particle Cloud IDE
IFTTT - Google Assistant Service

Hand tools and fabrication machines

Hacksaw
3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Camera Platform

Schematics

Schematic

Code

Particle Code

C/C++
// This #include statement was automatically added by the Particle IDE.
#include <AccelStepper.h>

void pan(const char *event, const char *data);

AccelStepper pan_stepper(1,2,3); //Driver mode, STEP pin 2, DIR pin 3

#define MIDPOINT 1200

void setup() {
    Particle.subscribe("pan",pan, MY_DEVICES);
    Particle.subscribe("set_accel",accel, MY_DEVICES);
    pinMode(2,OUTPUT);
    pinMode(3,OUTPUT);
    pan_stepper.setMaxSpeed(501);
    pan_stepper.setSpeed(75);
    pan_stepper.setAcceleration(75);
}

void loop() {
    
}

void pan(const char *event, const char *data){
    pan_stepper.setSpeed(String(data).toInt());
    if(int(data)>10){
    pan_stepper.move(MIDPOINT*2);
    pan_stepper.runToPosition();
    delay(3000);
    pan_stepper.move(-MIDPOINT*2);
    pan_stepper.runToPosition();
    }
}

void accel(const char *event, const char *data){
    pan_stepper.setAcceleration(String(data).toInt());
}

Webpage Page

HTML
<!DOCTYPE html>

<head>
	<title>Camera Controller</title>
	<script type="text/javascript" src="//cdn.jsdelivr.net/particle-api-js/5/particle.min.js"></script>
	<script type="text/javascript" src="photon_control.js"></script>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel=stylesheet type="text/css" href="cam_control.css">
</head>
<body>
<div id="sign-in">
	<div id="sign_in_header"><h3>Sign into your Particle account here</h3>
	<img src="https://proxy.duckduckgo.com/iu/?u=https%3A%2F%2Fwww-assets.particle.io%2Fimages%2Flogo.png%3Fmtime%3D20160727114211&f=1" class="logo_img">
	</div>
	<form onsubmit="sign_in(this.user.value,this.pass.value); return false" method="post">
		<br><p class="input_label">Username: </p><input type="text" name="user"><br>
		<p class="input_label">Password: </p><input type="password" name="pass"><br>
	<input type=submit value="Sign in" class="submit_btn"><br>
	<h3 id="success_fail"></h3>
	</form>
</div>
<div id="load_devices" style="visibility: hidden">
	<input type=text id="input_txtbox"><br>
	<button value=0 class="select_btn" onclick="event_publish(this.value);return false">Pan Camera</button>
	<button value=1 class="select_btn" onclick="event_publish(this.value);return false">Set Acceleration</button><br>
	<label for="clear_chk">Keep Value</label>
	<input type="checkbox" id="clear_chk" checked="false">
			
</div>


</body>

Webpage Javascript

JavaScript
var particle = new Particle();
var token;

var event_names = ["pan","set_accel"];

function sign_in(user, pass){
	particle.login({username: user, password: pass}).then(
	function(data){
		token = data.body.access_token;
		var status = document.getElementById("success_fail");
		status.innerHTML = "Success";
		document.getElementById("load_devices").style.visibility = "visible";
	}, function(err){status.innerHTML="Login failed, try again"}
	);
}

function event_publish(move_setAccel){
	var data_val = document.getElementById("input_txtbox").value;
	var publishEventPr = particle.publishEvent({name: event_names[move_setAccel],data: data_val,isPrivate: true, auth:token});
	publishEventPr.then(
	function(data){
		if(data.body.ok){console.log("event published")}
	}, function(err){console.log("Failed"+err)}
	);
	if(document.getElementById("clear_chk").checked==false){
		document.getElementById("input_txtbox").value = "";
	}
}

Webpage CSS

CSS
*{
	box-sizing: border-box;
	
}

body{
	font-family: arial, sans-serif;
}

.logo_img{
	width: 10%;
	height: 10%;
	padding-top: 3%;
	padding-left: 4px;
}

#sign_in_header h3, #sign_in_header img{
	float: left;
}

#sign-in{
	width: 30%;
	float: left;
	margin-bottom: 10px;
	justify-content: center;
}

.input_label{
	text-align: center;
	margin: 5px;
}

#sign-in input{
	width: 100%;
	padding: 12px 20px;
	margin: 8px 0;
	box-sizing: border-box;
}

.submit_btn{
	background-color: #f4f4f4;
	border: 2px solid black;
	color: black;
	display: inline-block;
	font-size: 15px;
	border-radius: 4px;
	width: 100%;
}

.select_btn{
	background-color: #f4f4f4;
	border: 2px solid black;
	color: black;
	display: inline-block;
	font-size: 20px;
	border-radius: 2px;
	height: 40px;
	width: 30%;
}

.select_btn:hover{
	cursor: pointer;
	background-color: white;
}

label{
	font-size: 16px;
}

#clear_chk{
	-moz-transform: scale(1.3);
	padding: 10px;
	margin: 15px;
}

.submit_btn:hover{
	cursor: pointer;
	background-color: white;
}

#load_devices * {
	margin-top:5px;
	margin-bottom:10px;
}

#load_devices{
	width: 70%;
	float: left;
	text-align: center;
	padding: 16px 18px;
	margin-top:10%;
	margin-bottom:5px;
	height: 40%;
}

#load_devices input{
	padding: 12px 14px;
	font-size: 16px;
}


#load_devices input[type=text] {
	width: 60%;
}

#success_fail{
	color: limegreen;
}

Credits

Evan Rust

Evan Rust

120 projects • 1052 followers
IoT, web, and embedded systems enthusiast. Contact me for product reviews or custom project requests.

Comments