Saturday, June 2, 2012

Arduino passive IR trigger for Canon EOS

The other day I wanted to experiment with external triggers for my Canon EOS 550D camera. I stumpled upon a nice open source project called Arduino Camera Control from Oleg Mazurov, the creator of the USB Host Shield library for Arduino.

The Arduino Camera Control project depends on the USB Host Shield library and the USB Host Shield from Sparkfun. It supports Canon EOS and Powershot, as well as Nikon DSLRs and P&S cameras. My main objective was sending commands to the camera for capturing images. The library does much more than that but if you want more detailed information about the library, you should read the original article on Circuits@Home.

In this post I want to show you how to use a passive infrared module for triggering the camera to take a picture. First off, the list of things you'll need for this project.

Now let's connect all the parts like shown in the Fritzing schematic.

Before you can upload this project's sketch, you'll need to install some libraries into your Arduino IDE.
Now depending on the USB Host Shield you are using, there are two variants of libraries you can install. If you are using the Sparkfun USB Host Shield then you'll need to install the following two libraries into your Arduino libraries folder (..\arduino-0022\libraries\).

If you are using the USB Host Shield 2.0 from Circuits@Home, then please install the ported versions of the libraries found here.

Now after installing the libraries you can copy the following Arduino sketch in a new sketch window and upload it to the board.

 #include <inttypes.h>  
 #include <avr/pgmspace.h>  
 #include <Max3421e.h>  
 #include <Max3421e_constants.h>  
 #include <Max_LCD.h>  
 #include <Usb.h>  
 #include <ptp.h>  
 #include <canoneos.h>  
 #include <MemoryFree.h>  
 #define DEV_ADDR    1  
 // Canon EOS 400D  
 #define DATA_IN_EP   1  
 #define DATA_OUT_EP   2  
 #define INTERRUPT_EP  3  
 #define CONFIG_NUM   1  
 //PIR definitions and declarations  
 #define SLEEP_MODE_PIN 4  
 #define MOTION_DETECT_PIN 2  
 int val;  
 class CamStateHandlers : public PTPStateHandlers  
    bool stateConnected;  
    CamStateHandlers() : stateConnected(false) {};  
    virtual void OnDeviceDisconnectedState(PTP *ptp);  
    virtual void OnDeviceInitializedState(PTP *ptp);  
 } CamStates;  
 void CamStateHandlers::OnDeviceDisconnectedState(PTP *ptp)  
   if (stateConnected)  
     stateConnected = false;  
     Notify(PSTR("Camera disconnected\r\n"));  
 void CamStateHandlers::OnDeviceInitializedState(PTP *ptp)  
   if (!stateConnected)  
     stateConnected = true;  
   uint16_t rc = Eos.Capture();  
   if (rc != PTP_RC_OK)  
     Message(PSTR("Error: "), rc);  
 void setup()   
  Serial.begin( 115200 );  
  delay( 200 );  
  //PIR related  
  digitalWrite(SLEEP_MODE_PIN, HIGH);  
 void loop()   
  val = digitalRead(MOTION_DETECT_PIN);  
  //the ePIR sensor is active low so if motion is detected the output is low  
  if(val == LOW) {  

The sketch is essentially just an extended version of the EOSCapture example from the Arduino Camera Control library. What it does is to poll the PIR sensor for changes. The PIR sensor used here is active low, so if the PIR sensor is triggered the signal on the motion detect pin becomes low, meaning the voltage on the pin is dropping towards 0V. If that's the case, the Eos.Task() function will be called which sends a control signal to the camera instructing it to take a picture. That's all there is.

Now upload the sketch to the Arduino board and connect your Canon EOS camera to the USB Host Shield. Turn on the camera and try triggering a photo by waving your hand in front of the sensor. If the camera wasn't properly recognized by the USB Host Shield, try to select the M-mode on the camera or try to push the capture button on the camera. The board needs to establish a session with the camera before sending command transactions. If your board is still connected to your computer open up the Serial Monitor within the Arduino IDE to see if a session was opened.

If everything works out your final project should work like shown here.

Now you can finally take pictures of animals or people when you are not around. A good use case would probably be wild-life photography.


  1. Hello

    I get errors with nearly the same configuration. I connect a canon g6 using oleg libraries(old versions). here are the errors :
    Data packet error: 4
    Data packet error: 4Data packet error: 4Session opened
    Fatal USB Error
    Transaction: Response recieve error: 0004
    StartShootingMode failed: : 2002
    Initialization error
    Fatal USB Error
    Transaction: Response recieve error: 0004
    EOSEventCheck error: : 2002
    Transaction: Command block send error: 0004
    EOSEventCheck error: : 2002
    Transaction: Command block send error: 0004
    Transaction: Command block send error: 0004
    Focus Lock Error: : 2002
    Transaction: Command block send error: 0004
    Capture Error: : 2002
    Error: : 2002
    Transaction: Command block send error: 0004
    EOSEventCheck error: : 2002

    Did have those errors? Thanks for your help

    1. Sorry I didn't get these errors. My setup luckily just worked. According to the output you can't get any command transaction through. You will have to ask the guys Circuits@Home for support. Maybe the library doesn't play along nicely with your camera's firmware or USB chipset.

      Sorry can't help.

  2. Awesome post Mario! Hey are you sure your pinouts on the Zilog ePIR are correct on the diagram? It looks like it just mapped Arduino pin 2 to ePir pin 2 and Arduino pin 4 to ePir Pin 4. I think you meant that Arduino pin 2 (MOTION DETECT PIN) to go to ePir Pin 5 (MOTION DETECT) and Arduino pin 4 (SLEEP MODE PIN) to go to ePir Pin 7 (SLEEP). But, maybe your ePir has different pinouts than mine?

  3. I guess it's been a while but I'm running through this right now and for Dave and Helene (and anyone reading this) - ePIR pin 1 is on the bottom in the diagram so that the sensor is facing away from the breadboard, so the diagram looks to be correct with Arduino pin 2 connecting to ePIR pin 5 (MD) and Arduino pin 4 connecting to ePIR pin 7 (SLP) - haven't fired this up yet but looks like it should work!