dynamic_sender.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009, Morgan Quigley, Clemens Eppner, Tully Foote
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  * 
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Stanford U. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  * 
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 // Modified Apr 6, 2010 by Adam Leeper - changed to use "image_transport"
00031 // Modified Aug 4, 2010 by Stefan Diewald - changed to fit Whiteboard robot's need
00032 
00033 #include <cstdio>
00034 #include <ros/ros.h>
00035 #include <ros/time.h>
00036 #include "uvc_cam/uvc_cam.h"
00037 #include "sensor_msgs/CameraInfo.h"
00038 #include "sensor_msgs/Image.h"
00039 #include "sensor_msgs/CompressedImage.h"
00040 #include "sensor_msgs/image_encodings.h"
00041 #include <camera_calibration_parsers/parse_ini.h>
00042 #include <dynamic_reconfigure/server.h>
00043 #include <corobot_camera/corobot_cameraConfig.h>
00044 #include <diagnostic_updater/diagnostic_updater.h>
00045 #include <diagnostic_updater/publisher.h>
00046 
00047 #include <image_transport/image_transport.h>
00048 #include <opencv/cvwimage.h>
00049 #include <opencv/highgui.h>
00050 
00051 #if not (ROS_VERSION_MINIMUM(1, 9, 0)) //If the ROS version is bellow Groovy, as cv_bridge is not present in groovy anymore
00052         #include <cv_bridge/CvBridge.h>
00053 #endif
00054 
00055 // get the messages
00056 #include "std_msgs/String.h"
00057 #include "corobot_srvs/setcontrol.h"
00058 #include "corobot_srvs/control.h"
00059 #include "corobot_msgs/videomode.h"
00060 #include "corobot_msgs/state.h"
00061 
00062 sensor_msgs::CameraInfo::Ptr camera_info;
00063 
00064 // the possible states
00065 enum e_state {PLAYING, STOP, CHANGE_MODE};
00066 char state = STOP;
00067 
00068 // variables to change width and height
00069 int new_width, new_height, new_fps;
00070 bool auto_exposure = true;
00071 bool camera_activated = true;
00072 int camera_state = 0; // This is used for the diagnostic function to know what to report to the user
00073 bool isjpeg = false;
00074 // pointer to cam
00075 uvc_cam::Cam * cam_ptr;
00076 
00077 /*
00078  *      change the state of the video sender:
00079  *
00080  *              - start: stream images
00081  *              - stop:  stop streaming
00082  */
00083 void stateCallback(const corobot_msgs::state::ConstPtr& msg) {
00084         if (msg->state == std::string("start")) {
00085                 state = PLAYING;
00086                 ROS_INFO("Camera starting...");
00087         }
00088         else if (msg->state == std::string("stop")) {
00089                 state = STOP;
00090                 ROS_INFO("Camera stopping...");
00091         }
00092 }
00093 
00094 /*
00095  *      change the image resolution (width, height) and fps
00096  *
00097  *              As there is no error handling built-in at the moment please be sure that you only set available width, height and fps.
00098  */
00099 void videomodeCallback(const corobot_msgs::videomode::ConstPtr& msg) {
00100         new_width = msg->width;
00101         new_height = msg->height;
00102         new_fps = msg->fps;
00103         auto_exposure = msg->auto_exposure;
00104         
00105         ROS_INFO("Receiced new video parameters: %dx%d, %d fps", new_width, new_height, new_fps);
00106 
00107         if ((bool)msg->immediately)
00108                 state = CHANGE_MODE;
00109 }
00110 
00111 /*
00112  *      set a control by the numeric id (see /usr/include/linux/videodev2.h for further control ids (CIDs))
00113  */
00114 bool setcontrol(corobot_srvs::setcontrol::Request  &req,
00115                                 corobot_srvs::setcontrol::Response &res ) {
00116         if (state == PLAYING) {
00117                 res.result = true;
00118 
00119                 try {
00120                         cam_ptr->set_control(req.id, req.value);
00121                 } catch (std::runtime_error& e) {
00122                         ROS_ERROR("Unable to set control %d to value %d. (%s)", req.id, req.value, e.what());
00123                         res.result = false;
00124                 }
00125 
00126                 return true;
00127         } else {
00128                 ROS_ERROR("Camera not running.");
00129                 return false;
00130         }
00131 }
00132 
00133 
00134 
00135 /*
00136  *      creates the uvc_cam object and gets the frames in a loop
00137  */
00138 void mainloop(const char* device, int width, int height, int fps, ros::NodeHandle n, image_transport::CameraPublisher pub, diagnostic_updater::Updater& updater)
00139 {
00140         ROS_INFO("Opening uvc_cam at %s with %dx%d, %d fps, auto-exposure: %s", device, width, height, fps, (auto_exposure)?"true":"false");
00141         ros::Rate r(5);
00142         // instantiate uvc_cam
00143         uvc_cam::Cam::mode_t mode;
00144         if(isjpeg)
00145                 mode = uvc_cam::Cam::MODE_MJPG;
00146         else
00147                 mode = uvc_cam::Cam::MODE_RGB;
00148         
00149         // create an IplImage Header for the later transformation to Image
00150         IplImage *imageIpl = cvCreateImageHeader(cvSize(width, height), 8, 3);
00151 
00152         ros::Time t_prev(ros::Time::now());
00153         uint64_t count = 0, skip_count = 0;
00154 
00155         int buf_idx = 0;
00156         unsigned char *frame = NULL;
00157         uint32_t bytes_used;
00158          unsigned int pair_id = 0;
00159 
00160         bool camera_activated = false;
00161         uvc_cam::Cam *cam;
00162 
00163         // run as long as ROS is running and videomode should not be changed or camera should not be stopped
00164         while (n.ok() && state == PLAYING) {
00165                 // only publish camera images if there is at least one subscriber
00166                 if(pub.getNumSubscribers() > 0)
00167                 {
00168                         camera_state = 0;
00169                         if (!camera_activated)
00170                         {
00171                                 try
00172                                 {
00173                                         cam = new uvc_cam::Cam(device, mode, width, height, fps);
00174                                         cam_ptr = cam;
00175                                         camera_activated = true;
00176                                 }
00177                                 catch (std::runtime_error &ex)
00178                                 {
00179                                         camera_state = 4;
00180                                         camera_activated = false;
00181                                 }
00182                         }
00183 
00184                         if (camera_activated)
00185                         {
00186                                 // get one frame
00187                                 buf_idx = cam->grab(&frame,bytes_used);
00188                                 if (buf_idx == -1)
00189                                         camera_state = 3;
00190                                 // do fps counting
00191                                 if (count++ % fps == 0) {
00192                                         ros::Time t(ros::Time::now());
00193                                         ros::Duration d(t - t_prev);
00194                                         ROS_DEBUG("%.1f fps skip %llu", (double) fps / d.toSec(), skip_count);
00195                                         t_prev = t;
00196                                 }
00197         
00198                                 // if we could grab a frame
00199                                 if (frame) {
00200                                 
00201                                         sensor_msgs::ImagePtr image(new sensor_msgs::Image);
00202         
00203                                         image->height = height;
00204                                         image->width = width;
00205                                         image->step = 3 * width;
00206                                         image->encoding = sensor_msgs::image_encodings::RGB8;
00207         
00208                                         ros::Time capture_time = ros::Time::now();
00209 
00210                                         image->header.stamp = capture_time;
00211                                         image->header.seq = pair_id;
00212  
00213                                         std::string frameid = "camera";
00214                                         image->header.frame_id = frameid;
00215 
00216                                         image->data.resize(image->step * image->height);
00217  
00218                                         memcpy(&image->data[0], frame, width*height * 3);
00219 
00220                                         // publish image & camera_info
00221                                         pub.publish(image, camera_info);
00222                 
00223                                         // the camera sets user settings like exposure time around the 50th frame
00224                                         if (count == 50)
00225                                                 ROS_DEBUG("User settings applied.");
00226 
00227                                         // release the frame
00228                                         cam->release(buf_idx);
00229                                 } else // there was no frame
00230                                         skip_count++;
00231                                 }
00232                                 
00233                         }               
00234                 else
00235                 {
00236                         camera_state = 2;
00237                         if (camera_activated)
00238                         {
00239                                 delete cam;
00240                                 cam = NULL;
00241                                 cam_ptr = NULL;
00242                                 camera_activated = false;
00243                         }
00244                         ROS_INFO("out of while loop");
00245                         r.sleep();
00246                 }
00247                 // for the callbacks
00248                 updater.update();
00249                 ros::spinOnce();
00250         }
00251 }
00252 
00253 void dynamic_reconfigureCallback(corobot_camera::corobot_cameraConfig &config, uint32_t level) {
00254                 camera_activated = config.camera_activated;
00255 }
00256 
00257 void webcam_diagnostic(diagnostic_updater::DiagnosticStatusWrapper &stat)
00261 {
00262         if (camera_state == 0)  
00263                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::OK, "The camera is working");
00264         else if (camera_state == 1)
00265         {
00266                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "The user has stopped the camera");
00267                 stat.addf("Recommendation", "Please restart the node. If the problem persists, make sure the immediately parameter is set to true.");
00268         }
00269         else if (camera_state == 2)
00270         {
00271                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::WARN, "No subscriber to the camera topic");
00272                 stat.addf("Recommendation", "Please start a node that uses the camera. If using corobot_teleop, make sure the connect button has been clicked and that you are on a tab that permits you to visualize the camera.");
00273         }
00274         else if (camera_state == 3)
00275         {
00276                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Could not grab the image");
00277                 stat.addf("Recommendation", "Please make sure the camera is not disconnected. Also make sure that you have the necessary permissions to access the camera");
00278         }
00279         else if (camera_state == 4)
00280         {
00281                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Could not initialize the camera");
00282                 stat.addf("Recommendation", "Please make sure the camera is not disconnected. Also make sure that you have the necessary permissions to access the camera");
00283         }
00284 
00285 }
00286 
00287 
00288 int main(int argc, char **argv) {
00289         ros::init(argc, argv, "corobot_camera");
00290         ros::NodeHandle n;
00291         ros::NodeHandle n_private("~");
00292         bool immediately;
00293 
00294         dynamic_reconfigure::Server<corobot_camera::corobot_cameraConfig> server;
00295         dynamic_reconfigure::Server<corobot_camera::corobot_cameraConfig>::CallbackType f;
00296 
00297         f = boost::bind(&dynamic_reconfigureCallback, _1, _2);
00298         server.setCallback(f);
00299 
00300         // image transport with publisher
00301         image_transport::ImageTransport it(n);
00302         image_transport::CameraPublisher pub;
00303 
00304 
00305         ros::Subscriber videomode_sub = n.subscribe("/camera/set_videomode", 1000, videomodeCallback);
00306         ros::Subscriber state_sub = n.subscribe("/camera/set_state", 1000, stateCallback);
00307         
00308         // create services to get and set controls
00309         ros::ServiceServer set_control_service = n.advertiseService("/camera/set_control", setcontrol);
00310 
00311         // get the parameters
00312         std::string device;     
00313         std::string out_topic;
00314         n_private.param<std::string>("device", device, "/dev/video0");
00315         n_private.param<std::string>("topic", out_topic, "/camera/image_raw");
00316         n_private.param("width", new_width, 960);
00317         n_private.param("height", new_height, 720);
00318         n_private.param("fps", new_fps, 30); 
00319         n_private.param("isjpeg", isjpeg, false); 
00320 
00321         std::string cameara_parameter_file;
00322         n_private.param<std::string> ("camera_parameter_file", cameara_parameter_file, "../camera_parameters.txt");
00323         
00324         n_private.param("immediately", immediately, true);
00325 
00326         if (immediately)
00327                 state = CHANGE_MODE;
00328         // camera_name is read out of the camera_parameter_file, not further used here
00329         std::string camera_name;
00330         // create a CameraInfo variable
00331         camera_info.reset(new sensor_msgs::CameraInfo);
00332         // read out the "ini" file
00333         if (camera_calibration_parsers::readCalibrationIni(cameara_parameter_file, camera_name, *camera_info)) {
00334                 ROS_INFO("Successfully read camera calibration.");
00335         } else {
00336                 ROS_ERROR("No camera_parameters.txt file found.");
00337         }
00338         // create an image publisher
00339 
00340         pub = it.advertiseCamera(out_topic.c_str(), 1);
00341         
00342         //create an updater that will send information on the diagnostics topics
00343         diagnostic_updater::Updater updater;
00344         updater.setHardwareIDf("Webcam");
00345         updater.add("Webcam", webcam_diagnostic); //function that will be executed with updater.update()
00346 
00347         /*sleep to overcome the problem of mjpg-streamer (called for 1 seconds in corobot_pantilt node) and this node to change the camera format at the same time. */
00348         sleep(1);
00349 
00350         while (n.ok()) {
00351                 // set it playing again after the parameter were changed
00352                 if (state == CHANGE_MODE)
00353                         state = PLAYING;
00354 
00355                 // start the mainloop which publishes images
00356                 if (state == PLAYING) {
00357                         camera_state = 0;
00358                         mainloop(device.c_str(), new_width, new_height, new_fps, n, pub, updater);
00359                 }
00360                 else
00361                         camera_state = 1;
00362                 updater.update();
00363                 ros::spinOnce();
00364         }
00365         return 0;
00366 }
00367 


corobot_camera
Author(s): Morgan Cormier/mcormier@coroware.com
autogenerated on Tue Jan 7 2014 11:39:24