using motion to control a camera


3 posts
by f32mark » Sat Nov 10, 2012 2:48 pm
After a bit of head scratching, I've finally managed to control a remote camera (a canon 60D in this example) using the motion package and a webcam to detect movement. Ive installed the gphoto2 library and used the sample code provided here http://sepharads.blogspot.co.uk/2011/11/camera-tethered-capturing-using.html as a starter.

The code is below, feel free to use it yourself. The setup uses a HP webcam and a usb connection to the Canon (I run the Pi headless, ie no screen, keyboard etc, just a network connection). The program assumes the motion.conf file is in the same directory as you run the program from (where it also stores the photo files), and it will assume that a line like this is at the end of the file:

on_motion_detected sudo kill -s 36 2277

I use the kill command to send a signal (36) to the running program that controls the canon. I use this method as I found constantly opening and closing the connection to the canon via usb fails after a couple of times and needs the camera shutting down. You need to install the lgphoto2 library, compiling is via the command:
gcc -0 camera camera.c -lgohoto2.


if you start the program with a 'Y' as a single argument, the original file is deleted from the camera:

./camera Y

Close down is a bit chaotic at the moment! The program should halt if you type 'n' at the keyboard, but it doesn't !

Here's the code:
Code: Select all
#include <stdio.h>
#include <fcntl.h>
#include <gphoto2/gphoto2-camera.h>
#include <signal.h>
#include <string.h>
#define TAKE_PHOTO 36

Camera *camera;
GPContext *context;
int outfileno;
char delornot[256];

void error_func (GPContext *context, const char *format, va_list args, void *data)
{
   fprintf(stderr, "*** Contexterror ***\n");
   vfprintf(stderr, format, args);
   fprintf(stderr, "\n");
}
void message_func (GPContext *context, const char *format, va_list args, void *data)
{
   vprintf(format, args);
   printf("\n");
}
int capture (const char *filename, char *delornot)
{
   int fd, retval;
   CameraFile *file;
   CameraFilePath camera_file_path;
   int waittime = 2000;
   CameraEventType type;
   void *data;
      
   /* take a shot */
   retval = gp_camera_capture(camera, GP_CAPTURE_IMAGE, &camera_file_path, context);
   if (retval)
   {
            printf("Error taking shot, error is %i\n",retval);
   }
   printf("Pathname on the camera: %s/%s\n", camera_file_path.folder, camera_file_path.name);
   fd = open(filename, O_CREAT | O_WRONLY, 0644);
   /* create new CameraFile object from a file descriptor */
   retval = gp_file_new_from_fd(&file, fd);
   if (retval)
   {
         printf("Error creating file, error is %i\n",retval);
   }
   /* copy picture from camera */
   retval = gp_camera_file_get(camera, camera_file_path.folder, camera_file_path.name,
                               GP_FILE_TYPE_NORMAL, file, context);
   if (retval)
   {
         printf("Error copying from camera, error is %i\n",retval);
   }
   if(delornot = "Y")
   {
      printf("Deleting\n");
      /*  remove picture from camera memory */
      retval = gp_camera_file_delete(camera, camera_file_path.folder, camera_file_path.name,
                                  context);
      if (retval)
      {
         printf("Error deleting from camera, error is %i\n",retval);
      }
   }
   /* free CameraFile object */
   gp_file_free(file);
// Code from here waits for camera to complete everything.
// Trying to take two successive captures without waiting
// will result in the camera getting randomly stuck.

   printf("Wait for events from camera\n");
   while (1)
   {
      retval = gp_camera_wait_for_event(camera, waittime, &type, &data, context);
      if (type == GP_EVENT_TIMEOUT)
      {
         break;
      }
      else if (type == GP_EVENT_CAPTURE_COMPLETE)
      {
         printf("Capture completed\n");
         waittime = 100;
      }
      else if (type != GP_EVENT_UNKNOWN)
      {
         printf("Unexpected event received from camera: %d\n", (int)type);
      }
   }
   return 0;
}



void takephoto(int num)
{
    char filename[256];
   
   sprintf(filename,"shot-%04d.jpg", outfileno++);
   printf("Capturing to file %s\n", filename);
   capture(filename,delornot);
}

int main (int argc, char *argv[])
{
   char inp;
   char buff[256];
   int pid;
   FILE *fp;
   
   /* delete file on camera? */
   if (argc == 2)
   {
      strcpy(delornot, argv[1]);
      if(strcmp("Y",delornot))
         printf("deleting original file on camera\n");
      else
         printf("keeping file on camera\n");
   }
   pid = getpid();
   printf("processID is %i\n",pid);
   
   /* set file counter to zero */

   outfileno = 0;
   /* open motion.conf */

   fp = fopen ("motion.conf","r+");
   if(fp == NULL)
   {
      printf("cannot open motion.conf\n");
      return -1;
   }

   /* set command to send signal to take a photo when motion detected */

   
   sprintf(buff,"on_motion_detected sudo kill -s %2i %6i\n",TAKE_PHOTO,pid);
   fseek(fp,(0 - strlen(buff)),SEEK_END);
   fprintf(fp,buff);
   fclose(fp);
   gp_camera_new (&camera);
   
   context = gp_context_new();
   /* set callbacks for camera messages */
   gp_context_set_error_func(context, error_func, NULL);
   gp_context_set_message_func(context, message_func, NULL);

   int ret = gp_camera_init(camera, context);
   if (ret < GP_OK)
   {
      printf("No camera auto detected.\n");
      gp_camera_free(camera);
      return 1;
   }
   
   /* on receipt of signal take a photo */
   
   signal(TAKE_PHOTO,takephoto);

   /* start motion */

   if (system("motion  > /dev/null")!=0)
   {
      printf("failed to start motion\n");
      return -1;
   }
   inp = 'y';

   /*  do some capturing */
   while(inp != 'n')
   {
      inp = getchar();
   }
   /* close camera */
   gp_camera_unref(camera);
   gp_context_unref(context);
   return 0;
}

Posts: 36
Joined: Wed Sep 05, 2012 4:58 am
by Jan1 » Wed Nov 14, 2012 10:25 am
Thanks for sharing your code.
I face a similar problem.
Do you know if it is possible to use TWO cameras at the same time?
I was also thinking about using Pi, but now I am not sure what advantage( to use Pi ) is.
You will have to add a screen( LCD panel) to check pictures taken by the camera, so price will increase.
Why do you use PI and not a laptop or tablet instead?
Is there any advantage then?

Thank you for reply
Posts: 10
Joined: Tue Nov 13, 2012 7:22 pm
by f32mark » Wed Nov 14, 2012 11:33 am
Jan1 wrote:Thanks for sharing your code.
I face a similar problem.
Do you know if it is possible to use TWO cameras at the same time?
I was also thinking about using Pi, but now I am not sure what advantage( to use Pi ) is.
You will have to add a screen( LCD panel) to check pictures taken by the camera, so price will increase.
Why do you use PI and not a laptop or tablet instead?
Is there any advantage then?

Thank you for reply

Jan1,
I access the Pi via the network, so I don't need an extra screen. This means I can make the control device small cheap and portable.
As to controlling two cameras, I don't see why not. The gphoto2 command line will show you all usb connected cameras, use the --auto-detect parameter.

EDIT:
yes you can control more than one camera. Take a look at the source for gp_camera_init to see how it'll either default to the first camera it finds (how I'm using the library), or uses a defined camera.

http://libgphoto2.sourcearchive.com/doc ... 68a9e.html
Posts: 36
Joined: Wed Sep 05, 2012 4:58 am