open_controllers_interface.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2008, Willow Garage, Inc.
00005  *                2013, Ryohei Ueda, JSK Lab
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Willow Garage nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *********************************************************************/
00035 
00036 #include <stdio.h>
00037 #include <getopt.h>
00038 #include <execinfo.h>
00039 #include <signal.h>
00040 #include <sys/mman.h>
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 #include <unistd.h>
00044 #include <fcntl.h>
00045 #include <pthread.h>
00046 #include <sys/mman.h>
00047 #include <boost/cast.hpp>
00048 
00049 #include <open_controllers_interface/open_controllers_interface.h>
00050 
00051 using namespace pr2_hardware_interface;
00052 using namespace std;
00053 using namespace boost::accumulators;
00054 
00055 static const int NSEC_PER_SECOND = 1e+9;
00056 static const int USEC_PER_SECOND = 1e6;
00057 
00058 namespace OpenControllersInterface {
00059   OpenController::OpenController():
00060     not_sleep_clock_(false) { // constructor
00061   }
00062 
00063   OpenController::~OpenController() {
00064 
00065   }
00066   bool OpenController::resetMotorsService(std_srvs::Empty::Request &req,
00067                                           std_srvs::Empty::Response &resp) {
00068     g_reset_motors_ = true;
00069     return true;
00070   }
00071 
00072   bool OpenController::haltMotorsService(std_srvs::Empty::Request &req,
00073                                          std_srvs::Empty::Response &resp) {
00074     quitRequest();
00075     return true;
00076   }
00077   
00078   bool OpenController::publishTraceService(std_srvs::Empty::Request &req,
00079                                            std_srvs::Empty::Response &resp) {
00080     g_publish_trace_requested_ = true;
00081     return true;
00082   }
00083 
00084   double timespecDiff(struct timespec* a, struct timespec* b) {
00085     return (a->tv_sec - b->tv_sec) + double(a->tv_nsec - b->tv_nsec) / NSEC_PER_SECOND;
00086   }
00087 
00088   void OpenController::start() {
00089     while(!g_quit_) {
00090       startMain();
00091       if (g_reset_motors_)
00092       {
00093         ControllerStatusPtr st = recoverController();
00094         if (!st || !st->isHealthy())
00095         {
00096           ROS_FATAL("oh no, no way to recover! quit!");
00097           g_quit_ = true;
00098         }
00099         g_reset_motors_ = false;
00100       }
00101     }
00102     ROS_INFO("good bye start()");
00103   }
00104 
00105   void OpenController::publishDiagnostics() {
00106     if (!!publisher_ && publisher_->trylock())
00107     {
00108       accumulator_set<double, stats<tag::max, tag::mean> > zero;
00109       vector<diagnostic_msgs::DiagnosticStatus> statuses;
00110       diagnostic_updater::DiagnosticStatusWrapper status;
00111 
00112       static double max_ec = 0, max_cm = 0, max_loop = 0, max_jitter = 0;
00113       double avg_ec, avg_cm, avg_loop, avg_jitter;
00114 
00115       avg_ec           = extract_result<tag::mean>(g_stats_.ec_acc);
00116       avg_cm           = extract_result<tag::mean>(g_stats_.cm_acc);
00117       avg_loop         = extract_result<tag::mean>(g_stats_.loop_acc);
00118       max_ec           = std::max(max_ec, extract_result<tag::max>(g_stats_.ec_acc));
00119       max_cm           = std::max(max_cm, extract_result<tag::max>(g_stats_.cm_acc));
00120       max_loop         = std::max(max_loop, extract_result<tag::max>(g_stats_.loop_acc));
00121       g_stats_.ec_acc   = zero;
00122       g_stats_.cm_acc   = zero;
00123       g_stats_.loop_acc = zero;
00124 
00125       // Publish average loop jitter
00126       avg_jitter         = extract_result<tag::mean>(g_stats_.jitter_acc);
00127       max_jitter         = std::max(max_jitter, extract_result<tag::max>(g_stats_.jitter_acc));
00128       g_stats_.jitter_acc = zero;
00129 
00130       static bool first = true;
00131       if (first)
00132       {
00133         first = false;
00134         status.add("Robot Description", g_robot_desc_);
00135       }
00136 
00137       status.addf("Max EtherCAT roundtrip (us)", "%.2f", max_ec*USEC_PER_SECOND);
00138       status.addf("Avg EtherCAT roundtrip (us)", "%.2f", avg_ec*USEC_PER_SECOND);
00139       status.addf("Max Controller Manager roundtrip (us)", "%.2f", max_cm*USEC_PER_SECOND);
00140       status.addf("Avg Controller Manager roundtrip (us)", "%.2f", avg_cm*USEC_PER_SECOND);
00141       status.addf("Max Total Loop roundtrip (us)", "%.2f", max_loop*USEC_PER_SECOND);
00142       status.addf("Avg Total Loop roundtrip (us)", "%.2f", avg_loop*USEC_PER_SECOND);
00143       status.addf("Max Loop Jitter (us)", "%.2f", max_jitter * USEC_PER_SECOND);
00144       status.addf("Avg Loop Jitter (us)", "%.2f", avg_jitter * USEC_PER_SECOND);
00145       status.addf("Control Loop Overruns", "%d", g_stats_.overruns);
00146       status.addf("Total Loop Count", "%ul", g_stats_.loop_count);
00147       status.addf("Recent Control Loop Overruns", "%d", g_stats_.recent_overruns);
00148       status.addf("Last Control Loop Overrun Cause", "ec: %.2fus, cm: %.2fus", 
00149                   g_stats_.overrun_ec*USEC_PER_SECOND, g_stats_.overrun_cm*USEC_PER_SECOND);
00150       status.addf("Last Overrun Loop Time (us)", "%.2f", g_stats_.overrun_loop_sec * USEC_PER_SECOND);
00151       status.addf("Realtime Loop Frequency", "%.4f", g_stats_.rt_loop_frequency);
00152 
00153       status.name = "Realtime Control Loop";
00154       if (g_stats_.overruns > 0 && g_stats_.last_overrun < 30)
00155       {
00156         if (g_stats_.last_severe_overrun < 30)
00157           status.level = 1;
00158         else
00159           status.level = 0;
00160         status.message = "Realtime loop used too much time in the last 30 seconds.";
00161       }
00162       else
00163       {
00164         status.level = 0;
00165         status.message = "OK";
00166       }
00167       g_stats_.recent_overruns = 0;
00168       g_stats_.last_overrun++;
00169       g_stats_.last_severe_overrun++;
00170 
00171       if (g_stats_.rt_loop_not_making_timing)
00172       {
00173         status.mergeSummaryf(status.ERROR, "Halting, realtime loop only ran at %.4f Hz", g_stats_.halt_rt_loop_frequency);
00174       }
00175 
00176       statuses.push_back(status);
00177       publisher_->msg_.status = statuses;
00178       publisher_->msg_.header.stamp = ros::Time::now();
00179       publisher_->unlockAndPublish();
00180     }
00181   }
00182 
00183   void OpenController::parseArguments(int argc, char** argv) {
00184     while (1) {
00185       static struct option long_options[] = {
00186         {"help", no_argument, 0, 'h'},
00187         {"stats", no_argument, 0, 's'},
00188         {"allow_unprogrammed", no_argument, 0, 'u'},
00189         {"interface", required_argument, 0, 'i'},
00190         {"xml", required_argument, 0, 'x'},
00191         {"dryrun", no_argument, 0, 'd'}
00192       };
00193     int option_index = 0;
00194     int c = getopt_long(argc, argv, "hi:usdx:", long_options, &option_index);
00195     if (c == -1) break;
00196     switch (c) {
00197     case 'h':
00198       Usage();
00199       break;
00200     case 'u':
00201       setAllowUnprogrammedP(true);
00202       break;
00203     case 'x':
00204       setRobotXMLFile(std::string(optarg));
00205       break;
00206     case 's':
00207       setStatsPublishP(true);
00208       break;
00209     case 'd':
00210       setDryRun(true);
00211       break;
00212     }
00213     }
00214   }
00215   
00216   
00217   void OpenController::initialize() {
00218     ros::NodeHandle node("~");
00219     initializeROS(node);            // initialize ros anyway
00220     reset_service_
00221       = node.advertiseService("reset_motors",
00222                               &OpenController::resetMotorsService,
00223                               this);
00224     halt_service_
00225       = node.advertiseService("halt_motors",
00226                               &OpenController::haltMotorsService,
00227                               this);
00228     publishTrace_service_
00229       = node.advertiseService("publish_trace",
00230                               &OpenController::publishTraceService,
00231                               this);
00232     
00233     publisher_.reset(new realtime_tools::RealtimePublisher<diagnostic_msgs::DiagnosticArray>(node, "/diagnostics", 2));
00234 
00235     if (!node.getParam("not_sleep_clock", not_sleep_clock_)) {
00236       not_sleep_clock_ = false;
00237     }
00238 
00239     if (!node.getParam("min_acceptable_rt_loop_frequency", min_acceptable_rt_loop_frequency_))
00240     {
00241       min_acceptable_rt_loop_frequency_ = 750.0; 
00242     }
00243     else 
00244     {
00245       ROS_WARN("min_acceptable_rt_loop_frequency changed to %f", min_acceptable_rt_loop_frequency_);
00246     }
00247     
00248     // read period
00249     if (!node.getParam("rt_period", period_))
00250     {
00251       ROS_WARN("failed to read rt_period parameter");
00252       period_ = 1e+6;            // 1ms in nanoseconds
00253     }
00254     ROS_INFO("realtime loop period is %f", period_);
00255 
00256     if (!node.getParam("pidfile", pidfile_)) {
00257       pidfile_ = "open_controller.pid";
00258     }
00259     ROS_INFO("pidfile is: %s", pidfile_.c_str());
00260 
00261     if (!node.getParam("piddir", piddir_)) {
00262       piddir_ = "/var/tmp/run/";
00263     }
00264     ROS_INFO("piddir is: %s", piddir_.c_str());
00265     
00266     if (stats_publish_p_) {
00267       rtpublisher_.reset(new realtime_tools::RealtimePublisher<std_msgs::Float64>(node, "realtime", 2));
00268     }
00269     
00270     // initialize pid file
00271     if (setupPidFile() < 0) {
00272       ROS_FATAL("pid file (%s/%s) already exists", piddir_.c_str(), pidfile_.c_str());
00273       exit(1);
00274     }
00275     
00276     // Initialize the hardware interface
00277     //EthercatHardware ec(name);
00278     //ec.init(g_options.interface_, g_options.allow_unprogrammed_);
00279     initializeCM();
00280     loadRobotDescription();
00281     initializeHW();
00282     
00283     for (size_t i = 0; i < cm_->state_->joint_states_.size(); i++) {
00284       cm_->state_->joint_states_[i].calibrated_ = true;
00285     }
00286 
00287    // Publish one-time before entering real-time to pre-allocate message vectors
00288     publishDiagnostics(); //ueda
00289 
00290     //Start Non-realtime diagonostic thread
00291     boost::thread t(&OpenController::diagnosticLoop, this);
00292 
00293     // Set to realtime scheduler for this thread
00294 #if 0                           // disable
00295     struct sched_param thread_param;
00296     policy = SCHED_FIFO;
00297     thread_param.sched_priority = sched_get_priority_max(policy);
00298     if ( pthread_setschedparam(pthread_self(), policy, &thread_param) < -1 ) {
00299       perror("sched_setscheduler");
00300     }
00301 #endif
00302   }
00303 
00304   void OpenController::loadRobotDescription() {
00305     // Load robot description
00306     TiXmlElement *root;
00307     TiXmlElement *root_element;
00308     
00309     TiXmlDocument xml;
00310     struct stat st;
00311     if (0 == stat(robot_xml_file_.c_str(), &st))
00312     {
00313       xml.LoadFile(robot_xml_file_.c_str());
00314     }
00315     else
00316     {
00317       ROS_INFO("Xml file not found, reading from parameter server");
00318       ros::NodeHandle top_level_node;
00319       if (top_level_node.getParam(robot_xml_file_.c_str(), g_robot_desc_))
00320         xml.Parse(g_robot_desc_.c_str());
00321       else
00322       {
00323         ROS_FATAL("Could not load the xml from parameter server: %s", robot_xml_file_.c_str());
00324         throw "end";
00325       }
00326     }
00327     root_element = xml.RootElement();
00328     root = xml.FirstChildElement("robot");
00329     if (!root || !root_element)
00330     {
00331       ROS_FATAL("Could not parse the xml from %s", robot_xml_file_.c_str());
00332       throw "end";
00333     }
00334 
00335     // Initialize the controller manager from robot description
00336     if (!cm_->initXml(root))
00337     {
00338       ROS_FATAL("Could not initialize the controller manager");
00339       throw "end";
00340     }
00341     else {
00342       ROS_INFO("success to initialize the controller manager");
00343     }
00344   }
00345 
00346   double OpenController::now() {
00347     struct timespec n;
00348     clock_gettime(CLOCK_MONOTONIC, &n);
00349     return double(n.tv_nsec) / NSEC_PER_SECOND + n.tv_sec;
00350   }
00351 
00352   void OpenController::timespecInc(struct timespec &tick, int nsec)
00353   {
00354     tick.tv_nsec += nsec;
00355     while (tick.tv_nsec >= NSEC_PER_SECOND)
00356     {
00357       tick.tv_nsec -= NSEC_PER_SECOND;
00358       tick.tv_sec++;
00359     }
00360   }
00361   double OpenController::publishJitter(double start) 
00362   {
00363     double jitter = now() - start;
00364     g_stats_.jitter_acc(jitter);
00365     // Publish realtime loops statistics, if requested
00366     if (!!rtpublisher_)
00367       {
00368         if (rtpublisher_->trylock())
00369           {
00370             rtpublisher_->msg_.data  = jitter;
00371             rtpublisher_->unlockAndPublish();
00372           }
00373       }
00374     return jitter;
00375   }
00376 
00377 
00378   void OpenController::startMain() {
00379 
00380     // setup the priority of the thread
00381     struct sched_param thread_param;
00382       int policy = SCHED_FIFO;
00383       thread_param.sched_priority = sched_get_priority_max(policy);
00384       if ( pthread_setschedparam(pthread_self(), policy, &thread_param) < -1 ) {
00385         perror("sched_setscheduler");
00386         ROS_ERROR("failed to sched_setscheduler");
00387       }
00388 
00389     // Keep history of last 3 calculation intervals.
00390     // the value is Hz we supporsed for realtime loop to be in
00391     RTLoopHistory rt_loop_history(3, 1.0 / (period_ / NSEC_PER_SECOND)); 
00392     double rt_loop_monitor_period_ = 0.6 / 3;
00393     unsigned long rt_cycle_count = 0;
00394     struct timespec tick;
00395     clock_gettime(CLOCK_REALTIME, &tick);
00396     // Snap to the nearest second
00397     timespecInc(tick, period_);
00398     clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, NULL);
00399     double last_published = now();
00400     double last_loop_start = now();
00401     double last_rt_monitor_time = now();
00402     struct timespec last_exec_time;
00403     clock_gettime(CLOCK_REALTIME, &last_exec_time);
00404     g_stats_.loop_count = 0;
00405     while (!g_quit_ && !g_reset_motors_) {
00406       g_stats_.loop_count++;
00407       // Track how long the actual loop takes
00408       double this_loop_start = now();
00409       g_stats_.loop_acc(this_loop_start - last_loop_start);
00410       last_loop_start = this_loop_start;
00411       bool success_update_joint = false;
00412       double start = now();
00413       if (g_reset_motors_) {
00414         // Also, clear error flags when motor reset is requested
00415         g_stats_.rt_loop_not_making_timing = false;
00416         break; // go to recoverController
00417       }
00418       else {
00419         // struct timespec current_time;
00420         // clock_gettime(CLOCK_REALTIME, &current_time);
00421         // timespecInc(exec_time, period_);
00422         // if (((exec_time.tv_sec - current_time.tv_sec) + double(exec_time.tv_nsec - current_time.tv_nsec) / NSEC_PER_SECOND) > 0) {
00423         //   ROS_INFO("sleep %f", ((exec_time.tv_sec - current_time.tv_sec) + double(exec_time.tv_nsec - current_time.tv_nsec) / NSEC_PER_SECOND));
00424         //   clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &exec_time, NULL);
00425         // }
00426         // clock_gettime(CLOCK_REALTIME, &exec_time);
00427 
00428         struct timespec exec_time;
00429 
00430         ControllerStatusPtr status = updateJoints(&exec_time);
00431         success_update_joint = status->isHealthy();
00432         g_reset_motors_ = !success_update_joint;
00433         // double diff = timespecDiff(&exec_time, &last_exec_time);
00434         // ROS_INFO("diff: %f", diff);
00435         last_exec_time.tv_sec = exec_time.tv_sec;
00436         last_exec_time.tv_nsec = exec_time.tv_nsec;
00437       }
00438 
00439       if (g_publish_trace_requested_)
00440       {
00441         g_publish_trace_requested_ = false;
00442 #if 0
00443         ec.publishTrace(-1,"",0,0);
00444 #endif
00445       }
00446       double after_ec = now();
00447       if (success_update_joint) {
00448         cm_->update();
00449       }
00450       double end = now();
00451 
00452       g_stats_.ec_acc(after_ec - start);
00453       g_stats_.cm_acc(end - after_ec);
00454 
00455       if ((end - last_published) > 1.0)
00456       {
00457         publishDiagnostics();
00458         last_published = end;
00459       }
00460 
00461       // Realtime loop should run about 1000Hz.  
00462       // Missing timing on a control cycles usually causes a controller glitch and actuators to jerk.
00463       // When realtime loop misses a lot of cycles controllers will perform poorly and may cause robot to shake.
00464       // Halt motors if realtime loop does not run enough cycles over a given period.
00465       ++rt_cycle_count;
00466       if ((start - last_rt_monitor_time) > rt_loop_monitor_period_)
00467       {
00468         // Calculate new average rt loop frequency       
00469         double rt_loop_frequency = double(rt_cycle_count) / rt_loop_monitor_period_;
00470 
00471         // Use last X samples of frequency when deciding whether or not to halt
00472         rt_loop_history.sample(rt_loop_frequency);
00473         double avg_rt_loop_frequency = rt_loop_history.average();
00474         if (avg_rt_loop_frequency < min_acceptable_rt_loop_frequency_)
00475         {
00476           if (!g_stats_.rt_loop_not_making_timing)
00477           {
00478             // Only update this value if motors when this first occurs (used for diagnostics error message)
00479             g_stats_.halt_rt_loop_frequency = avg_rt_loop_frequency;
00480           }
00481           g_stats_.rt_loop_not_making_timing = true;
00482         }
00483         g_stats_.rt_loop_frequency = avg_rt_loop_frequency;
00484         rt_cycle_count = 0;
00485         last_rt_monitor_time = start;
00486       }
00487       // Compute end of next period
00488       timespecInc(tick, period_);
00489 
00490       struct timespec before; 
00491       clock_gettime(CLOCK_REALTIME, &before); 
00492       double overrun_time = (before.tv_sec + double(before.tv_nsec)/NSEC_PER_SECOND) - 
00493         (tick.tv_sec + double(tick.tv_nsec)/NSEC_PER_SECOND);
00494       if (overrun_time > 0.0)
00495       {
00496         ROS_WARN("  overrun: %f", overrun_time);
00497         double jitter = publishJitter(start);
00498         ROS_WARN("  jitter: %f", jitter);
00499         ROS_WARN("  loop:   %d", g_stats_.loop_count);
00500         // Total amount of time the loop took to run
00501         g_stats_.overrun_loop_sec = overrun_time;
00502 
00503         // We overran, snap to next "period"
00504         // ueda
00505         //timespecInc(tick, (before.tv_nsec / period_ + 1) * period_);
00506         tick.tv_sec = before.tv_sec;
00507         // tick.tv_nsec = (before.tv_nsec / period_) * period_;
00508         tick.tv_nsec = before.tv_nsec;
00509         timespecInc(tick, period_);
00510 
00511         // initialize overruns
00512         if (g_stats_.overruns == 0){
00513           g_stats_.last_overrun = 1000;
00514           g_stats_.last_severe_overrun = 1000;
00515         }
00516         // check for overruns
00517         if (g_stats_.recent_overruns > 10)
00518           g_stats_.last_severe_overrun = 0;
00519         g_stats_.last_overrun = 0;
00520 
00521         g_stats_.overruns++;
00522         g_stats_.recent_overruns++;
00523         g_stats_.overrun_ec = after_ec - start;
00524         g_stats_.overrun_cm = end - after_ec;
00525       }
00526 
00527       struct timespec sleep_before;
00528       clock_gettime(CLOCK_REALTIME, &sleep_before);
00529       // Sleep until end of period
00530       if (!not_sleep_clock_)
00531         clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tick, NULL);
00532       if (overrun_time <= 0.0)
00533         publishJitter(start);
00534       // Calculate RT loop jitter
00535       struct timespec sleep_after;
00536       clock_gettime(CLOCK_REALTIME, &sleep_after);
00537       double sleep_time = (sleep_after.tv_sec - sleep_before.tv_sec
00538                            + double(sleep_after.tv_nsec-sleep_before.tv_nsec)/NSEC_PER_SECOND);
00539       //double jitter = (after.tv_sec - tick.tv_sec + double(after.tv_nsec-tick.tv_nsec)/NSEC_PER_SECOND);
00540       if (overrun_time > 0.0) {
00541         ROS_WARN("  sleep_time: %f", sleep_time);
00542       }
00543 
00544       // Halt the motors, if requested by a service call
00545       if (g_halt_requested_)
00546       {
00547         fprintf(stderr, "detect halt request\n");
00548         g_quit_ = true;
00549         g_halt_requested_ = false;
00550       }
00551     }
00552     ROS_INFO("good bye startMain()");
00553   }
00554 
00555   void OpenController::finalize() {
00556     ROS_WARN("finalizing");
00557     finalizeHW();
00558     /* Shutdown all of the motors on exit */
00559     for (pr2_hardware_interface::ActuatorMap::const_iterator it = hw_->actuators_.begin(); it != hw_->actuators_.end(); ++it)
00560     {
00561       it->second->command_.enable_ = false;
00562       it->second->command_.effort_ = 0;
00563     }
00564 #if 0
00565     ec.update(false, true);
00566 #endif
00567     //pthread_join(diagnosticThread, 0);
00568     if (!!publisher_) {
00569       publisher_->stop();
00570       publisher_.reset();
00571     }
00572     rtpublisher_.reset();
00573     //ros::shutdown();
00574     //return (void *)rv;
00575     fprintf(stderr, "exiting from finalize\n");
00576   }
00577 
00578   void OpenController::diagnosticLoop() {
00579     //EthercatHardware *ec((EthercatHardware *) args);
00580     struct timespec tick;
00581     clock_gettime(CLOCK_MONOTONIC, &tick);
00582     while (!g_quit_) {
00583       //ec->collectDiagnostics();
00584       tick.tv_sec += 1;
00585       clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tick, NULL);
00586     }
00587   }
00588 
00589   int OpenController::lock_fd(int fd) {
00590     struct flock lock;
00591     int rv;
00592     
00593     lock.l_type = F_WRLCK;
00594     lock.l_whence = SEEK_SET;
00595     lock.l_start = 0;
00596     lock.l_len = 0;
00597     
00598     rv = fcntl(fd, F_SETLK, &lock);
00599     return rv;
00600   }
00601   
00602   int OpenController::setupPidFile() {
00603     int rv = -1;
00604     pid_t pid;
00605     int fd;
00606     FILE *fp = NULL;
00607     boost::filesystem::path fullpath = boost::filesystem::path(piddir_) / boost::filesystem::path(pidfile_);
00608     umask(0);
00609     mkdir(piddir_.c_str(), 0777);
00610     fd = open(fullpath.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IWOTH | S_IROTH);
00611     if (fd == -1)
00612     {
00613       if (errno != EEXIST)
00614       {
00615         ROS_FATAL("Unable to create pid file '%s': %s", fullpath.c_str(), strerror(errno));
00616         goto end;
00617       }
00618 
00619       if ((fd = open(fullpath.c_str(), O_RDWR)) < 0)
00620       {
00621         ROS_FATAL("Unable to open pid file '%s': %s", fullpath.c_str(), strerror(errno));
00622         goto end;
00623       }
00624 
00625       if ((fp = fdopen(fd, "rw")) == NULL)
00626       {
00627         ROS_FATAL("Can't read from '%s': %s", fullpath.c_str(), strerror(errno));
00628         goto end;
00629       }
00630       pid = -1;
00631       if ((fscanf(fp, "%d", &pid) != 1) || (pid == getpid()) || (lock_fd(fileno(fp)) == 0))
00632       {
00633         int rc;
00634 
00635         if ((rc = unlink(fullpath.c_str())) == -1)
00636         {
00637           ROS_FATAL("Can't remove stale pid file '%s': %s", fullpath.c_str(), strerror(errno));
00638           goto end;
00639         }
00640       } else {
00641         ROS_FATAL("Another instance of pr2_etherCAT is already running with pid: %d", pid);
00642         goto end;
00643       }
00644     }
00645 
00646     unlink(fullpath.c_str());
00647     fd = open(fullpath.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IWOTH | S_IROTH);
00648 
00649     if (fd == -1)
00650     {
00651       ROS_FATAL("Unable to open pid file '%s': %s", fullpath.c_str(), strerror(errno));
00652       goto end;
00653     }
00654 
00655     if (lock_fd(fd) == -1)
00656     {
00657       ROS_FATAL("Unable to lock pid file '%s': %s", fullpath.c_str(), strerror(errno));
00658       goto end;
00659     }
00660 
00661     if ((fp = fdopen(fd, "w")) == NULL)
00662     {
00663       ROS_FATAL("fdopen failed: %s", strerror(errno));
00664       goto end;
00665     }
00666 
00667     fprintf(fp, "%d\n", getpid());
00668 
00669     /* We do NOT close fd, since we want to keep the lock. */
00670     fflush(fp);
00671     fcntl(fd, F_SETFD, (long) 1);
00672     rv = 0;
00673   end:
00674     return rv;
00675   }
00676 
00677   void OpenController::cleanupPidFile() {
00678     boost::filesystem::path path = boost::filesystem::path(piddir_) / boost::filesystem::path(pidfile_);
00679     unlink(path.c_str());
00680   }
00681   
00682   void OpenController::Usage(std::string msg) {
00683     fprintf(stderr, "Usage: main [options]\n");
00684     fprintf(stderr, "  Available options\n");
00685     fprintf(stderr, "    -s, --stats                 Publish statistics on the RT loop jitter on \"pr2_etherCAT/realtime\" in seconds\n");
00686     fprintf(stderr, "    -x, --xml <file|param>      Load the robot description from this file or parameter name\n");
00687     fprintf(stderr, "    -d, --dryrun                Run in dry run mode, not communicating with the controller.\n");
00688     fprintf(stderr, "    -h, --help                  Print this message and exit\n");
00689     if (msg != "")
00690     {
00691       fprintf(stderr, "Error: %s\n", msg.c_str());
00692     }
00693   }
00694 
00695   void OpenController::quitRequest() {
00696     g_halt_requested_ = true;
00697   }
00698 
00699   bool OpenController::initRT() {
00700     if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
00701       perror("mlockall");
00702       return false;
00703     }
00704     else {
00705       return true;
00706     }
00707   }
00708 
00709   Finalizer::~Finalizer() {
00710     ROS_WARN("Finalizer::~Finalizer is called");
00711     controller->finalize();
00712   }
00713 }
00714 


open_controllers_interface
Author(s): Ryohei Ueda , Kei Okada
autogenerated on Sat Jun 8 2019 19:52:47