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 <ros/ros.h>
00035 #include <sensor_msgs/JointState.h>
00036 #include <sensor_msgs/Imu.h>
00037 #include <geometry_msgs/Twist.h>
00038 #include <std_msgs/Float64.h>
00039 #include <tf/transform_broadcaster.h>
00040 #include <nav_msgs/Odometry.h>
00041 #include <robotnik_msgs/set_mode.h>
00042 #include <robotnik_msgs/get_mode.h>
00043 #include <robotnik_msgs/set_odometry.h>
00044 #include <robotnik_msgs/ptz.h>
00045
00046
00047
00048 #include "diagnostic_msgs/DiagnosticStatus.h"
00049 #include "diagnostic_updater/diagnostic_updater.h"
00050 #include "diagnostic_updater/update_functions.h"
00051 #include "diagnostic_updater/DiagnosticStatusWrapper.h"
00052 #include "diagnostic_updater/publisher.h"
00053
00054
00055 #define PI 3.1415926535
00056 #define GUARDIAN_MIN_COMMAND_REC_FREQ 5.0
00057 #define GUARDIAN_MAX_COMMAND_REC_FREQ 150.0
00058
00059 #define SKID_STEERING 1
00060 #define MECANUM_STEERING 2
00061
00062 #define GUARDIAN_WHEEL_DIAMETER 0.25 // Default wheel diameter
00063 #define GUARDIAN_D_TRACKS_M 1.0 // default equivalent W distance (difference is due to slippage of skid steering)
00064 #define GUARDIAN_WHEELBASE 0.446 // default real L distance forward to rear axis
00065 #define GUARDIAN_TRACKWIDTH 0.408 // default real W distance from left wheels to right wheels
00066
00067 using namespace std;
00068
00069 class GuardianControllerClass {
00070
00071 public:
00072
00073 ros::NodeHandle node_handle_;
00074 ros::NodeHandle private_node_handle_;
00075 double desired_freq_;
00076
00077
00078 diagnostic_updater::Updater diagnostic_;
00079 diagnostic_updater::FrequencyStatus freq_diag_;
00080 diagnostic_updater::HeaderlessTopicDiagnostic *subs_command_freq;
00081 ros::Time last_command_time_;
00082 diagnostic_updater::FunctionDiagnosticTask command_freq_;
00083
00084
00085 std::string robot_model_;
00086
00087
00088 ros::Publisher ref_vel_flw_;
00089 ros::Publisher ref_vel_frw_;
00090 ros::Publisher ref_vel_blw_;
00091 ros::Publisher ref_vel_brw_;
00092 ros::Publisher ref_pos_flw_;
00093 ros::Publisher ref_pos_frw_;
00094 ros::Publisher ref_pos_blw_;
00095 ros::Publisher ref_pos_brw_;
00096 ros::Publisher ref_pos_pan_;
00097 ros::Publisher ref_pos_tilt_;
00098
00099
00100 ros::Subscriber joint_state_sub_;
00101
00102
00103 ros::Subscriber cmd_sub_;
00104
00105
00106 ros::Subscriber ptz_sub_;
00107
00108
00109
00110
00111 ros::ServiceServer srv_SetOdometry_;
00112 ros::ServiceServer srv_SetMode_;
00113 ros::ServiceServer srv_GetMode_;
00114
00115
00116 std::string frw_vel_topic_;
00117 std::string flw_vel_topic_;
00118 std::string brw_vel_topic_;
00119 std::string blw_vel_topic_;
00120
00121
00122 std::string joint_front_right_wheel;
00123 std::string joint_front_left_wheel;
00124 std::string joint_back_left_wheel;
00125 std::string joint_back_right_wheel;
00126
00127
00128 std::string joint_camera_pan;
00129 std::string joint_camera_tilt;
00130
00131
00132 std::string pan_pos_topic_;
00133 std::string tilt_pos_topic_;
00134
00135
00136 int kinematic_modes_;
00137 int active_kinematic_mode_;
00138
00139
00140 int frw_vel_, flw_vel_, blw_vel_, brw_vel_;
00141 int pan_pos_, tilt_pos_;
00142
00143
00144 double linearSpeedXMps_;
00145 double linearSpeedYMps_;
00146 double angularSpeedRads_;
00147
00148
00149 double robot_pose_px_;
00150 double robot_pose_py_;
00151 double robot_pose_pa_;
00152 double robot_pose_vx_;
00153 double robot_pose_vy_;
00154
00155
00156 sensor_msgs::JointState joint_state_;
00157
00158
00159 geometry_msgs::Twist base_vel_msg_;
00160
00161
00162 double v_ref_x_;
00163 double v_ref_y_;
00164 double w_ref_;
00165 double v_ref_z_;
00166 double pos_ref_pan_;
00167 double pos_ref_tilt_;
00168
00169
00170 bool read_state_;
00171
00172
00173 double guardian_wheel_diameter_;
00174 double guardian_d_tracks_m_;
00175 double guardian_wheelbase_;
00176 double guardian_trackwidth_;
00177
00178
00179 double ang_vel_x_;
00180 double ang_vel_y_;
00181 double ang_vel_z_;
00182
00183 double lin_acc_x_;
00184 double lin_acc_y_;
00185 double lin_acc_z_;
00186
00187 double orientation_x_;
00188 double orientation_y_;
00189 double orientation_z_;
00190 double orientation_w_;
00191
00192
00193 bool publish_odom_tf_;
00194
00195 ros::Subscriber imu_sub_;
00196
00197
00198 ros::Publisher odom_pub_;
00199
00200
00201 tf::TransformBroadcaster odom_broadcaster;
00202
00203
00207 GuardianControllerClass(ros::NodeHandle h) : diagnostic_(),
00208 node_handle_(h), private_node_handle_("~"),
00209 desired_freq_(100),
00210 freq_diag_(diagnostic_updater::FrequencyStatusParam(&desired_freq_, &desired_freq_, 0.05) ),
00211 command_freq_("Command frequency check", boost::bind(&GuardianControllerClass::check_command_subscriber, this, _1))
00212 {
00213
00214
00215 ROS_INFO("guardian_robot_control_node - Init ");
00216
00217
00218
00219 kinematic_modes_ = 1;
00220
00221 ros::NodeHandle guardian_robot_control_node_handle(node_handle_, "guardian_robot_control");
00222
00223
00224 if (!private_node_handle_.getParam("model", robot_model_)) {
00225 ROS_ERROR("Robot model not defined.");
00226 exit(-1);
00227 }
00228 else ROS_INFO("Robot Model : %s", robot_model_.c_str());
00229
00230
00231 private_node_handle_.param<std::string>("frw_vel_topic", frw_vel_topic_, "/guardian/joint_frw_velocity_controller/command");
00232 private_node_handle_.param<std::string>("flw_vel_topic", flw_vel_topic_, "/guardian/joint_flw_velocity_controller/command");
00233 private_node_handle_.param<std::string>("blw_vel_topic", blw_vel_topic_, "/guardian/joint_blw_velocity_controller/command");
00234 private_node_handle_.param<std::string>("brw_vel_topic", brw_vel_topic_, "/guardian/joint_brw_velocity_controller/command");
00235
00236
00237 private_node_handle_.param<std::string>("joint_front_right_wheel", joint_front_right_wheel, "joint_front_right_wheel");
00238 private_node_handle_.param<std::string>("joint_front_left_wheel", joint_front_left_wheel, "joint_front_left_wheel");
00239 private_node_handle_.param<std::string>("joint_back_left_wheel", joint_back_left_wheel, "joint_back_left_wheel");
00240 private_node_handle_.param<std::string>("joint_back_right_wheel", joint_back_right_wheel, "joint_back_right_wheel");
00241
00242
00243 private_node_handle_.param<std::string>("pan_pos_topic", pan_pos_topic_, "/guardian/joint_pan_position_controller/command");
00244 private_node_handle_.param<std::string>("tilt_pos_topic", tilt_pos_topic_, "/guardian/joint_tilt_position_controller/command");
00245 private_node_handle_.param<std::string>("joint_camera_pan", joint_camera_pan, "joint_camera_pan");
00246 private_node_handle_.param<std::string>("joint_camera_tilt", joint_camera_tilt, "joint_camera_tilt");
00247
00248
00249 if (!private_node_handle_.getParam("guardian_wheel_diameter", guardian_wheel_diameter_))
00250 guardian_wheel_diameter_ = GUARDIAN_WHEEL_DIAMETER;
00251 if (!private_node_handle_.getParam("guardian_d_tracks_m", guardian_d_tracks_m_))
00252 guardian_d_tracks_m_ = GUARDIAN_D_TRACKS_M;
00253 ROS_INFO("guardian_wheel_diameter_ = %5.2f", guardian_wheel_diameter_);
00254 ROS_INFO("guardian_d_tracks_m_ = %5.2f", guardian_d_tracks_m_);
00255
00256 private_node_handle_.param("publish_odom_tf", publish_odom_tf_, true);
00257 if (publish_odom_tf_) ROS_INFO("PUBLISHING odom->base_footprin tf");
00258 else ROS_INFO("NOT PUBLISHING odom->base_footprint tf");
00259
00260
00261 linearSpeedXMps_ = 0.0;
00262 linearSpeedYMps_ = 0.0;
00263 angularSpeedRads_ = 0.0;
00264
00265
00266 robot_pose_px_ = 0.0;
00267 robot_pose_py_ = 0.0;
00268 robot_pose_pa_ = 0.0;
00269 robot_pose_vx_ = 0.0;
00270 robot_pose_vy_ = 0.0;
00271
00272
00273 v_ref_x_ = 0.0;
00274 v_ref_y_ = 0.0;
00275 w_ref_ = 0.0;
00276 v_ref_z_ = 0.0;
00277 pos_ref_pan_ = 0.0;
00278 pos_ref_tilt_= 0.0;
00279
00280
00281 ang_vel_x_ = 0.0; ang_vel_y_ = 0.0; ang_vel_z_ = 0.0;
00282 lin_acc_x_ = 0.0; lin_acc_y_ = 0.0; lin_acc_z_ = 0.0;
00283 orientation_x_ = 0.0; orientation_y_ = 0.0; orientation_z_ = 0.0; orientation_w_ = 0.0;
00284
00285
00286 active_kinematic_mode_ = SKID_STEERING;
00287
00288
00289 srv_SetMode_ = guardian_robot_control_node_handle.advertiseService("set_mode", &GuardianControllerClass::srvCallback_SetMode, this);
00290 srv_GetMode_ = guardian_robot_control_node_handle.advertiseService("get_mode", &GuardianControllerClass::srvCallback_GetMode, this);
00291 srv_SetOdometry_ = guardian_robot_control_node_handle.advertiseService("set_odometry", &GuardianControllerClass::srvCallback_SetOdometry, this);
00292
00293
00294 joint_state_sub_ = guardian_robot_control_node_handle.subscribe<sensor_msgs::JointState>("/guardian/joint_states", 1, &GuardianControllerClass::jointStateCallback, this);
00295
00296
00297 imu_sub_ = guardian_robot_control_node_handle.subscribe("/guardian/imu_data", 1, &GuardianControllerClass::imuCallback, this);
00298
00299
00300 ref_vel_frw_ = guardian_robot_control_node_handle.advertise<std_msgs::Float64>( frw_vel_topic_, 50);
00301 ref_vel_flw_ = guardian_robot_control_node_handle.advertise<std_msgs::Float64>( flw_vel_topic_, 50);
00302 ref_vel_blw_ = guardian_robot_control_node_handle.advertise<std_msgs::Float64>( blw_vel_topic_, 50);
00303 ref_vel_brw_ = guardian_robot_control_node_handle.advertise<std_msgs::Float64>( brw_vel_topic_, 50);
00304
00305 ref_pos_pan_ = guardian_robot_control_node_handle.advertise<std_msgs::Float64>( pan_pos_topic_, 50);
00306 ref_pos_tilt_ = guardian_robot_control_node_handle.advertise<std_msgs::Float64>( tilt_pos_topic_, 50);
00307
00308
00309 cmd_sub_ = guardian_robot_control_node_handle.subscribe<geometry_msgs::Twist>("command", 1, &GuardianControllerClass::commandCallback, this);
00310
00311
00312 ptz_sub_ = guardian_robot_control_node_handle.subscribe<robotnik_msgs::ptz>("command_ptz", 1, &GuardianControllerClass::command_ptzCallback, this);
00313
00314
00315
00316
00317 odom_pub_ = guardian_robot_control_node_handle.advertise<nav_msgs::Odometry>("/guardian/odom", 1000);
00318
00319
00320 diagnostic_.setHardwareID("guardian_robot_control - simulation");
00321 diagnostic_.add( freq_diag_ );
00322 diagnostic_.add( command_freq_ );
00323
00324
00325
00326 double min_freq = GUARDIAN_MIN_COMMAND_REC_FREQ;
00327 double max_freq = GUARDIAN_MAX_COMMAND_REC_FREQ;
00328 subs_command_freq = new diagnostic_updater::HeaderlessTopicDiagnostic("/guardian_robot_control/command", diagnostic_,
00329 diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10));
00330 subs_command_freq->addTask(&command_freq_);
00331
00332
00333 read_state_ = false;
00334 }
00335
00337 int starting()
00338 {
00339
00340 ROS_INFO("GuardianControllerClass::starting");
00341
00342
00343
00344
00345
00346
00347 if (read_state_) {
00348 vector<string> joint_names = joint_state_.name;
00349 frw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_wheel)) - joint_names.begin();
00350 flw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_wheel)) - joint_names.begin();
00351 blw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_wheel)) - joint_names.begin();
00352 brw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_wheel)) - joint_names.begin();
00353
00354
00355
00356 return 0;
00357 }
00358 else return -1;
00359 }
00360
00361
00363 void UpdateControl()
00364 {
00365
00366 if (active_kinematic_mode_ == SKID_STEERING) {
00367
00368 double v_left_mps, v_right_mps;
00369
00370
00371 v_left_mps = ((joint_state_.velocity[blw_vel_] + joint_state_.velocity[flw_vel_]) / 2.0) * (guardian_wheel_diameter_ / 2.0);
00372 v_right_mps = -((joint_state_.velocity[brw_vel_] + joint_state_.velocity[frw_vel_]) / 2.0) * (guardian_wheel_diameter_ / 2.0);
00373
00374
00375 linearSpeedXMps_ = (v_right_mps + v_left_mps) / 2.0;
00376 angularSpeedRads_ = (v_right_mps - v_left_mps) / guardian_d_tracks_m_;
00377
00378
00379
00380
00381
00382 double epv=0.0;
00383 double epw=0.0;
00384 static double epvant =0.0;
00385 static double epwant =0.0;
00386
00387
00388
00389
00390
00391 double kpv=2.5; double kdv=0.0;
00392 double kpw=25.0; double kdw=15.0;
00393
00394
00395 epv = v_ref_x_ - linearSpeedXMps_;
00396 epw = w_ref_ - angularSpeedRads_;
00397
00398
00399
00400 double uv= kpv * epv + kdv * (epv - epvant);
00401 double uw= kpw * epw + kdw * (epw - epwant);
00402 epvant = epv;
00403 epwant = epw;
00404
00405
00406 double dUl = uv - 0.5 * guardian_d_tracks_m_ * uw;
00407
00408 double dUr = -(uv + 0.5 * guardian_d_tracks_m_ * uw);
00409
00410
00411 double limit = 100.0;
00412
00413
00414
00415
00416 std_msgs::Float64 frw_ref_msg;
00417 std_msgs::Float64 flw_ref_msg;
00418 std_msgs::Float64 blw_ref_msg;
00419 std_msgs::Float64 brw_ref_msg;
00420
00421 double k1 = 0.5;
00422
00423 frw_ref_msg.data = saturation( -k1 * dUr, -limit, limit);
00424 flw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
00425 blw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
00426 brw_ref_msg.data = saturation( -k1 * dUr, -limit, limit);
00427
00428 ref_vel_frw_.publish( frw_ref_msg );
00429 ref_vel_flw_.publish( flw_ref_msg );
00430 ref_vel_blw_.publish( blw_ref_msg );
00431 ref_vel_brw_.publish( brw_ref_msg );
00432 }
00433
00434
00435 std_msgs::Float64 pan_ref_pos_msg, tilt_ref_pos_msg;
00436 pan_ref_pos_msg.data = pos_ref_pan_;
00437 ref_pos_pan_.publish( pan_ref_pos_msg );
00438 tilt_ref_pos_msg.data = pos_ref_tilt_;
00439 ref_pos_tilt_.publish( tilt_ref_pos_msg );
00440 }
00441
00442
00443 void UpdateOdometry()
00444 {
00445
00446 if (active_kinematic_mode_ == SKID_STEERING) {
00447
00448
00449 robot_pose_vx_ = linearSpeedXMps_ * cos(robot_pose_pa_);
00450 robot_pose_vy_ = linearSpeedXMps_ * sin(robot_pose_pa_);
00451 }
00452
00453
00454 double fSamplePeriod = 1.0 / desired_freq_;
00455 robot_pose_pa_ += ang_vel_z_ * fSamplePeriod;
00456 robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
00457 robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
00458
00459 }
00460
00461
00462 void PublishOdometry()
00463 {
00464 ros::Time current_time = ros::Time::now();
00465
00466
00467 geometry_msgs::TransformStamped odom_trans;
00468 odom_trans.header.stamp = current_time;
00469 odom_trans.header.frame_id = "odom";
00470 odom_trans.child_frame_id = "base_footprint";
00471
00472 odom_trans.transform.translation.x = robot_pose_px_;
00473 odom_trans.transform.translation.y = robot_pose_py_;
00474 odom_trans.transform.translation.z = 0.0;
00475 odom_trans.transform.rotation.x = orientation_x_;
00476 odom_trans.transform.rotation.y = orientation_y_;
00477 odom_trans.transform.rotation.z = orientation_z_;
00478 odom_trans.transform.rotation.w = orientation_w_;
00479
00480
00481
00482
00483 if (publish_odom_tf_) odom_broadcaster.sendTransform(odom_trans);
00484
00485
00486 nav_msgs::Odometry odom;
00487 odom.header.stamp = current_time;
00488 odom.header.frame_id = "odom";
00489
00490
00491
00492 odom.pose.pose.position.x = robot_pose_px_;
00493 odom.pose.pose.position.y = robot_pose_py_;
00494 odom.pose.pose.position.z = 0.0;
00495
00496 odom.pose.pose.orientation.x = orientation_x_;
00497 odom.pose.pose.orientation.y = orientation_y_;
00498 odom.pose.pose.orientation.z = orientation_z_;
00499 odom.pose.pose.orientation.w = orientation_w_;
00500
00501 for(int i = 0; i < 6; i++)
00502 odom.pose.covariance[i*6+i] = 0.1;
00503
00504
00505 odom.child_frame_id = "base_footprint";
00506
00507 odom.twist.twist.linear.x = robot_pose_vx_;
00508 odom.twist.twist.linear.y = robot_pose_vy_;
00509 odom.twist.twist.linear.z = 0.0;
00510
00511 odom.twist.twist.angular.x = ang_vel_x_;
00512 odom.twist.twist.angular.y = ang_vel_y_;
00513 odom.twist.twist.angular.z = ang_vel_z_;
00514
00515 for(int i = 0; i < 6; i++)
00516 odom.twist.covariance[6*i+i] = 0.1;
00517
00518
00519 odom_pub_.publish(odom);
00520 }
00521
00523 void stopping()
00524 {}
00525
00526
00527
00528
00529
00530
00531 void check_command_subscriber(diagnostic_updater::DiagnosticStatusWrapper &stat)
00532 {
00533 ros::Time current_time = ros::Time::now();
00534
00535 double diff = (current_time - last_command_time_).toSec();
00536
00537 if(diff > 1.0){
00538 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Topic is not receiving commands");
00539
00540
00541 }else{
00542 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Topic receiving commands");
00543 }
00544 }
00545
00546
00547
00548 void setCommand(const geometry_msgs::Twist &cmd_vel)
00549 {
00550 v_ref_x_ = saturation(cmd_vel.linear.x, -10.0, 10.0);
00551 v_ref_y_ = saturation(cmd_vel.linear.y, -10.0, 10.0);
00552 w_ref_ = saturation(cmd_vel.angular.z, -10.0, 10.0);
00553 v_ref_z_ = saturation(cmd_vel.linear.z, -10.0, 10.0);
00554 }
00555
00556
00557
00558 bool srvCallback_SetMode(robotnik_msgs::set_mode::Request& request, robotnik_msgs::set_mode::Response& response)
00559 {
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575 return false;
00576 }
00577
00578
00579 bool srvCallback_GetMode(robotnik_msgs::get_mode::Request& request, robotnik_msgs::get_mode::Response& response)
00580 {
00581 response.mode = active_kinematic_mode_;
00582 return true;
00583 }
00584
00585
00586
00587 bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response )
00588 {
00589
00590
00591
00592
00593
00594 response.ret = true;
00595 return true;
00596 }
00597
00598
00599
00600 void jointStateCallback(const sensor_msgs::JointStateConstPtr& msg)
00601 {
00602 joint_state_ = *msg;
00603 read_state_ = true;
00604 }
00605
00606
00607 void commandCallback(const geometry_msgs::TwistConstPtr& msg)
00608 {
00609
00610 last_command_time_ = ros::Time::now();
00611 subs_command_freq->tick();
00612
00613 base_vel_msg_ = *msg;
00614 this->setCommand(base_vel_msg_);
00615 }
00616
00617
00618 void command_ptzCallback(const robotnik_msgs::ptzConstPtr& msg)
00619 {
00620 pos_ref_pan_ += msg->pan / 180.0 * PI;
00621 pos_ref_tilt_ += msg->tilt / 180.0 * PI;
00622 }
00623
00624
00625 void imuCallback( const sensor_msgs::Imu& imu_msg){
00626
00627 orientation_x_ = imu_msg.orientation.x;
00628 orientation_y_ = imu_msg.orientation.y;
00629 orientation_z_ = imu_msg.orientation.z;
00630 orientation_w_ = imu_msg.orientation.w;
00631
00632 ang_vel_x_ = imu_msg.angular_velocity.x;
00633 ang_vel_y_ = imu_msg.angular_velocity.y;
00634 ang_vel_z_ = imu_msg.angular_velocity.z;
00635
00636 lin_acc_x_ = imu_msg.linear_acceleration.x;
00637 lin_acc_y_ = imu_msg.linear_acceleration.y;
00638 lin_acc_z_ = imu_msg.linear_acceleration.z;
00639 }
00640
00641 double saturation(double u, double min, double max)
00642 {
00643 if (u>max) u=max;
00644 if (u<min) u=min;
00645 return u;
00646 }
00647
00648 double radnorm( double value )
00649 {
00650 while (value > PI) value -= PI;
00651 while (value < -PI) value += PI;
00652 return value;
00653 }
00654
00655 double radnorm2( double value )
00656 {
00657 while (value > 2.0*PI) value -= 2.0*PI;
00658 while (value < -2.0*PI) value += 2.0*PI;
00659 return value;
00660 }
00661
00662 bool spin()
00663 {
00664 ROS_INFO("guardian_robot_control::spin()");
00665 ros::Rate r(desired_freq_);
00666
00667 while (!ros::isShuttingDown())
00668 {
00669 if (starting() == 0)
00670 {
00671 while(ros::ok() && node_handle_.ok()) {
00672 UpdateControl();
00673 UpdateOdometry();
00674 PublishOdometry();
00675 diagnostic_.update();
00676 ros::spinOnce();
00677 r.sleep();
00678 }
00679 ROS_INFO("END OF ros::ok() !!!");
00680 } else {
00681
00682
00683 usleep(1000000);
00684 ros::spinOnce();
00685 }
00686 }
00687
00688 ROS_INFO("guardian_robot_control::spin() - end");
00689 return true;
00690 }
00691
00692 };
00693
00694 int main(int argc, char** argv)
00695 {
00696 ros::init(argc, argv, "guardian_robot_control");
00697
00698 ros::NodeHandle n;
00699 GuardianControllerClass sxlrc(n);
00700
00701
00702
00703 sxlrc.spin();
00704
00705 return (0);
00706
00707
00708 }
00709