I wanted to control the zoom of a Sony block camera from a normal RC transmitter.
For the test I used:
A Sony FCB EX11D camera with VISCA control
An Arduino Mini running at 3.3 V
A Spektrum DX6i transmitter
An AR6200 receiver
A monitor with a composite video input
The camera accepts approximately 6 to 12 V, has a 10 times optical zoom and produces NTSC composite video. The Arduino sends Sony VISCA commands at 9600 baud.
Connections
Camera RX to Arduino TX
Camera TX to Arduino RX
The camera TX connection is only needed if the program reads VISCA replies. With a 3.3 V controller it should be connected through the correct level conversion.
Camera ground to Arduino ground
Arduino digital pin 3 to the ELEV channel signal on the RC receiver
For this demonstration I powered the receiver from 3.3 V. A normal RC installation will often use 5 V, so the signal going into a 3.3 V Arduino may need a resistor divider or level converter.
The program measures the pulse width from the receiver. Moving the stick in one direction sends the VISCA zoom tele command, moving it in the other direction sends zoom wide, and returning it to the center sends zoom stop and autofocus.
Arduino and ATtiny85 versions of the code are below.
Build photos and code below.
Arduino version
#include <SoftwareSerial.h>
const byte rcPin = 3;
const byte cameraRxPin = 10; // Leave disconnected for transmit only control
const byte cameraTxPin = 11; // Connect to camera RX
SoftwareSerial cameraSerial(cameraRxPin, cameraTxPin);
const byte addressSet[] = {0x88, 0x30, 0x01, 0xFF};
const byte interfaceClear[] = {0x88, 0x01, 0x00, 0x01, 0xFF};
const byte zoomTele[] = {0x81, 0x01, 0x04, 0x07, 0x23, 0xFF};
const byte zoomWide[] = {0x81, 0x01, 0x04, 0x07, 0x33, 0xFF};
const byte zoomStop[] = {0x81, 0x01, 0x04, 0x07, 0x00, 0xFF};
const byte autoFocus[] = {0x81, 0x01, 0x04, 0x38, 0x02, 0xFF};
enum ZoomState { STOPPED, TELE, WIDE };
ZoomState lastState = STOPPED;
template <size_t N>
void sendPacket(const byte (&packet)[N]) {
cameraSerial.write(packet, N);
}
void setup() {
pinMode(rcPin, INPUT);
cameraSerial.begin(9600);
delay(500);
sendPacket(addressSet);
delay(250);
sendPacket(interfaceClear);
delay(250);
sendPacket(autoFocus);
}
void loop() {
unsigned long pulse = pulseIn(rcPin, HIGH, 25000UL);
ZoomState nextState = STOPPED;
if (pulse > 1550) {
nextState = TELE;
} else if (pulse != 0 && pulse < 1400) {
nextState = WIDE;
}
if (nextState != lastState) {
if (nextState == TELE) {
sendPacket(zoomTele);
} else if (nextState == WIDE) {
sendPacket(zoomWide);
} else {
sendPacket(zoomStop);
sendPacket(autoFocus);
}
lastState = nextState;
}
}
ATtiny85 version
#include <SoftwareSerial.h>
#define rcPin PB0
#define cameraRxPin PB1
#define cameraTxPin PB2
SoftwareSerial cameraSerial(cameraRxPin, cameraTxPin);
const byte addressSet[] = {0x88, 0x30, 0x01, 0xFF};
const byte interfaceClear[] = {0x88, 0x01, 0x00, 0x01, 0xFF};
const byte zoomTele[] = {0x81, 0x01, 0x04, 0x07, 0x23, 0xFF};
const byte zoomWide[] = {0x81, 0x01, 0x04, 0x07, 0x33, 0xFF};
const byte zoomStop[] = {0x81, 0x01, 0x04, 0x07, 0x00, 0xFF};
const byte autoFocus[] = {0x81, 0x01, 0x04, 0x38, 0x02, 0xFF};
enum ZoomState { STOPPED, TELE, WIDE };
ZoomState lastState = STOPPED;
template <size_t N>
void sendPacket(const byte (&packet)[N]) {
cameraSerial.write(packet, N);
}
void setup() {
pinMode(rcPin, INPUT);
pinMode(cameraRxPin, INPUT);
pinMode(cameraTxPin, OUTPUT);
cameraSerial.begin(9600);
delay(500);
sendPacket(addressSet);
delay(250);
sendPacket(interfaceClear);
delay(250);
sendPacket(autoFocus);
}
void loop() {
unsigned long pulse = pulseIn(rcPin, HIGH, 25000UL);
ZoomState nextState = STOPPED;
if (pulse > 1550) {
nextState = TELE;
} else if (pulse != 0 && pulse < 1400) {
nextState = WIDE;
}
if (nextState != lastState) {
if (nextState == TELE) {
sendPacket(zoomTele);
} else if (nextState == WIDE) {
sendPacket(zoomWide);
} else {
sendPacket(zoomStop);
sendPacket(autoFocus);
}
lastState = nextState;
}
}
No comments:
Post a Comment