Camera Control Unit

$160-$185

Camera Control Unit (Explainer)

Order one for yourself here: http://therealtonystark.com/shop/misc/ccu/ An incredible asset to any live-streamer, this Camera Control Unit is equipped to control the pan and tilt of up to two cameras using an embedded joystick. Clicking the joystick’s button will change the on-board indicator LEDs to inform you of which camera you are controlling.

Clear

An incredible asset to any live-streamer, this Camera Control Unit is equipped to control the pan and tilt of up to two cameras using an embedded joystick.  Clicking the joystick’s button will change the on-board indicator LEDs to inform you of which camera you are controlling.

The unit includes four pre-set buttons which, when pressed for 2 seconds, will retain the current position of the camera for quick recall.  Each camera can have up to four independent positions!

How could this get any better?  The WiFi-enabled unit can also be configured to receive commands through the web or even an app.

Oh – and you can even order a 3D printed cover for the unit here.

Don’t forget to check out the Additional Required Items to ensure you have everything necessary!

List of Included Features

  • Joystick with built-in pushbutton for 180 degree, bidirectional control and toggle functionality.
  • Four buttons which can recall preset positions for up to two pan-and-tilt units (not included – see additional items).
  • Runs on 5V regulated power supply (not included – see additional items).
  • WiFi Unit – can receive commands from the web or an app to operate functions.

The circuitry measures 10 x 5 x 1 cm (joystick is 3cm tall).

Additional Required Items (not included in kits)

  • 5V Power Supply (ensure you order one that works in your region!)
  • 4.8V-6V servos x 2 (recommend the Lynxmotion Pan-and-Tilt Kit)
    • You will need one pair of servos for each camera (max of four servos can be controlled with a single CCU)
  • Servo Extension Wires (measure the distance between where the servos and joystick will sit).
    • (see optional items below if your servos will be more than 60cm (2′) from the joystick).

Optional Additional Items

  • Power Switch (can be inserted between the power jack and power supply.)
  • Boosted Servo Extension Cable [recommended for each servo if the distance between your joystick and servos will exceed 60cm (2′).]

Particle Photon Installation

In order to install the code onto the unit, you will have to follow the instructions on Particle’s website here:

Particle Photon Installation Instructions

Be sure to follow the instructions exactly as indicated, and feel free to contact me if you have any issues.

Particle Photon Code

Once you have successfully “claimed” your Photon device, head to http://build.particle.io to flash the following code onto your device:

/* This code was written and developed by TheRealStark (Ryan Brooks) December 2015
* Copyright 2015 by Ryan Brooks http://www.therealtonystark.com
*/
/* This code is intended for use with the Camera Control Unit designed by Ryan Brooks.
* The code manages the input of a joystick and converts the readings to four servos in order to position up to two pan-and-tilt units.
* The code is open-source and can be borrowed / edited, but a reference to this code is requested in all derivative applications.
*/

Servo H1; // Camera 1 Horizontal
Servo V1; // Camera 1 Vertical
Servo H2; // Camera 2 Horizontal
Servo V2; // Camera 2 Vertical

int posH1 = 90; // variable for managing camera 1’s horizontal position
int posV1 = 90; // variable for managing camera 1’s vertical position
int posH2 = 90; // variable for managing camera 2’s horizontal position
int posV2 = 90; // variable for managing camera 2’s vertical position

const int ledA = D3; // variable for ledA
const int ledB = D4; // variable for ledB
const int ledC = D5; // variable for ledC
const int ledD = D6; // variable for ledD

const int btnA = D7; // variable for button A input
const int btnB = A6; // variable for button B input
const int btnC = RX; // variable for button C input
const int btnD = TX; // variable for button D input

const int joyH = A1; // variable for button joystick horizontal input
const int joyV = A2; // variable for button joystick vertical input
const int joyB = A3; // variable for button joystick selection button input

const int led1 = A5; // variable for led1
const int led2 = A4; // variable for led2

int stateA, stateB, stateC, stateD, stateJ; // variables for monitoring the state of each pushbutton
int stateH, stateV, rangeH, rangeV, joyHstatic, joyVstatic; // variables for managing joystick range and motion

int h1A = 90, v1A = 90, h1B = 90, v1B = 90, h1C = 90, v1C = 90, h1D = 90, v1D = 90; // initial memory states for each camera
int h2A = 90, v2A = 90, h2B = 90, v2B = 90, h2C = 90, v2C = 90, h2D = 90, v2D = 90;
int mode = 0; // variable for monitoring current memory state and associated LEDs illuminated
int joyBuffer = 5; // variable value for amount of movement before joystick motion is tracked
int currentCam = 1; // variable for toggling between current camera being controlled

bool resetA = true; // variables for debounce of each button
bool resetB = true;
bool resetC = true;
bool resetD = true;
bool resetJ = true;
bool resetTime = true; // variable for resetting timer to recalibrate joystick’s neutral position

unsigned long prevTime = 0; // start time for button press timer
unsigned long currTime = 0; // current time
unsigned long joyTime = 0; // timer for joystick recalibration (every 10 seconds of non-movement)

void setup() {

H1.attach(WKP); // pin designations for servos
V1.attach(D0);
H2.attach(D1);
V2.attach(D2);

pinMode(ledA, OUTPUT); // pin designations for LEDs
pinMode(ledB, OUTPUT);
pinMode(ledC, OUTPUT);
pinMode(ledD, OUTPUT);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);

pinMode(btnA, INPUT); // pin designations for buttons
pinMode(btnB, INPUT);
pinMode(btnC, INPUT);
pinMode(btnD, INPUT);

pinMode(joyH, INPUT); // pin designations for joystick inputs
pinMode(joyV, INPUT);
pinMode(joyB, INPUT_PULLUP);

joyStatic(); // calibrate joystick’s neutral position

digitalWrite(led1, HIGH); // start with camera 1 as default configuration
digitalWrite(led2, LOW);

} // end void setup

void loop() {

stateA = digitalRead(btnA); // read buttons
stateB = digitalRead(btnB);
stateC = digitalRead(btnC);
stateD = digitalRead(btnD);
stateJ = digitalRead(joyB);

stateH = analogRead(joyH); // read joystick
stateV = analogRead(joyV);

rangeH = map(stateH, 0, 4095, -5, 5); // map joystick value to smaller range
rangeV = map(stateV, 0, 4095, -5, 5);

// delay(500);

if (stateJ == false && resetJ == true) { // function for toggling between camera 1 and 2
resetJ = false; // debounce
if (currentCam == 1) { // switch between cameras, switch indicator LEDs
currentCam = 2;
digitalWrite(led1, LOW);
digitalWrite(led2, HIGH);
} else if (currentCam == 2) {
currentCam = 1;
digitalWrite(led2, LOW);
digitalWrite(led1, HIGH);
}
} // end stateJ if

if(stateJ == true && resetJ == false) { // reset joystick button
resetJ = true;
}

moveCam(); // run moveCam function
currTime = millis();
buttonCheck(); // check button states

switch (mode) { // activiate appropriate LEDs depending on current mode

case 0: // no memory state
digitalWrite(ledA, LOW);
digitalWrite(ledB, LOW);
digitalWrite(ledC, LOW);
digitalWrite(ledD, LOW);
break;

case 1: // memory state 1
digitalWrite(ledA, HIGH);
digitalWrite(ledB, LOW);
digitalWrite(ledC, LOW);
digitalWrite(ledD, LOW);
break;

case 2: // memory state 2
digitalWrite(ledA, LOW);
digitalWrite(ledB, HIGH);
digitalWrite(ledC, LOW);
digitalWrite(ledD, LOW);
break;

case 3: // memory state 3
digitalWrite(ledA, LOW);
digitalWrite(ledB, LOW);
digitalWrite(ledC, HIGH);
digitalWrite(ledD, LOW);
break;

case 4: // memory state 4
digitalWrite(ledA, LOW);
digitalWrite(ledB, LOW);
digitalWrite(ledC, LOW);
digitalWrite(ledD, HIGH);
break;
} // end switch

} // end void loop

void setCam(int thisH, int thisV) { // function for setting the current memory selection

if (currentCam == 1) {
posH1 = thisH;
posV1 = thisV;
H1.write(thisH);
V1.write(thisV);
} else if (currentCam == 2) {
posH2 = thisH;
posV2 = thisV;
H2.write(thisH);
V2.write(thisV);
} // end currentCam if
} // end void setCam

void moveCam() { // function for mapping joystick movement to servo position

if (currentCam == 1) {
if (stateH < (joyHstatic+joyBuffer) && stateH > (joyHstatic-joyBuffer) && stateV < (joyVstatic+joyBuffer) && stateV > (joyVstatic-joyBuffer)) {
// if the joystick is in the “neutral zone”
if (resetTime == true) {
joyTime = millis();
resetTime = false;
} else {
if ((currTime – joyTime) > 10000) {
joyStatic();
resetTime = true;
}
}
} else { // if joystick is outside of neutral zone
resetTime = true;
if (stateH >= (joyHstatic+5) && posH1 < (180-rangeH)) { // if servo is below it’s max
posH1 += rangeH;
} else if (stateH <= (joyHstatic-5) && posH1 > rangeH+60) {
posH1 += rangeH;
}

if (stateV >= (joyVstatic+5) && posV1 < (180-rangeV)) {
posV1 += rangeV;
} else if (stateV <= (joyVstatic-5) && posV1 > (rangeV)) {
posV1 += rangeV;
}
delay(50);
mode = 0;

}
if (mode == 0) { // if not in preset mode, move servos to new positions
H1.write(posH1);
V1.write(posV1);
}

} else if (currentCam == 2) {
if (stateH < (joyHstatic+joyBuffer) && stateH > (joyHstatic-joyBuffer) && stateV < (joyVstatic+joyBuffer) && stateV > (joyVstatic-joyBuffer)) {
if (resetTime == true) {
joyTime = millis();
resetTime = false;
} else {
if ((currTime – joyTime) > 10000) {
joyStatic();
resetTime = true;
}
}
} else {
resetTime = true;
if (stateH >= (joyHstatic+5) && posH2 < (180-rangeH)) {
posH2 += rangeH;
} else if (stateH <= (joyHstatic-5) && posH2 > rangeH) {
posH2 += rangeH;
}

if (stateV >= (joyVstatic+5) && posV2 < (180-rangeV)) {
posV2 += rangeV;
} else if (stateV <= (joyVstatic-5) && posV2 > rangeV) {
posV2 += rangeV;
}
delay(50);
mode = 0;
}
if (mode == 0) {
H2.write(posH2);
V2.write(posV2);
}
}

} // end moveCam

void buttonCheck() {
if(currentCam == 1) {
if (stateA == false) { // if the A button is pressed
if (resetA == true) { // if the A button has been pressed and not released
resetA = false;
prevTime = millis();
}
if ((currTime – prevTime) > 2000) { // if button has been held for 2 seconds
h1A = posH1; // set new memory positions
v1A = posV1;
delay(500);

for(int i=0; i<3; i++) { // blink current memory led 3 times to indicate new memory set
digitalWrite(ledA, HIGH);
delay(500);
digitalWrite(ledA, LOW);
delay(500);
}
digitalWrite(ledA, HIGH);
mode = 1;
} // end currTime if
} // end stateA if

if (stateA == true && resetA == false) { // if button A is no longer pressed
resetA = true; // debounce
if ((currTime – prevTime) < 1000) { // if button was pressed for less than a second setCam(h1A, v1A); // return servos to memory A position mode = 1; // set mode to memory A } // end currTime if } // end stateA if if (stateB == false) { // if the B button is pressed if (resetB == true) { // if the B button has been pressed and not released resetB = false; prevTime = millis(); } if ((currTime – prevTime) > 2000) {
h1B = posH1;
v1B = posV1;
delay(500);

for(int i=0; i<3; i++) {
digitalWrite(ledB, HIGH);
delay(500);
digitalWrite(ledB, LOW);
delay(500);
}
digitalWrite(ledB, HIGH);
mode = 2;
}
}
if (stateB == true && resetB == false) {
resetB = true;
if ((currTime – prevTime) < 1000) { setCam(h1B, v1B); mode = 2; } } if (stateC == false) { // if the C button is pressed if (resetC == true) { // if the C button has been pressed and not released resetC = false; prevTime = millis(); } if ((currTime – prevTime) > 2000) {
h1C = posH1;
v1C = posV1;
delay(500);

for(int i=0; i<3; i++) {
digitalWrite(ledC, HIGH);
delay(500);
digitalWrite(ledC, LOW);
delay(500);
}
digitalWrite(ledC, HIGH);
mode = 3;
}
}
if (stateC == true && resetC == false) {
resetC = true;
if ((currTime – prevTime) < 1000) { setCam(h1C, v1C); mode = 3; } } if (stateD == false) { // if the D button is pressed if (resetD == true) { // if the D button has been pressed and not released resetD = false; prevTime = millis(); } if ((currTime – prevTime) > 2000) {
h1D = posH1;
v1D = posV1;
delay(500);

for(int i=0; i<3; i++) {
digitalWrite(ledD, HIGH);
delay(500);
digitalWrite(ledD, LOW);
delay(500);
}
digitalWrite(ledD, HIGH);
mode = 4;
}
}
if (stateD == true && resetD == false) {
resetD = true;
if ((currTime – prevTime) < 1000) { setCam(h1D, v1D); mode = 4; } } } else if (currentCam == 2) { if (stateA == false) { // if the A button is pressed if (resetA == true) { // if the A button has been pressed and not released resetA = false; prevTime = millis(); } if ((currTime – prevTime) > 2000) {
h2A = posH2;
v2A = posV2;
delay(500);

for(int i=0; i<3; i++) {
digitalWrite(ledA, HIGH);
delay(500);
digitalWrite(ledA, LOW);
delay(500);
}
digitalWrite(ledA, HIGH);
mode = 1;
}
}
if (stateA == true && resetA == false) {
resetA = true;
if ((currTime – prevTime) < 1000) { setCam(h2A, v2A); mode = 1; } } if (stateB == false) { // if the B button is pressed if (resetB == true) { // if the B button has been pressed and not released resetB = false; prevTime = millis(); } if ((currTime – prevTime) > 2000) {
h2B = posH2;
v2B = posV2;
delay(500);

for(int i=0; i<3; i++) {
digitalWrite(ledB, HIGH);
delay(500);
digitalWrite(ledB, LOW);
delay(500);
}
digitalWrite(ledB, HIGH);
mode = 2;
}
}
if (stateB == true && resetB == false) {
resetB = true;
if ((currTime – prevTime) < 1000) { setCam(h2B, v2B); mode = 2; } } if (stateC == false) { // if the C button is pressed if (resetC == true) { // if the C button has been pressed and not released resetC = false; prevTime = millis(); } if ((currTime – prevTime) > 2000) {
h2C = posH2;
v2C = posV2;
delay(500);

for(int i=0; i<3; i++) {
digitalWrite(ledC, HIGH);
delay(500);
digitalWrite(ledC, LOW);
delay(500);
}
digitalWrite(ledC, HIGH);
mode = 3;
}
}
if (stateC == true && resetC == false) {
resetC = true;
if ((currTime – prevTime) < 1000) { setCam(h2C, v2C); mode = 3; } } if (stateD == false) { // if the D button is pressed if (resetD == true) { // if the D button has been pressed and not released resetD = false; prevTime = millis(); } if ((currTime – prevTime) > 2000) {
h2D = posH2;
v2D = posV2;
delay(500);

for(int i=0; i<3; i++) {
digitalWrite(ledD, HIGH);
delay(500);
digitalWrite(ledD, LOW);
delay(500);
}
digitalWrite(ledD, HIGH);
mode = 4;
}
}
if (stateD == true && resetD == false) {
resetD = true;
if ((currTime – prevTime) < 1000) {
setCam(h2D, v2D);
mode = 4;
}
}
} // end currentCam if
} // end void buttonCheck

void joyStatic() { // function for recalibrating joystick neutral position

joyHstatic = 0;
joyVstatic = 0;

for (int i=0; i<10; i++) {
stateH = analogRead(joyH);
stateV = analogRead(joyV);

joyHstatic += stateH;
joyVstatic += stateV;
}

joyHstatic /= 10;
joyVstatic /= 10;

} // end void joyStatic

Additional Information

Model

WiFi-Enabled, Standard (no wireless connectivity)

Reviews

There are no reviews yet.

Be the first to review “Camera Control Unit”

Your email address will not be published. Required fields are marked *