After the prototype remote trigger I presented in my previous post has been tested succesfully I decided to make my own shield for the arduino and put the whole system in a box, that I could take with me for shooting panoramas. What you see in the following pictures is my attempt to make a portable system for all types of remote triggering my NEX 5. I called this project The Ultimate Trigger V1.
I tried to make the shield somehow modular in design. This means I can attach different types of servos, I can attach a different IR receiver and I can change the attached wireless RF receiver without using a soldering iron.
This image shows the guts of the whole system. On the left side from top to bottom:
The arduino board with the attached shield. Several items are connected via cables to the shield: The IR remote receiver with its red-black-blue cable going to the upper lid of the box on the right. The IR receiver itself is glued to the lid with instant adhesive. The servo can be connected via the red-black-green cable going towards the outside of the lid. The third party wireless RF remote receiver (dismantled compared to my last post) sits in the bottom right part of the left lid and is attached to the shild also via a cable. Last but not least you see the 9V battery powering the arduino and the shield. The wireless RF receiver has its own battery.
When the box is closed you see on the upper side (which is in my definition the side next to the camera and thus close to the servo) the three pins, where a servo can be attached. Furthermore you see on the side facing the operator the three LEDs showing the status of the device.
On the bottom side you see from left to right: The IR receiver, the arduino USB port and the arduino power port.
Like the image before this one shows the bottom part of the box (from left to right): The IR receiver, the arduino USB port and the arduino power port.
The following images show the system without the box. First the shield connected to the arduino. The battery, servo, RF receiver and IR receiver are all disconnected.
This image shows the top view of the plain shield.
This image shows the bottom view of the plain shield.
Warning: WP_Syntax::substituteToken(): Argument #1 ($match) must be passed by reference, value given in /home/pacs/mma00/users/panotwins/doms/panotwins.de/subs/wp/wp-content/plugins/wp-syntax/wp-syntax.php on line 380
One problem with the Sony NEX 5 camara series is the lack of a decent remote shutter mode. You are able to switch it to IR mode and use the IR remote control to take a picture. However you can’t combine any of the other available trigger modes like bracketing or high speed trigger with the IR remote control. I wanted to change this and started this project described here: The ultimate remote trigger for the Sony NEX 5 using a servo and an arduino board. I called this project The Ultimate Trigger V1.
The remote control has four different possibilities for taking a picture:
Software – Via code running on a host computer sending commands to the COM port where the arduino is attached
Arduino – Via code running on the arduino itself (not implemented at the moment)
IR remote – Via an arbitrary IR remote control
Cable – Via an attached remote release cable
The following image shows the finished breadboard version. You see the arduino board in blue on the left above the yellow 9V battery. Between the arduino board and the battery is the attached wireless remote receiver. In the middle you find the white breadboard with the necessary electronics. On the NEX you see the servo attached via a cable strap and a rubber band. On the right you see the wireless remote transmitter and the IR remote transmitter.
This image shows the breadboard in detail: On the breadboard you find from top to bottom:
The attached servo (a JR type model with brown, red and orange cables)
The attached wireless receiver. This could also be any other type of Minolta, Konica-Minolta or Sony remote cable release. The receiver is a third party RF wireless type.
The IR receiver able to receive most types of consumer IR remote controls.
Three status LEDs with the necessary series resistors.
This image shows the breadboard design in detail. It has been made with Fritzing.
This image shows the schematics of the electronics (also made with Fritzing).
The following code for the arduino sketch makes use of two libraries: Servo (included in the arduino IDE) and IRremote!
/*
* Ultimate Trigger V1
* by Markus Matern aka PanoTwin Markus
*
* Release: 20120107
*
* This code is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/
* or send a letter to:
* Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
*/#include <Servo.h>#include <IRremote.h>// Servo configurationconstint servoPin =11;constint minimumAngle =0;constint maximumAngle =179;constint zeroAngle =100;constint wakeUpAngle =107;constint shootAngle =110;
Servo myservo;// Wireless remote configurationconstint triggerWhite =10;constint triggerBlue =9;int whiteVal = LOW;int blueVal = LOW;// IR receiver configurationint RECV_PIN =8;
IRrecv irrecv(RECV_PIN);
decode_results results;// Diagonstic configurationconstint ledStatus =7;constint ledTrigger =6;constint ledError =5;void setup(){// Diagnostic setup
pinMode(ledStatus, OUTPUT);
digitalWrite(ledStatus, HIGH);
pinMode(ledTrigger, OUTPUT);
digitalWrite(ledTrigger, LOW);
pinMode(ledError, OUTPUT);
digitalWrite(ledError, LOW);// Servo setup
myservo.attach(servoPin);
myservo.write(zeroAngle);// Wireless setup
pinMode(triggerWhite, INPUT);// make sure the input pin is not undefined
digitalWrite(triggerWhite, HIGH);
pinMode(triggerBlue, INPUT);// make sure the input pin is not undefined
digitalWrite(triggerBlue, HIGH);// IR receiver setup
irrecv.enableIRIn();// Start the receiver// Serial setup
Serial.begin(9600);}void shoot(){
StatusTrigger(1);
myservo.write(wakeUpAngle);
delay(1000);
myservo.write(shootAngle);
delay(1000);
myservo.write(zeroAngle);
StatusTrigger(0);
delay(1000);}void wakeUp(){
StatusTrigger(1);
myservo.write(wakeUpAngle);
delay(1000);
myservo.write(zeroAngle);
StatusTrigger(0);
delay(1000);}void minAngle(){
StatusTrigger(1);
myservo.write(minimumAngle);
delay(1000);
myservo.write(zeroAngle);
delay(1000);
StatusTrigger(0);}void maxAngle(){
StatusTrigger(1);
myservo.write(maximumAngle);
delay(1000);
myservo.write(zeroAngle);
delay(1000);
StatusTrigger(0);}void Blink(int blinkLed,int milliseconds,int blinkCount){for(int i =0; i < blinkCount; i++){
Status(blinkLed,1);
delay(milliseconds/blinkCount/2);
Status(blinkLed,0);
delay(milliseconds/blinkCount/2);}}void BlinkBeforeTrigger(int milliseconds){
Blink(ledTrigger, milliseconds,3);}void StatusTrigger(int newStatus){
Status(ledTrigger, newStatus);}void StatusError(int newStatus){
Status(ledError, newStatus);}void Status(int pin,int newStatus){if(newStatus){
digitalWrite(pin, HIGH);}else{
digitalWrite(pin, LOW);}}void loop(){// remote control via serial communicationif(Serial.available()>0){int b = Serial.read();switch(b){case't':
shoot();break;case'w':
wakeUp();break;case'0':
minAngle();break;case'8':
maxAngle();break;default:
Blink(ledError,600,3);break;}
Serial.flush();}elseif(irrecv.decode(&results)){switch(results.value){// Sony Shutter (2 Sec)case0xECB8F:
StatusTrigger(1);
Blink(ledTrigger,2000,4);// Note: No break here!// fall through to shoot!// Sony Shuttercase0xB4B8F:
shoot();break;case0:break;default:
StatusError(1);
Serial.println(results.value, HEX);
Blink(ledError,600,3);
StatusError(0);break;}// Receive the next value
irrecv.resume();}else{// Check the wireless remote triggerint newWhiteVal = digitalRead(triggerWhite);int newBlueVal = digitalRead(triggerBlue);if(newWhiteVal != whiteVal){if(newWhiteVal == HIGH){//Serial.println("White High");
myservo.write(zeroAngle);
StatusTrigger(0);}else{//Serial.println("White Low");
StatusTrigger(1);
StatusError(0);
myservo.write(wakeUpAngle);}
whiteVal = newWhiteVal;}if(newBlueVal != blueVal){if(newBlueVal == HIGH){//Serial.println("Blue High");
StatusError(0);}else{//Serial.println("Blue Low");
myservo.write(shootAngle);
StatusTrigger(1);
StatusError(1);}
blueVal = newBlueVal;}}}
/*
* Ultimate Trigger V1
* by Markus Matern aka PanoTwin Markus
*
* Release: 20120107
*
* This code is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/
* or send a letter to:
* Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
*/
#include <Servo.h>
#include <IRremote.h>
// Servo configuration
const int servoPin = 11;
const int minimumAngle = 0;
const int maximumAngle = 179;
const int zeroAngle = 100;
const int wakeUpAngle = 107;
const int shootAngle = 110;
Servo myservo;
// Wireless remote configuration
const int triggerWhite = 10;
const int triggerBlue = 9;
int whiteVal = LOW;
int blueVal = LOW;
// IR receiver configuration
int RECV_PIN = 8;
IRrecv irrecv(RECV_PIN);
decode_results results;
// Diagonstic configuration
const int ledStatus = 7;
const int ledTrigger = 6;
const int ledError = 5;
void setup() {
// Diagnostic setup
pinMode(ledStatus, OUTPUT);
digitalWrite(ledStatus, HIGH);
pinMode(ledTrigger, OUTPUT);
digitalWrite(ledTrigger, LOW);
pinMode(ledError, OUTPUT);
digitalWrite(ledError, LOW);
// Servo setup
myservo.attach(servoPin);
myservo.write(zeroAngle);
// Wireless setup
pinMode(triggerWhite, INPUT);
// make sure the input pin is not undefined
digitalWrite(triggerWhite, HIGH);
pinMode(triggerBlue, INPUT);
// make sure the input pin is not undefined
digitalWrite(triggerBlue, HIGH);
// IR receiver setup
irrecv.enableIRIn(); // Start the receiver
// Serial setup
Serial.begin(9600);
}
void shoot(){
StatusTrigger(1);
myservo.write(wakeUpAngle);
delay(1000);
myservo.write(shootAngle);
delay(1000);
myservo.write(zeroAngle);
StatusTrigger(0);
delay(1000);
}
void wakeUp(){
StatusTrigger(1);
myservo.write(wakeUpAngle);
delay(1000);
myservo.write(zeroAngle);
StatusTrigger(0);
delay(1000);
}
void minAngle(){
StatusTrigger(1);
myservo.write(minimumAngle);
delay(1000);
myservo.write(zeroAngle);
delay(1000);
StatusTrigger(0);
}
void maxAngle(){
StatusTrigger(1);
myservo.write(maximumAngle);
delay(1000);
myservo.write(zeroAngle);
delay(1000);
StatusTrigger(0);
}
void Blink(int blinkLed,
int milliseconds,
int blinkCount)
{
for(int i = 0; i < blinkCount; i++) {
Status(blinkLed, 1);
delay(milliseconds/blinkCount/2);
Status(blinkLed, 0);
delay(milliseconds/blinkCount/2);
}
}
void BlinkBeforeTrigger(int milliseconds) {
Blink(ledTrigger, milliseconds, 3);
}
void StatusTrigger(int newStatus) {
Status(ledTrigger, newStatus);
}
void StatusError(int newStatus) {
Status(ledError, newStatus);
}
void Status(int pin, int newStatus) {
if(newStatus){
digitalWrite(pin, HIGH);
} else {
digitalWrite(pin, LOW);
}
}
void loop() {
// remote control via serial communication
if (Serial.available() > 0) {
int b = Serial.read();
switch(b) {
case 't':
shoot();
break;
case 'w':
wakeUp();
break;
case '0':
minAngle();
break;
case '8':
maxAngle();
break;
default:
Blink(ledError, 600, 3);
break;
}
Serial.flush();
} else if (irrecv.decode(&results)) {
switch(results.value)
{
// Sony Shutter (2 Sec)
case 0xECB8F:
StatusTrigger(1);
Blink(ledTrigger, 2000, 4);
// Note: No break here!
// fall through to shoot!
// Sony Shutter
case 0xB4B8F:
shoot();
break;
case 0:
break;
default:
StatusError(1);
Serial.println(results.value, HEX);
Blink(ledError, 600, 3);
StatusError(0);
break;
}
// Receive the next value
irrecv.resume();
} else {
// Check the wireless remote trigger
int newWhiteVal = digitalRead(triggerWhite);
int newBlueVal = digitalRead(triggerBlue);
if (newWhiteVal != whiteVal) {
if (newWhiteVal == HIGH) {
//Serial.println("White High");
myservo.write(zeroAngle);
StatusTrigger(0);
} else {
//Serial.println("White Low");
StatusTrigger(1);
StatusError(0);
myservo.write(wakeUpAngle);
}
whiteVal = newWhiteVal;
}
if (newBlueVal != blueVal) {
if (newBlueVal == HIGH) {
//Serial.println("Blue High");
StatusError(0);
} else {
//Serial.println("Blue Low");
myservo.write(shootAngle);
StatusTrigger(1);
StatusError(1);
}
blueVal = newBlueVal;
}
}
}
This stereographic reprojection shows the Oktoberfest from the Bavaria statue. The original panorama has been made from inside the head of Bavaria. Bavaria is a hollow bronze statue that can be ascended in the inside. It is located next to the Theresienwiese, where the famous Oktoberfest takes place since more than 200 years. See the original panorama here.
The Novoflex NEX/NIK adapter makes it possible to mount Nikon lenses on the Sony NEX camera line. Read more about the lens here or here. On the Novoflex homepage you find an adapter finder here.
The Nikon 50mm f/1.8 AI is a manual lens. The Novoflex NEX/NIK adapter is also only a manual adapter. However this is not a problem with the Sony NEX-5. You just have to be aware of some things.
Make sure you enable the shooting without a lens: Menu → Setup → Release w/o lens → Enable
Before you continue make sure you have Firmware ≥ Ver. 04 installed! Check this using Menu → Setup → Version. When you have an older version installed download the latest version from the Sony support site here.
Enable the MF Assist function using Menu → Setup → MF Assist → 2 Sec You can choose between No Limit — 2 Sec — 5 Sec.
Enable the Peaking Level using Menu → Setup → Peaking Level → Mid
You can choose between Low — Mid — High.
Choose your Peaking Color using Menu → Setup → Peaking Color→ Red
You can choose between Yellow — Red — White.
Switch your camera to A- Mode (aperture priority) and use the MF Assist button to get a perfectly sharp picture even when shooting the lens wide open with f/1.8!
Some months ago I stumbled across a post on Sonyalpha Rumors. The Lensbaby Tilt Transformer with the possibility to mount the Lensbaby Composer Focus Front or Nikon lenses on it. The local photography store had it in stock and I bought it right away! First without a Nikon lens, but shortly afterwards I bought two of them. You see the results in the following images.
See additional information for this Nikon lens on the Sony NEX camera line in this post.
See additional information for this Nikon lens on the Sony NEX camera line in this post.
The Lensbaby Tilt Transformer makes it possible to mount Nikon lenses (with an F-mount) on the Sony NEX camera line. Read more about the lens here or here.
During our talk about “Reprojecting equirectangular images for a printed presentation” in Palmela and Vienna we presented two scripts you can use to reproject images using a so called Droste – effect. See some examples in these posts.
Here is a short overview over the software we used, you can consider this as the required runtime environment for the scripts:
One of these is a script for the Gimp’s Mathmap Plugin. The other one is a script for the Pixel Bender Toolkit. The problem with the original two scripts is, that the parameters they use have different names and they are implemented differently! E.g. sizes are pixel sizes in one script and percentages of the image size in the other script. I wanted to be able to use the same parameters in both environments. So I started to bring the scripts back together.
The main motivation for this was to be able to work on large files. The Pixel Bender stand alone version has a size limitation depending on your graphics card. This may be a maximum of 2048×2048 pixels or like in my case 4096×4096 pixels. When you want to process larger images you have to switch to The Gimp. These size limitations do not apply there! The Mathmap rendering on the other hand is really slow compared to the Pixel Bender. This is because Mathmap renders the final image and the preview on a single core of your CPU. The Pixel Bender toolkit renders both on the GPU!
This table shows links to the original scripts (Mathmap V10 and Pixel Bender V1.1) and the modified versions with exchangable parameters (Mathmap V11 and Pixel Bender V2).
See two screenshots of some sample settings using Mathmap and Pixel Bender and the original and transformed image:
For an example workflow on how to generate a Droste spiral effect from a 360° panoramic (or equirectangular) image image read this post.
Acknowledegements go to the following persons, who started the first versions of the scripts: Mathmap: breic, Josh Sommers; Pixel Bender: Tom Beddard
You find further information about the Math behind the Droste effect here and here.