Go to the documentation of this file.00001
00026 #include "roboteq_driver/controller.h"
00027 #include "roboteq_driver/channel.h"
00028
00029 #include "roboteq_msgs/Status.h"
00030 #include "serial/serial.h"
00031
00032 #include <boost/bind.hpp>
00033 #include <boost/algorithm/string/replace.hpp>
00034 #include <boost/algorithm/string/trim.hpp>
00035 #include <boost/algorithm/string/split.hpp>
00036 #include <boost/algorithm/string/classification.hpp>
00037 #include <unistd.h>
00038 #include <iostream>
00039 #include <sstream>
00040
00041
00042 extern const char* script_lines[];
00043 extern const int script_ver = 8;
00044
00045 namespace roboteq {
00046
00047 const std::string eol("\r");
00048 const size_t max_line_length(128);
00049
00050 Controller::Controller(const char *port, int baud)
00051 : nh_("~"), port_(port), baud_(baud), connected_(false), version_(""),
00052 start_script_attempts_(0), serial_(NULL),
00053 command("!", this), query("?", this), param("^", this)
00054 {
00055 pub_status_ = nh_.advertise<roboteq_msgs::Status>("status", 1);
00056 }
00057
00058 Controller::~Controller() {
00059 }
00060
00061 void Controller::addChannel(Channel* channel) {
00062 channels_.push_back(channel);
00063 }
00064
00065 void Controller::connect() {
00066 if (!serial_) serial_ = new serial::Serial();
00067 serial::Timeout to(serial::Timeout::simpleTimeout(500));
00068 serial_->setTimeout(to);
00069 serial_->setPort(port_);
00070 serial_->setBaudrate(baud_);
00071
00072 for (int tries = 0; tries < 5; tries++) {
00073 try {
00074 serial_->open();
00075 query << "FID" << send;
00076 setSerialEcho(false);
00077 flush();
00078 } catch (serial::IOException) {
00079 }
00080
00081 if (serial_->isOpen()) {
00082 connected_ = true;
00083 return;
00084 } else {
00085 connected_ = false;
00086 ROS_INFO("Bad Connection with serial port Error %s",port_);
00087 }
00088 }
00089
00090 ROS_INFO("Motor controller not responding.");
00091 }
00092
00093 void Controller::read() {
00094 ROS_DEBUG_STREAM_NAMED("serial", "Bytes waiting: " << serial_->available());
00095 std::string msg = serial_->readline(max_line_length, eol);
00096 static bool receiving_script_messages = false;
00097 if (!msg.empty()) {
00098 ROS_DEBUG_STREAM_NAMED("serial", "RX: " << msg);
00099 if (msg[0] == '+' || msg[0] == '-') {
00100
00101 boost::lock_guard<boost::mutex> lock(last_response_mutex_);
00102 last_response_ = msg;
00103 last_response_available_.notify_one();
00104 } else if (msg[0] == '&') {
00105
00106 boost::trim(msg);
00107 if (msg[1] == 's') {
00108 processStatus(msg);
00109 } else if (msg[1] == 'f') {
00110 processFeedback(msg);
00111 }
00112 receiving_script_messages = true;
00113 } else {
00114
00115 ROS_WARN_STREAM("Unknown serial message received: " << msg);
00116 }
00117 } else {
00118 ROS_WARN_NAMED("serial", "Serial::readline() returned no data.");
00119 if (!receiving_script_messages) {
00120 if (start_script_attempts_ < 5) {
00121 start_script_attempts_++;
00122 ROS_DEBUG("Attempt #%d to start MBS program.", start_script_attempts_);
00123 startScript();
00124 flush();
00125 } else {
00126 ROS_DEBUG("Attempting to download MBS program.");
00127 if (downloadScript()) {
00128 start_script_attempts_ = 0;
00129 }
00130 ros::Duration(1.0).sleep();
00131 }
00132 } else {
00133 ROS_DEBUG("Script is believed to be in-place and running, so taking no action.");
00134 }
00135 }
00136 }
00137
00138 void Controller::write(std::string msg) {
00139 tx_buffer_ << msg << eol;
00140 }
00141
00142 void Controller::flush() {
00143 ROS_DEBUG_STREAM_NAMED("serial", "TX: " << boost::algorithm::replace_all_copy(tx_buffer_.str(), "\r", "\\r"));
00144 ssize_t bytes_written = serial_->write(tx_buffer_.str());
00145 if (bytes_written < tx_buffer_.tellp()) {
00146 ROS_WARN_STREAM("Serial write timeout, " << bytes_written << " bytes written of " << tx_buffer_.tellp() << ".");
00147 }
00148 tx_buffer_.str("");
00149 }
00150
00151 void Controller::processStatus(std::string str) {
00152 roboteq_msgs::Status msg;
00153 msg.header.stamp = ros::Time::now();
00154
00155 std::vector<std::string> fields;
00156 boost::split(fields, str, boost::algorithm::is_any_of(":"));
00157 try {
00158 int reported_script_ver = boost::lexical_cast<int>(fields[1]);
00159 static int wrong_script_version_count = 0;
00160 if (reported_script_ver == script_ver) {
00161 wrong_script_version_count = 0;
00162 } else {
00163 if (++wrong_script_version_count > 5) {
00164 ROS_WARN_STREAM("Script version mismatch. Expecting " << script_ver <<
00165 " but controller consistently reports " << reported_script_ver << ". " <<
00166 ". Now attempting download.");
00167 downloadScript();
00168 }
00169 return;
00170 }
00171
00172 if (fields.size() != 7) {
00173 ROS_WARN("Wrong number of status fields. Dropping message.");
00174 return;
00175 }
00176
00177 msg.fault = boost::lexical_cast<int>(fields[2]);
00178 msg.status = boost::lexical_cast<int>(fields[3]);
00179 msg.ic_temperature = boost::lexical_cast<int>(fields[6]);
00180 } catch (std::bad_cast& e) {
00181 ROS_WARN("Failure parsing status data. Dropping message.");
00182 return;
00183 }
00184
00185 pub_status_.publish(msg);
00186 }
00187
00188 void Controller::processFeedback(std::string msg) {
00189 std::vector<std::string> fields;
00190 boost::split(fields, msg, boost::algorithm::is_any_of(":"));
00191 if (fields.size() != 11) {
00192 ROS_WARN("Wrong number of feedback fields. Dropping message.");
00193 return;
00194 }
00195 int channel_num;
00196 try {
00197 channel_num = boost::lexical_cast<int>(fields[1]);
00198 } catch (std::bad_cast& e) {
00199 ROS_WARN("Failure parsing feedback channel number. Dropping message.");
00200 return;
00201 }
00202 if (channel_num >= 1 && channel_num <= channels_.size()) {
00203 channels_[channel_num - 1]->feedbackCallback(fields);
00204 } else {
00205 ROS_WARN("Bad channel number. Dropping message.");
00206 return;
00207 }
00208 }
00209
00210 bool Controller::downloadScript() {
00211 ROS_DEBUG("Commanding driver to stop executing script.");
00212 stopScript(); flush();
00213 ros::Duration(0.5).sleep();
00214 serial_->read();
00215
00216
00217 ROS_DEBUG("Commanding driver to enter download mode.");
00218 write("%SLD 321654987"); flush();
00219
00220
00221 for (int find_ack = 0; find_ack < 7; find_ack++) {
00222 std::string msg = serial_->readline(max_line_length, eol);
00223 ROS_DEBUG_STREAM_NAMED("serial", "HLD-RX: " << msg);
00224 if (msg == "HLD\r") goto found_ack;
00225 }
00226 ROS_DEBUG("Could not enter download mode.");
00227 return false;
00228 found_ack:
00229
00230
00231 int line_num = 0;
00232 while(script_lines[line_num]) {
00233 std::string line(script_lines[line_num]);
00234 write(line);
00235 flush();
00236 std::string ack = serial_->readline(max_line_length, eol);
00237 ROS_DEBUG_STREAM_NAMED("serial", "ACK-RX: " << ack);
00238 if (ack != "+\r") return false;
00239 line_num++;
00240 }
00241 return true;
00242 }
00243
00244 }