This website uses browsing/session and functional cookies to ensure you get the best experience. Learn More

Modifying a YARP Driver

From Wiki for iCub and Friends
Jump to: navigation, search

This page documents the steps taken to make a small change to an existing driver. For background information, or creating a new device, see:

This page is just concerned with making a small change to an existing driver.

Contents

The change we'd like to make

The opencv_grabber device can read a movie, which is handy for testing programs designed to operate normally on input from a camera. At the time of writing, when the movie finishes black images are generated. It would be nice if instead the device could be asked to loop.

For example, we can currently do:

yarpview /view &
yarpdev --device opencv_grabber  --movie /scratch/show.avi --framerate 10 --name /grabber --verbose
 yarp connect /grabber /view

but would like to be able to add a --loop flag.

Without knowing much about YARP, how do we track down where to make this change?

Finding the device documentation

First, lets start with what we do know, which is the name of the device: opencv_grabber. If we do:

 yarpdev --list

we'll see everything yarpdev knows about all devices, including the one we care about:

 Here are devices listed for your system:
 ...
 Device "opencv_grabber", C++ class OpenCVGrabber, wrapped by "grabber"

So the class associated with the device is called "OpenCVGrabber".

We can go to the YARP User Documentation and search for this class name.

This leads to a description of the class, which mentions its author (Eric Mislevic). We could try to track Eric down, or continue ourselves. Let's continue ourselves.

Finding the source code

Now we need to find the source code for the class. The name of the header file is mentioned in the documentation (OpenCVGrabber.h) so we can just search in our YARP source repository for that. For example, here's what I did on my Linux box:

 paulfitz@contact:~/cvs/yarp2$ find src -name OpenCVGrabber.h
 src/libYARP_dev/src/opencv_grabber/common/yarp/OpenCVGrabber.h

This is indeed the header file corresponding to the documentation we already found.

Now where's the implementation, the cpp file? The directory structure of devices is documented in the Device Driver How-To. It is a little complicated because sometimes there are multiple implementations for different operating systems. Let's now worry about the details here and take a look at the structure of the "opencv_grabber" directory we found:

 paulfitz@contact:~/cvs/yarp2$ find src/libYARP_dev/src/opencv_grabber | grep -v CVS
 src/libYARP_dev/src/opencv_grabber
 src/libYARP_dev/src/opencv_grabber/common
 src/libYARP_dev/src/opencv_grabber/common/yarp
 src/libYARP_dev/src/opencv_grabber/common/yarp/OpenCVGrabber.h
 src/libYARP_dev/src/opencv_grabber/default
 src/libYARP_dev/src/opencv_grabber/default/yarp
 src/libYARP_dev/src/opencv_grabber/default/yarp/OpenCVGrabber.cpp
 src/libYARP_dev/src/opencv_grabber/default/libraries.txt

So the only relevant C files are:

 src/libYARP_dev/src/opencv_grabber/common/yarp/OpenCVGrabber.h
 src/libYARP_dev/src/opencv_grabber/default/yarp/OpenCVGrabber.cpp

What should we change?

Now we have to figure out the right change to make. Let's forget about making the device configurable for a moment, and pretend we ALWAYS want it to loop. How can we do this?

Images are read in opencv using cvQueryFrame. we find this in the getImage method. We see that if this call fails, as it presumably does when the movie runs out, then "zeroed" images are returned. So this is the point we need to modify.

The easiest way to kickstart the movie again is just to restart the device by calling open() with a saved copy of the configuration. So that's what I tried first. There are no general rules here, you just have to read the code, figure out what's going on, and make the change you need.

Trying out your change

When you've changed something, you need to recompile:

 paulfitz@contact:~/cvs/yarp2$ make
 [ 45%] Built target YARP_OS
 [ 70%] Built target harness_os
 [ 71%] Built target yarp
 [ 78%] Built target YARP_sig
 [ 82%] Built target harness_sig
 Scanning dependencies of target YARP_dev
 [ 83%] Building CXX object src/libYARP_dev/CMakeFiles/YARP_dev.dir/src/opencv_grabber/default/yarp/OpenCVGrabber.o
 [ 84%] Building CXX object src/libYARP_dev/CMakeFiles/YARP_dev.dir/src_generated/PopulateDrivers.o
 Linking CXX static library ../../lib/libYARP_dev.a
 [ 97%] Built target YARP_dev
 Linking CXX executable ../../bin/harness_dev
 [ 98%] Built target harness_dev
 Linking CXX executable ../../bin/yarpdev
 [ 99%] Built target yarpdev
 Linking CXX executable ../../bin/yarphear
 [100%] Built target yarphear

Good, everything compiled. And upon trying out the motivating example at the start of this page, the video looped as expected.

Cleaning up

When you change the behavior of a device, it is good not to surprise anyone already using the device with new behavior. So let's only use looping if it is requested with a --loop option. We do this by adding a boolean variable (called m_loop to fit into the existing programmer's style) and add the following code in the "open" method:

 // Should we loop?
 m_loop = config.check("loop","if present, loop movie");

Then we make our new behavior conditional on this flag.

It is important to check that the flag works -- that without it, behavior is as before, and with it, behavior is as we want. So we recompile and retest.

Also, we should check that the documentation for our new new flag is understandable in yarpdev with the --verbose option:

 $ yarpdev --device opencv_grabber  --movie /scratch/show.avi --framerate 1 --verbose 
 ...
 ===============================================================
 == Options checked by device:
 == 
 device=opencv_grabber
 grabber.subdevice=opencv_grabber
     name (or nested configuration) of device to wrap
 opencv_grabber.device=opencv_grabber
 opencv_grabber.movie=/scratch/show.avi
     if present, read from specified file rather than camera
 opencv_grabber.loop
     if present, loop movie
     ...
Personal tools
Namespaces

Variants
Actions
Navigation
Print/export
Toolbox