00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <unistd.h>
00020 #include <sys/time.h>
00021 #include <math.h>
00022
00023 #include <ros/ros.h>
00024 #include <geometry_msgs/Twist.h>
00025 #include <std_msgs/Bool.h>
00026 #include <tf/transform_broadcaster.h>
00027 #include <diagnostic_updater/diagnostic_updater.h>
00028 #include <rosie_msgs/PowerState.h>
00029
00030
00031 extern "C" {
00032 #include "omnilib/omnilib.h"
00033 }
00034
00035 #define LIMIT(x, l) ( (x>l) ? l : (x<-l) ? -l : x )
00036
00037 class Omnidrive
00038 {
00039 private:
00040 ros::NodeHandle n_;
00041 diagnostic_updater::Updater diagnostic_;
00042 ros::Publisher power_pub_;
00043 ros::Subscriber power_sub_;
00044 ros::Time watchdog_time_;
00045 double drive_[3], drive_last_[3];
00046 bool runstop_;
00047 std::string frame_id_;
00048 std::string child_frame_id_;
00049 std::string power_name_;
00050 void cmdArrived(const geometry_msgs::Twist::ConstPtr& msg);
00051 void stateUpdate(diagnostic_updater::DiagnosticStatusWrapper &s);
00052 void powerCommand(const rosie_msgs::PowerState::ConstPtr& msg);
00053 void runstopReceiver(const std_msgs::BoolConstPtr &msg);
00054 public:
00055 Omnidrive();
00056 void main();
00057 };
00058
00059
00060 Omnidrive::Omnidrive() : n_("omnidrive"), diagnostic_(), runstop_(false)
00061 {
00062 diagnostic_.setHardwareID("omnidrive");
00063 diagnostic_.add("Base", this, &Omnidrive::stateUpdate);
00064 n_.param("frame_id", frame_id_, std::string("/odom"));
00065 n_.param("child_frame_id", child_frame_id_, std::string("/base_link"));
00066 n_.param("power_name", power_name_, std::string("Wheels"));
00067
00068 power_pub_ = n_.advertise<rosie_msgs::PowerState>("/power_state", 1);
00069 power_sub_ = n_.subscribe<rosie_msgs::PowerState>("/power_command", 16, &Omnidrive::powerCommand, this);
00070
00071
00072 for(int i=0; i < 3; i++) {
00073 drive_last_[i] = 0;
00074 drive_[i] = 0;
00075 }
00076
00077 watchdog_time_ = ros::Time::now();
00078 }
00079
00080 void Omnidrive::cmdArrived(const geometry_msgs::Twist::ConstPtr& msg)
00081 {
00082
00083
00084 drive_[0] = msg->linear.x;
00085 drive_[1] = msg->linear.y;
00086 drive_[2] = msg->angular.z;
00087
00088 if(msg->linear.z == -1) {
00089
00090 for(int i=0; i < 3; i++) {
00091 drive_last_[i] = 0;
00092 drive_[i] = 0;
00093 }
00094 }
00095
00096 watchdog_time_ = ros::Time::now();
00097 }
00098
00099
00100 void Omnidrive::runstopReceiver(const std_msgs::BoolConstPtr &msg)
00101 {
00102 runstop_ = msg->data;
00103 }
00104
00105 void Omnidrive::stateUpdate(diagnostic_updater::DiagnosticStatusWrapper &s)
00106 {
00107 int estop;
00108 char drive[4];
00109 omnidrive_status(&drive[0], &drive[1], &drive[2], &drive[3], &estop);
00110
00111 bool operational = (drive[0] == '4' &&
00112 drive[1] == '4' &&
00113 drive[2] == '4' &&
00114 drive[3] == '4' &&
00115 estop == 0);
00116
00117 if(operational)
00118 s.summary(0, "Operational");
00119 else
00120 s.summary(1, "Down");
00121
00122 for(int i=0; i < 4; i++)
00123 s.add(std::string("status drive ")+(char) ('1' + i),
00124 std::string("")+drive[i]);
00125 s.add("Emergency Stop", (estop) ? "== pressed ==" : "released");
00126
00127 commstatus_t comm = omnidrive_commstatus();
00128
00129 for(int i=0; i < 4; i++)
00130 s.addf(std::string("comm status drive ")+(char) ('1' + i),
00131
00132 "0x%02X, %s, %s operational",
00133 comm.slave_state[i],
00134 comm.slave_online[i] ? "online" : "offline",
00135 comm.slave_operational[i] ? "" : "not");
00136
00137 s.addf("master state", "Link is %s, %d slaves, AL states: 0x%02X",
00138 comm.master_link ? "up" : "down",
00139 comm.master_slaves_responding,
00140 comm.master_al_states);
00141
00142 s.addf("working counter", "%d, %s",
00143 comm.working_counter,
00144 comm.working_counter_state == 2 ? "complete" : "incomplete");
00145
00146 rosie_msgs::PowerState power;
00147 power.name = power_name_;
00148 power.enabled = operational;
00149
00150 power_pub_.publish(power);
00151 }
00152
00153 void Omnidrive::powerCommand(const rosie_msgs::PowerState::ConstPtr& msg)
00154 {
00155 if(msg->name == power_name_)
00156 {
00157 int estop;
00158 char drive[4];
00159 omnidrive_status(&drive[0], &drive[1], &drive[2], &drive[3], &estop);
00160
00161 bool power_state = (drive[0] == '4' &&
00162 drive[1] == '4' &&
00163 drive[2] == '4' &&
00164 drive[3] == '4' &&
00165 estop == 0);
00166
00167 if(msg->enabled == true && power_state == false)
00168 {
00169 omnidrive_recover();
00170 omnidrive_poweron();
00171 }
00172
00173 if(msg->enabled == false && power_state == true)
00174 {
00175 omnidrive_poweroff();
00176 }
00177
00178 }
00179 }
00180
00181 void Omnidrive::main()
00182 {
00183 double speed, acc_max, t, radius, drift;
00184 int tf_frequency, runstop_frequency;
00185 const int loop_frequency = 250;
00186
00187 n_.param("speed", speed, 0.1);
00188
00189 n_.param("acceleration", acc_max, 0.5*speed*speed/0.015);
00190
00191 n_.param("radius", radius, 0.6);
00192 n_.param("tf_frequency", tf_frequency, 50);
00193 n_.param("runstop_frequency", runstop_frequency, 10);
00194 n_.param("watchdog_period", t, 0.5);
00195 ros::Duration watchdog_period(t);
00196 n_.param("odometry_correction", drift, 1.0);
00197
00198
00199 acc_max /= loop_frequency;
00200
00201 if(omnidrive_init() != 0) {
00202 ROS_ERROR("failed to initialize omnidrive");
00203 ROS_ERROR("check dmesg and try \"sudo /etc/init.d/ethercat restart\"");
00204 return;
00205 }
00206 omnidrive_set_correction(drift);
00207
00208 tf::TransformBroadcaster transforms;
00209
00210 ros::Subscriber sub = n_.subscribe("/cmd_vel", 10, &Omnidrive::cmdArrived, this);
00211 ros::Subscriber runstop_sub = n_.subscribe("/soft_runstop", 1, &Omnidrive::runstopReceiver, this);
00212 ros::Publisher hard_runstop_pub = n_.advertise<std_msgs::Bool>("/hard_runstop", 1);
00213
00214 double x=0, y=0, a=0;
00215
00216 int tf_publish_counter=0;
00217 int tf_send_rate = loop_frequency / tf_frequency;
00218
00219 int runstop_publish_counter=0;
00220 int runstop_send_rate = loop_frequency / runstop_frequency;
00221
00222 ros::Rate r(loop_frequency);
00223
00224 while(n_.ok()) {
00225
00226 omnidrive_odometry(&x, &y, &a);
00227
00228 if(ros::Time::now() - watchdog_time_ > watchdog_period || runstop_) {
00229
00230 omnidrive_drive(0, 0, 0);
00231
00232 if((drive_[0] != 0 || drive_[1] != 0 || drive_[2] !=0)
00233 && !runstop_)
00234 ROS_WARN("engaged watchdog!");
00235
00236 for(int i=0; i < 3; i++) {
00237 drive_last_[i] = 0;
00238 drive_[i] = 0;
00239 }
00240
00241 watchdog_time_ = ros::Time::now();
00242 }
00243
00244 for(int i=0; i < 3; i++) {
00245
00246 double acc = drive_[i] - drive_last_[i];
00247 double fac_rot = (i == 2) ? 1.0/radius : 1.0;
00248 acc = LIMIT(acc, acc_max*fac_rot*fac_rot);
00249 drive_[i] = drive_last_[i] + acc;
00250
00251
00252 drive_[i] = LIMIT(drive_[i], speed*fac_rot);
00253
00254 drive_last_[i] = drive_[i];
00255 }
00256
00257 omnidrive_drive(drive_[0], drive_[1], drive_[2]);
00258
00259
00260 if(++tf_publish_counter == tf_send_rate) {
00261 tf::Quaternion q;
00262 q.setRPY(0, 0, a);
00263 tf::Transform pose(q, tf::Point(x, y, 0.0));
00264 transforms.sendTransform(tf::StampedTransform(pose, ros::Time::now(), frame_id_, child_frame_id_));
00265 tf_publish_counter = 0;
00266 }
00267
00268
00269 if(++runstop_publish_counter == runstop_send_rate) {
00270 int runstop=0;
00271 omnidrive_status(0,0,0,0,&runstop);
00272 std_msgs::Bool msg;
00273 msg.data = (runstop != 0);
00274 hard_runstop_pub.publish(msg);
00275 runstop_publish_counter = 0;
00276 }
00277
00278
00279 ros::spinOnce();
00280
00281 diagnostic_.update();
00282 r.sleep();
00283 }
00284
00285 omnidrive_shutdown();
00286 }
00287
00288
00289 int main(int argc, char *argv[])
00290 {
00291 ros::init(argc, argv, "omni_ethercat");
00292
00293 Omnidrive drive;
00294 drive.main();
00295
00296 return 0;
00297 }