Last week my friend Hans and I spent some time in my lab exploring which features of his Nikon D300 are available via PTP protocol. Hans is working on extended range HDR-capable intervalometer and he needed to find out a way to switch his camera into bulb mode using Arduino board and USB Host shield. After we finished I realized that while bulb mode is not tricky to activate, it is not obvious either and no hints exist in the code and examples showing how to do this. This short article is intended to fill the void.
In PTP, shooting parameters, such as shutter speed, aperture, ISO, etc. are changed by setting certain device property. For each parameter there exists a list of allowed values of this property, each property value corresponding to a parameter value. For some parameters, property and parameter value lists are dynamic. For example, starting and ending aperture values are different for different lenses; additionally, the aperture step can be changed in camera settings. Stepping can also be changed for shutter speed and exposure compensation and this can also happen during PTP session if a photographer decides to switch modes – in this case a property may become unavailable, like shutter speed in aperture priority mode. Therefore, before changing a property value for one of these parameters it is necessary to somehow retrieve a list of available property values.
The property value list retrieval mechanism is slightly different for different cameras. On Canon DSLRs, a special event is generated by the camera and sent back to PTP host at the beginning of the session and also each time camera mode was changed, lens were swapped and so on. The application needs to track those events and constantly maintain current value list for each property. On Nikon DSLR, it is possible to simply get value list for a property any time it is needed. To save memory, the list is not stored but simply requested from the camera each time a property needs changing. It is combined with actual property change in two templates – StepUp and StepDown. If you need to increase, for example, shutter speed – call StepUp. If you need to decrease it, call StepDown.
If you “step up” shutter speed on Nikon DSLR manually, the last 2 values will be 30 seconds and bulb. If you step up shutter speed using StepUp method using Nkremote sketch it will stop at 30 seconds. This happens because bulb mode is not included in the list of available property values for shutter speed but simply defined as 0xffffffff. As a result, StepUp doesn’t know that another value is available. It is still possible, however, to set the property directly and I will show you how to do it.
For the demonstration, I will be modifying Nkremote sketch itself. The psconsole.cpp file contains the menu tree. The “Change Settings” menu contains transitions to menus which change a particular parameter of the camera. The last one, i.e., number nine or “FocusPoint” is not very useful for remote control so I’m going to modify this menu to activate bulb mode instead. The code of ChangeFocusAreaMenu() is as follows:
QState PSConsole::ChangeFocusAreaMenu(PSConsole *me, QEvent const *e) { switch (e->sig) { case Q_ENTRY_SIG: PrintMenuTitles(UPDWN_MENU_COUNT, menuUpDown); PrintFocusArea(); return Q_HANDLED(); case MENU_SELECT_SIG: { switch (((MenuSelectEvt*)e)->item_index) { case 0: return Q_TRAN(&PSConsole::ChangeSettingsMenu); case 2: StepUp<VT_FOCUSAREA>((PTP*)&Nk, NK_DPC_AutofocusArea); PrintFocusArea(); return Q_HANDLED(); case 1: StepDown<VT_FOCUSAREA>((PTP*)&Nk, NK_DPC_AutofocusArea); PrintFocusArea(); return Q_HANDLED(); } // switch (((MenuSelectEvt*)e)->item_index) } // case MENU_SELECT_SIG: } return Q_SUPER(&PSConsole::Active); }
Cases 1 and 2 originally change the focus area. I’m commenting down StepUp() and StepDown() and inserting property change operation (lines 3 and 8). The new code will activate bulb mode if you press ’1′ or ’2′ in the terminal.
1 2 3 4 5 6 7 8 9 10 | case 2: //StepUp<VT_FOCUSAREA>((PTP*)&Nk, NK_DPC_AutofocusArea); Nk.SetDevicePropValue(0xd100, (uint32_t)0xffffffff); PrintFocusArea(); return Q_HANDLED(); case 1: //StepDown<VT_FOCUSAREA>((PTP*)&Nk, NK_DPC_AutofocusArea); Nk.SetDevicePropValue(0xd100, (uint32_t)0xffffffff); PrintFocusArea(); return Q_HANDLED(); |
After you change Nkremote, compile it and load into Arduino board. In a terminal window, choose “Change Settings”, then “FocusPoint”. On the next screen press ’1′ or ’2′, then ’0′ to return to the previous level. Now go to “View Settings”, you should see T:Bulb near the end of the output. To change it back to normal shutter mode go to “Change Settings”, then to the “Shutter Speed”.
Now let’s talk briefly about limitations. First, the bulb mode is only available in “Manual” and “Shutter Priority” modes. In all other modes an attempt to set shutter speed to bulb will be rejected. Another rather annoying limitation is capture command, which doesn’t function in bulb mode ( most Canon DSLRs continue to execute capture when switched to bulb, manually or otherwise). Cable release will work as usual so it is still possible to make a HDR intervalometer which can switch between ‘normal’ and bulb modes – all that is necessary is a digital pin on Arduino, a transistor and a couple of resistors.
This is it for the PTP, bulb mode and Nikons. I hope the information in this article was helpful for you. Enjoy!
Oleg.
Related posts:
- Controlling Canon Powershot cameras with Arduino
- Using Logitech Extreme 3D Pro joystick with Arduino HID library
- Arduino 1.0-compatible USB Host Library released
- Google Open Accessory Interface for USB Host Shield Library 2.0 released
- USB Host Shield library Version 2.0 released.
- Sony PS3 Controller support added to USB Host library
- USGlobalsat ND-100S GPS receiver works with USB Host library
- Andriod ADK-compatible USB Host Library release.
- Bluetooth RFCOMM/SPP service support for USB Host 2.0 Library released!
- Developing Arduino code for HID Joystick


Hi,
Can use USB Focus Controler control NIKON camera,such as change ISO,Aperture,etc?
If of course,Why are there not such product in the market?
Thank you!
Hi,
I’m trying to keep up with you guys, some time ago (ehh… almost 2 years now) I was trying to control my EOS 20D camera via USB.
Now I bought myself a other more up to date EOS camera and tried to pick up on things again to control this new one but so far no luck.
I am running Arduino IDE 1.02 with libraries ‘PTP_2.0′ and ‘USB_Host_Shield_2.0′ installed on my iMac Mountain Lion.
I’ve also installed QP for Arduino v4.5.02.
Should the examples compile without any other library or settings?
I feel somehow silly that after a day of trying, going backwards and forwards, I can’t get most of the examples to compile, what am I missing?
cheers,
John
What kind of errors are you getting? Have you been able to compile/run something simple, like PTPDevInfo? -> https://github.com/felis/PTP_2.0/tree/master/examples/ptpsketches/PTPDevInfo
Hi Oleg,
I am able to compile PTPDevInfo and this works beautifully with my USB shield and my EOS/Powershot camera’s.
(your original shield ‘v1′ that I modified it and after I ordered a new one yesterday in your shop).
I also tried a fresh installation of the Arduino IDE on a clean/virgin OSX computer with only the libraries installed that where necessary like PTP_2.0, USB_Host_v2.0, QP for Arduino (this one installed in the Arduino.app library) and some other basic libraries.
But the more advanced programs like EOS camera remote it struggles and doesn’t want to compile.
Can there be things left that I’m missing?
Cheers,
John
BTW; Am I correct that the biggest change from V1 to v2 hardware is cutting GPX connection and tying MRST to the USB controller from the reset of the Arduino. By doing this the hardware seems to be working and also the one that I have from Sparkfun works with this mod.
This is the first error message during compilation;
EOSCamController.pde: In member function ‘virtual void CamStateHandlers::OnDeviceInitializedState(PTP*)’:
EOSCamController:536: error: cannot declare variable ‘hnd’ to be of abstract type ‘EosEventHandlers’
eoseventhandler.h:13: note: because the following virtual functions are pure within ‘EosEventHandlers’:
/Users/John/Documents/Arduino/libraries/ptp/eoseventparser.h:37: note: virtual void EOSEventHandlers::OnObjectCreated(const EOSEvent*)
-John
I believe it has something to do with IDE version. I’m using 1.0 – try with this version ans see if it makes any difference.
Similar error in the same area;
EOSCamController.cpp: In member function ‘virtual void CamStateHandlers::OnDeviceInitializedState(PTP*)’:
EOSCamController.pde:-1: error: cannot declare variable ‘hnd’ to be of abstract type ‘EosEventHandlers’
eoseventhandler.h:13: note: because the following virtual functions are pure within ‘EosEventHandlers’:
/Users/John/Documents/Arduino/libraries/ptp/eoseventparser.h:37: note: virtual void EOSEventHandlers::OnObjectCreated(const EOSEvent*)
This is strange; I need to take a look into this, give me couple of days.
The problem is that there is one more event handler was added to EOSEventHandler class in the PTP library, but the EOSCamController sample sketch has not been changed since. It is going to be fixed in the next release of the library. Add line:
virtual void OnObjectCreated(const EOSEvent *evt) {};
to eoseventhandler.h file found in EOSCamController folder to make it running.
Hi Oleg en Alex,
Getting there…
I’ve edited the extra line in and now it compiles a lot further then before but it ends with this error;
core.a(new.cpp.o): In function `operator delete(void*)’:
X:\arduino-1.0.2\hardware\arduino\cores\arduino/new.cpp:10: multiple definition of `operator delete(void*)’
QP\qp_port.cpp.o:\\Neelix2\Users\john\My Documents\Arduino\libraries\QP/qp_port.cpp:49: first defined here
I’ve tried Arduino v1.0 / v1.0.2 and QP v4.3.00 / v4.5.02 and combinations of both.
Which version of QP should I stick with anyway?
QP v4.3.00 gave me the result above in both Arduino versions.
Cheers!
Hello,Oleg
If I want to do some experiments of USB control NIKON camera D90,I should use what library?
In my opinion should use “felis-USB_Host_Shield_2.0-2be3f61″and”PTP_2.0-master”.Is right
or wrong?Is there any other library I must want to have?
Thanks!
Can you help me,Thanks!
Bingo!
I’ve added the extra line as Alex suggested and I had commented out some extra lines in the qp_port.cpp
Now it compiles and runs with Arduino v1.0.2 and QP for Arduino v4.3.00
——
// void operator delete(void *) {
// Q_ERROR(); // this operator should never be actually called
// }
——
Thanks both for your help!
John, I would really appreciate you help here since at the moment I recieve no reply from Oleg.
I’ve followed your progress and have made these changes:
1. Replaced qp_ccp
2. Commented out these lines in the qp_port.cpp:
// void operator delete(void *) {
// Q_ERROR(); // this operator should never be actually called
// }
3. Added the following line to eoseventhandler.h file found in EOSCamController folder:
virtual void OnObjectCreated(const EOSEvent *evt) {};
Now I’m able to compile all examples except EOSRemote which spits out this error log:
EOSRemote.cpp: In member function ‘virtual void CamStateHandlers::OnDeviceInitializedState(PTP*)’:
EOSRemote.pde:-1: error: cannot declare variable ‘hnd’ to be of abstract type ‘EosEventHandlers’
/eoseventhandlers.h:12: note: because the following virtual functions are pure within ‘EosEventHandlers’:
C:\Program Files (x86)\arduino-1.0.1\libraries\ptp/eoseventparser.h:37: note: virtual void EOSEventHandlers::OnObjectCreated(const EOSEvent*)
Can you help me out with this?
Hi,
I want to do some experiments of USB control NIKON camera D90.
I added librarys “felis-USB_Host_Shield_2.0-2be3f61″and”PTP_2.0-master”base in Arduino v1.0.1.
When I compile NKEventLab.pde and NKEventMonitor.pde and NKLiveView.pde are successful.
But when I compile NKRemote.pde is unsuccessful.Because lose files such as qp_port.h,
Is any librarys I donot add?
Thanks!
Why nobody answer?
waiting…
why?
hello,all
Let nikon camera into LiveView, What command can do it?
Thanks!
Hi!
I’m also struggling with this library for 2 days now.
I’m trying to compile eosHdrCapture and tried as suggested several different verions of the arduino-ide and of the qp-library in all kinds of variants:
Arduino-ide 1.0.1/1.0.2/1.0.3
qp-lib: qp_arduino_4.3.00/ 4.5.02/ 4.5.03
The best solution yet is ArduinoIDE 1.0.1 and qp 4.3.00 with qp_ports.cpp you provided at your site.
But when I try to compile, I’m still getting errors:
core.a(new.cpp.o): In function `operator delete(void*)’:
[...]arduino\cores\arduino/new.cpp:10: multiple definition of `operator delete(void*)’
[...]arduino-1.0.1\libraries\qp/qp_port.cpp:49: first defined here
I googled around but couldn’t find a solution…
Has anybody suggestions for what I could do?
thanks in advance!
You may try to comment it out in qp_port.cpp.
Thank you very much!
That did the trick…
Hi there,
could you please share the modified code?
this would be great!
vincent.langer@filmakademie.de
thanks,
Vincent
What do you mean by “share”? It’s right here in the article.
yes and i did everything alex and hannes mentioned – but with no success!
and i thought someone who had success on windows could send me his whole arduino folder with all libraries.
Oleg,
On the basis of you librarys I succeed in making the D90 camera into the liveview mode and also MoveFocus.
Now I have a question want to your help.When let D90 into liveview mode ,D90 display screen into a blank screen
and D90 control panel display on “PC”. My question is D90 into liveview mode Can make display screen not into a blank screen?
Waiting for your help,You only need to answer” Can or NO”.Thank you very much!
I don’t think it’s possible. I experimented with several Nikon cameras, they all turn off LCD as well as video out when switched to LiveView from a PC. So basically on Nikons you can move focus but you can’t see it.
I see ,thank you!
Hi Oleg,
thank you for documenting all of the PTP commands for the Canon and Nikon cameras.
Have you had any success switching the Canon 5D MkII or 7D into BULB mode while leaving the Mode dial in MANUAL mode. Typically this is for extended HDR work to avoid touching the camera to switch from Manual to Bulb mode when exposures over 30 seconds are required as part of the exposure range.
I know it can be done as I use a programme called GBTimelapse which controls my 5D MkII via a usb tether and I can pretty much ignore what the mode dial is physically set to and use the software to switch modes.
best regards and happy new year
Kev Lewis
The GBTimelapse looks interesting and it has trial version too. Let me see if I can figure out how to implement the functionality.
Thank you for the hint!
Thank you Oleg, your background knowledge would be appreciated
Kev
hi oleg,
some time ago i baught the usb-host shield from solarbotics, it says rev 1.21.
i’m trying to get it to run on a freeduino, mega328, externally powered, with the usbhostlib 2 (from github)
when running the test-script, i get:
Press RESET to restart test
Circuits At Home 2011
USB Host Shield Quality Control Routine
Reading REVISION register… Die revision 03
SPI long test. Transfers 1MB of data. Each dot is 64K
Test failed. Value written: 01 read: 00
Unrecoverable error – test halted!!
0×55 pattern is transmitted via SPI
Press RESET to restart test
can i get the shield running?
best regards,
ralf.
I added a paragraph to the hardware manual describing how to mod the old board -> http://www.circuitsathome.com/usb-host-shield-hardware-manual , near the end of the page.
Rehi,
Works like a charm now, thanks for your great work!
Best,
Ralf
I having some trouble getting the EosCamcontroller to compile.
Arduino version 1.0.3 and using arduino qp 4.3.
I added the line virtual void OnObjectCreated(const EOSEvent *evt) {};
to eoseventhandler.h file found in EOSCamController as described above.
I commented out// void operator delete(void *) {
// Q_ERROR(); // this operator should never be actually called
// } in qp_port.cpp as noted above.
than commented out void operator delete(void *) {
Q_ERROR();
now I am left with the following error messages:
qp/qp.cpp.o: In function `QHsm::dispatch(QEvent const*)’:
/Users/fsb/Documents/Arduino/libraries/qp/qp.cpp:235: undefined reference to `Q_onAssert’
/Users/fsb/Documents/Arduino/libraries/qp/qp.cpp:246: undefined reference to `Q_onAssert’
/Users/fsb/Documents/Arduino/libraries/qp/qp.cpp:330: undefined reference to `Q_onAssert’
qp/qp.cpp.o: In function `QHsm::init(QEvent const*)’:
/Users/fsb/Documents/Arduino/libraries/qp/qp.cpp:111: undefined reference to `Q_onAssert’
/Users/fsb/Documents/Arduino/libraries/qp/qp.cpp:134: undefined reference to `Q_onAssert’
Obviously I am doing something stupid, any suggestions for help?
fsb
cleaned up libraries
Everything now compiles with IDE 1.01 and 1.03
Only cannot load Eoscamcontroller (get avrdude stk500 error)
so still working on my canon. However, NKremote works great with my
Nikon D300.
This is great Oleg, Nice work.
fsb
Hi,
To all of you that have problem compiling the library. Here is a short guide I wrote on how to do so:
These are the steps you need to do in order to compile the library:
Download the PTP library: https://github.com/felis/PTP_2.0
Extract and rename the folder to: PTP_20
Download the QP library version 4.3.00: http://sourceforge.net/projects/qpc/files/QP_Arduino/4.3.00/
Extract the QP library and navigate to the libraries/qp folder.
Now replace the qp_port.cpp with the file found here: http://www.circuitsathome.com/chome_downloads/qp_port.cpp
Now comment out the following function:
void operator delete(void *) {
Q_ERROR(); // this operator should never be actually called
}
Now put these files inside the PTP_20 directory.
Now open PTP_20/ptpdebug.h and notice these lines:
#include "../USBHost/printhex.h"
#include "../USBHost/hexdump.h"
#include "../USBHost/message.h"
You will have to change the USBHost directory to the name of your USB Host Shield library directory. For instance I had to change mine to:
#include "../USB_Host_Shield_20/printhex.h"
#include "../USB_Host_Shield_20/hexdump.h"
#include "../USB_Host_Shield_20/message.h"
Open eoseventhandler.h in PTP_20/examples/Canon_EOS/EOSCamController and eoseventhandlers.h in PTP_20/examples/Canon_EOS/EOSRemote and then add the following function:
virtual void OnObjectCreated(const EOSEvent *evt) {};
So the class end up looking like this:
class EosEventHandlers : public EOSEventHandlers
{
public:
virtual void OnPropertyChanged(const EOSEvent *evt);
virtual void OnAcceptedListSize(const EOSEvent *evt, const uint16_t size);
virtual void OnPropertyValuesAccepted(const EOSEvent *evt, const uint16_t index, const uint32_t &val);
virtual void OnObjectCreated(const EOSEvent *evt) {};
};
Now finally put the PTP_20 directory inside the Arduino libraries folder.
Now you should be able to compile the library.
Congratulations Oleg for your works !!
I have a question :
It is possible to get speed, aperture, White balance settings, and set it,
from the DSLR Nikon camera ?
Have you an PDE sketch exemple ?
I work on a project “Photographer Tools”, that is a color meter, exposure meter,
flash meter, and I search a solution (Actually I create a computer Program with the SDK Nikon)
to get and set directly the parameters mesured by my “Photographer Tools” on the DSLR.
This is the link of my project :
The good way for me,
is to use a remote module (with arduino Nano for example and bluetooth or wifi connection)
to get and set DSLR exposure values from my “Photographer Tools”.
If you have any arduino solution ?
Thanks for your reading.
Regards.
The example which does this is called NKRemote. Look in examples dir under Nikon.
Thanks oleg,
I look this.
That a good news for me (set the exposure from arduino).
Regards.
Hi all,
I have two little questions.
The usb host shield V20 is compatible with the “USB Host Shield for Arduino Pro Mini” ?
The arduino sketch “NKRemote” work with this shield and arduino pro mini ?
It is for create a very smaller transceiver with NRF24L01 Wifi module.
Yes it is compatible, but you might have to solder 5V to the VBUS line.
Thanks for info.
It is not a good news for me if I am forced to use a 3.3V to 5V boost for the VBUS. Thanks, I test all when I receive my mini shield and Arduino pro mini 3.3V.
Hi,
I’m having a bunch of trouble with PTPCapture with the new Nikon J3 (And probably other V*/J* series). Have had no problems with the software in the past and have gotten it working on other nikons ranging from Coolpix to DSLR’s.
When hooked up, it gets to the “Camera Connected” mark, then gets stuck- no image is taken. Identical un-altered sketch runs fine on others. PTP DevInfo works fine too (attached below) and it looks to me that it should support capture image.
Moreover, the “Image Capture” application on Mac OS is able to remotely trigger the camera without issues!
Any ideas? Thanks!
PTPDevInfo:
Start
Camera connected
Std.Ver.: 0×100
Vendor Ext. ID: 0×6(Microsoft)
Vend.Ext.Ver.: 0×64
microsoft.com: 1.0
Func.Mode: 0x21E0
Operations supported:
1001 GetDeviceInfo
1002 OpenSession
1003 CloseSession
1004 GetStorageIDs
1005 GetStorageInfo
1006 GetNumObjects
1007 GetObjectHandles
1008 GetObjectInfo
1009 GetObject
100A GetThumb
100B DeleteObject
100C SendObjectInfo
100D SendObject
100E InitiateCapture
100F FormatStore
1014 GetDevicePropDesc
1015 GetDevicePropValue
1016 SetDevicePropValue
101B GetPartialObject
90C0 Vendor defined
90C1 Vendor defined
90C2 Vendor defined
90C3 Vendor defined
90C4 Vendor defined
90C7 Vendor defined
90C8 Vendor defined
9201 Vendor defined
9202 Vendor defined
9203 Vendor defined
9207 Vendor defined
9801 GetObjectPropsSupported
9802 GetObjectPropDesc
9803 GetObjectPropValue
9805 GetObjectPropList
Events supported:
4001 CancelTransaction
4002 ObjectAdded
4004 StoreAdded
4005 StoreRemoved
4006 DevicePropChanged
4008 DeviceInfoChanged
4009 RequestObjectTransfer
400A StoreFull
400C StorageInfoChanged
400D CaptureComplete
Device properties supported:
5001 BatteryLevel
5004 CompressionSetting
5007 FNumber
500E ExposureProgramMode
5011 DateTime
D303 Vendor defined
D406 Session_Initiator_Version_Info
D407 Perceived_Device_Type
Capture formats:
3801 EXIF_JPEG
3000 Undefined
Image Formats:
3000 Undefined
3001 Association
3002 Script
3006 DPOF
300D QT
3801 EXIF_JPEG
380D TIFF
Manufacturer: Nikon Corporation
Model: J3
Device ver.: Ver.1.0001