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 #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
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
00065 enum e_state {PLAYING, STOP, CHANGE_MODE};
00066 char state = STOP;
00067
00068
00069 int new_width, new_height, new_fps;
00070 bool auto_exposure = true;
00071 bool camera_activated = true;
00072 int camera_state = 0;
00073 bool isjpeg = false;
00074
00075 uvc_cam::Cam * cam_ptr;
00076
00077
00078
00079
00080
00081
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
00096
00097
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
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
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
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
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
00164 while (n.ok() && state == PLAYING) {
00165
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
00187 buf_idx = cam->grab(&frame,bytes_used);
00188 if (buf_idx == -1)
00189 camera_state = 3;
00190
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
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
00221 pub.publish(image, camera_info);
00222
00223
00224 if (count == 50)
00225 ROS_DEBUG("User settings applied.");
00226
00227
00228 cam->release(buf_idx);
00229 } else
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
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
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
00309 ros::ServiceServer set_control_service = n.advertiseService("/camera/set_control", setcontrol);
00310
00311
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
00329 std::string camera_name;
00330
00331 camera_info.reset(new sensor_msgs::CameraInfo);
00332
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
00339
00340 pub = it.advertiseCamera(out_topic.c_str(), 1);
00341
00342
00343 diagnostic_updater::Updater updater;
00344 updater.setHardwareIDf("Webcam");
00345 updater.add("Webcam", webcam_diagnostic);
00346
00347
00348 sleep(1);
00349
00350 while (n.ok()) {
00351
00352 if (state == CHANGE_MODE)
00353 state = PLAYING;
00354
00355
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