00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 #include <cstdio>
00035 #include <ros/ros.h>
00036 #include <ros/time.h>
00037 #include "uvc_cam/uvc_cam.h"
00038 #include "sensor_msgs/CameraInfo.h"
00039 #include "sensor_msgs/Image.h"
00040 #include "sensor_msgs/CompressedImage.h"
00041 #include "sensor_msgs/image_encodings.h"
00042 #include <camera_calibration_parsers/parse_ini.h>
00043 #include <dynamic_reconfigure/server.h>
00044 #include <corobot_camera/corobot_cameraConfig.h>
00045 #include <diagnostic_updater/diagnostic_updater.h>
00046 #include <diagnostic_updater/publisher.h>
00047 #include "corobot_diagnostics/diagnostics.h"
00048 
00049 #include <image_transport/image_transport.h>
00050 #include <opencv/cvwimage.h>
00051 #include <opencv/highgui.h>
00052 
00053 
00054 #if not (ROS_VERSION_MINIMUM(1, 9, 0)) 
00055         #include <cv_bridge/CvBridge.h>
00056 #endif
00057 
00058 
00059 #include "std_msgs/String.h"
00060 #include "corobot_msgs/videomode.h"
00061 #include "corobot_msgs/state.h"
00062 
00063 sensor_msgs::CameraInfo::Ptr camera_info;
00064 ros::Publisher image_pub;
00065 
00066 
00067 enum e_state {PLAYING, STOP, CHANGE_MODE};
00068 char state = STOP;
00069 
00070 
00071 int new_width, new_height, new_fps;
00072 
00073 
00074 bool auto_exposure = true;
00075 
00076 
00077 bool camera_activated = true;
00078 
00079 
00080 int camera_state = 0;
00081 
00082 
00083 bool isjpeg = false;
00084 
00085 
00086 uvc_cam::Cam * cam_ptr;
00087 
00088 
00089 
00090 
00091 
00092 
00093 
00094 void stateCallback(const corobot_msgs::state::ConstPtr& msg) {
00095         if (msg->state == std::string("start")) {
00096                 state = PLAYING;
00097                 ROS_INFO("Camera starting...");
00098         }
00099         else if (msg->state == std::string("stop")) {
00100                 state = STOP;
00101                 ROS_INFO("Camera stopping...");
00102         }
00103 }
00104 
00105 
00106 
00107 
00108 
00109 
00110 void videomodeCallback(const corobot_msgs::videomode::ConstPtr& msg) {
00111         new_width = msg->width;
00112         new_height = msg->height;
00113         new_fps = msg->fps;
00114         auto_exposure = msg->auto_exposure;
00115         
00116         ROS_INFO("Receiced new video parameters: %dx%d, %d fps", new_width, new_height, new_fps);
00117 
00118         if ((bool)msg->immediately)
00119                 state = CHANGE_MODE;
00120 }
00121 
00122 
00123 const static unsigned char dht_data[] = {
00124 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
00125 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
00126 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03,
00127 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
00128 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
00129 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05,
00130 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
00131 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22,
00132 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15,
00133 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17,
00134 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36,
00135 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
00136 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
00137 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
00138 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95,
00139 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
00140 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
00141 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
00142 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
00143 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
00144 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05,
00145 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
00146 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
00147 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33,
00148 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
00149 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,
00150 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
00151 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
00152 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
00153 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
00154 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
00155 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
00156 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
00157 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
00158 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
00159 }; 
00160 
00161 
00162     
00163 int is_huffman(unsigned char *buf)
00164 {
00165     unsigned char *ptbuf;
00166     int i = 0;
00167     ptbuf = buf;
00168     while(((ptbuf[0] << 8) | ptbuf[1]) != 0xffda) {
00169         if(i++ > 2048)
00170             return 0;
00171         if(((ptbuf[0] << 8) | ptbuf[1]) == 0xffc4)
00172             return 1;
00173         ptbuf++;
00174     }
00175     return 0;
00176 } 
00177          
00178 
00179 
00180 
00181 void mainloop(const char* device, int width, int height, int fps, ros::NodeHandle n, image_transport::CameraPublisher pub, diagnostic_updater::Updater& updater)
00182 {
00183         ROS_INFO("Opening uvc_cam at %s with %dx%d, %d fps, auto-exposure: %s", device, width, height, fps, (auto_exposure)?"true":"false");
00184         ros::Rate r(fps);
00185         
00186         uvc_cam::Cam::mode_t mode;
00187         if(isjpeg)
00188                 mode = uvc_cam::Cam::MODE_MJPG;
00189         else
00190                 mode = uvc_cam::Cam::MODE_RGB;
00191 
00192         ros::Time t_prev(ros::Time::now());
00193         uint64_t count = 0, skip_count = 0;
00194 
00195         int buf_idx = 0;
00196         unsigned char *frame = NULL;
00197         uint32_t bytes_used;
00198          unsigned int pair_id = 0;
00199 
00200         bool camera_activated = false;
00201         uvc_cam::Cam *cam;
00202         
00203         
00204         sensor_msgs::ImagePtr image(new sensor_msgs::Image);
00205         image->height = height;
00206         image->width = width;
00207         image->step = 3 * width;
00208         image->encoding = sensor_msgs::image_encodings::RGB8;
00209         image->data.resize(image->step * image->height);
00210 
00211         
00212         while (n.ok() && state == PLAYING) {
00213                 
00214                 if(pub.getNumSubscribers() > 0 || image_pub.getNumSubscribers() > 0)
00215                 {
00216                         camera_state = 0;
00217                         if (!camera_activated) 
00218                         {
00219                                 try
00220                                 {
00221                                         cam = new uvc_cam::Cam(device, mode, width, height, fps);
00222                                         cam_ptr = cam;
00223                                         camera_activated = true;
00224                                 }
00225                                 catch (std::runtime_error &ex)
00226                                 {
00227                                         camera_state = 4;
00228                                         camera_activated = false;
00229                                 }
00230                         }
00231 
00232                         if (camera_activated) 
00233                         {
00234                                 
00235                                 buf_idx = cam->grab(&frame,bytes_used);
00236                                 if (buf_idx == -1)
00237                                         camera_state = 3;
00238         
00239                                 
00240                                 if (frame) 
00241                                 {
00242                                         ros::Time capture_time = ros::Time::now();
00243 
00244                                         image->header.stamp = capture_time;
00245                                         image->header.seq = pair_id;
00246  
00247                                         std::string frameid = "camera";
00248                                         image->header.frame_id = frameid;
00249                     
00250           
00251           if(!isjpeg)
00252           {
00253                                         memcpy(&image->data[0], frame, width*height * 3);
00254 
00255                                             
00256                                             pub.publish(image, camera_info);
00257                       }
00258                       else 
00259                       {
00260                   sensor_msgs::CompressedImage msg;
00261               msg.header.frame_id.append("/camera");
00262               msg.header.stamp = ros::Time::now();
00263               msg.format = "jpg";
00264               if(!is_huffman(frame)) { 
00265                   unsigned char *ptdeb, *ptlimit, *ptcur = frame;
00266                   int sizein, pos = 0;
00267                       ptdeb = ptcur = frame;
00268                       ptlimit = frame + bytes_used;
00269                   while((((ptcur[0] << 8) | ptcur[1]) != 0xffc0) && (ptcur < ptlimit))
00270                       ptcur++;
00271                   sizein = ptcur - ptdeb;
00272                   msg.data.insert( msg.data.end(), frame, frame + sizein  );
00273                   msg.data.insert( msg.data.end(), dht_data, dht_data + sizeof(dht_data)  );
00274                   msg.data.insert( msg.data.end(), ptcur, ptcur + bytes_used - sizein  );
00275               } 
00276               else 
00277               {
00278                   msg.data.insert( msg.data.end(), frame, frame + bytes_used  );
00279               } 
00280               image_pub.publish(msg);
00281                       }
00282                                         
00283                                         if (count == 50)
00284                                                 ROS_DEBUG("User settings applied.");
00285 
00286                                         
00287                                         cam->release(buf_idx);
00288                                 } else 
00289                                         skip_count++;
00290                                 }
00291                                 
00292                         }               
00293                 else 
00294                 {
00295                         camera_state = 2;
00296                         if (camera_activated) 
00297                         {
00298                                 delete cam;
00299                                 cam = NULL;
00300                                 cam_ptr = NULL;
00301                                 camera_activated = false;
00302                         }
00303                         
00304                 }
00305                 
00306                 updater.update(); 
00307                 ros::spinOnce();
00308                 r.sleep();
00309         }
00310 }
00311 
00312 void dynamic_reconfigureCallback(corobot_camera::corobot_cameraConfig &config, uint32_t level)
00316 {
00317                 camera_activated = config.camera_activated;
00318 }
00319 
00320 void webcam_diagnostic(diagnostic_updater::DiagnosticStatusWrapper &stat)
00324 {
00325         if (camera_state == 0)  
00326                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::OK, "The camera is working");
00327         else if (camera_state == 1)
00328         {
00329                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::WARN, "The user has stopped the camera. Activate it again to see the camera view");
00330         }
00331         else if (camera_state == 2)
00332         {
00333                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::WARN, "No subscriber to the camera topic - Start corobot_teleop or another image viewer");
00334         }
00335         else if (camera_state == 3)
00336         {
00337                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Could not grab the image");
00338                 stat.addf("Recommendation", CAMERA_DISCONNECTED);
00339         }
00340         else if (camera_state == 4)
00341         {
00342                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Could not initialize the camera");
00343                 stat.addf("Recommendation", ERROR_CAMERA_PARAMETERS);
00344         }
00345 
00346 }
00347 
00348 
00349 int main(int argc, char **argv) {
00350         ros::init(argc, argv, "corobot_camera");
00351         ros::NodeHandle n;
00352         ros::NodeHandle n_private("~");
00353         bool immediately;
00354 
00355         dynamic_reconfigure::Server<corobot_camera::corobot_cameraConfig> server;
00356         dynamic_reconfigure::Server<corobot_camera::corobot_cameraConfig>::CallbackType f;
00357 
00358         f = boost::bind(&dynamic_reconfigureCallback, _1, _2);
00359         server.setCallback(f);
00360 
00361         
00362         image_transport::ImageTransport it(n);
00363         image_transport::CameraPublisher pub;
00364 
00365 
00366         ros::Subscriber videomode_sub = n.subscribe("/camera/set_videomode", 1000, videomodeCallback);
00367         ros::Subscriber state_sub = n.subscribe("/camera/set_state", 1000, stateCallback);
00368 
00369         
00370         std::string device;     
00371         std::string out_topic;
00372         n_private.param<std::string>("device", device, "/dev/video0");
00373         n_private.param<std::string>("topic", out_topic, "/camera/image_raw");
00374         n_private.param("width", new_width, 960);
00375         n_private.param("height", new_height, 720);
00376         n_private.param("fps", new_fps, 30); 
00377         n_private.param("isjpeg", isjpeg, false); 
00378 
00379         std::string cameara_parameter_file;
00380         n_private.param<std::string> ("camera_parameter_file", cameara_parameter_file, "../camera_parameters.txt");
00381         
00382         n_private.param("immediately", immediately, true);
00383 
00384         if (immediately)
00385                 state = CHANGE_MODE;
00386         
00387         std::string camera_name;
00388         
00389         camera_info.reset(new sensor_msgs::CameraInfo);
00390         
00391         if (camera_calibration_parsers::readCalibrationIni(cameara_parameter_file, camera_name, *camera_info)) {
00392                 ROS_INFO("Successfully read camera calibration.");
00393         } else {
00394                 ROS_ERROR("No camera_parameters.txt file found.");
00395         }
00396         
00397 
00398     if(!isjpeg)
00399             pub = it.advertiseCamera(out_topic.c_str(), 1);
00400         else
00401             image_pub = n.advertise<sensor_msgs::CompressedImage>("image_raw/compressed", 1);
00402         
00403         
00404         diagnostic_updater::Updater updater;
00405         updater.setHardwareIDf("Webcam");
00406         updater.add("Webcam", webcam_diagnostic); 
00407 
00408         
00409         sleep(1);
00410 
00411         while (n.ok()) {
00412                 
00413                 if (state == CHANGE_MODE)
00414                         state = PLAYING;
00415 
00416                 
00417                 if (state == PLAYING) {
00418                         camera_state = 0;
00419                         mainloop(device.c_str(), new_width, new_height, new_fps, n, pub, updater);
00420                 }
00421                 else
00422                         camera_state = 1;
00423                 updater.update();
00424                 ros::spinOnce();
00425         }
00426         return 0;
00427 }
00428