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 #include <stdio.h>
00033 #include <vector>
00034 #include <math.h>
00035 #include <sstream>
00036
00037 #include <ros/ros.h>
00038 #include <cereal_port/CerealPort.h>
00039
00040 #include "sensorhand_speed/hand_cmd.h"
00041 #include "sensorhand_speed/hand_dump.h"
00042
00043 #define TIMEOUT 100
00044
00045
00046 enum Command_id {START_DUMP = 0, STOP_DUMP = 1, OPEN = 2, CLOSE = 3, STOP = 4, GET_SN = 5, RESET = 6, PRGM = 7};
00047 typedef struct {
00048 Command_id id;
00049 double param;
00050 char* response;
00051 } Command;
00052
00053 enum State {IDLE, READ_FIRST, READ_LEN, READ_DATA, READ_CS} state;
00054
00055
00056 bool readByte(cereal::CerealPort* device, char* data);
00057 bool sendCommand(cereal::CerealPort* device, Command* cmd);
00058 bool srv_callback(sensorhand_speed::hand_cmd::Request& request, sensorhand_speed::hand_cmd::Response& response);
00059 void publish_dump(ros::Publisher& dump_pub, char* data);
00060
00061
00062
00063 std::vector<Command> pending_cmd;
00064 bool dump_mode = false;
00065
00066
00067
00068
00069
00070
00071
00072 int main(int argc, char** argv) {
00073 ros::init(argc, argv, "hand_node");
00074 ros::NodeHandle n("~");
00075
00076 cereal::CerealPort device;
00077
00078
00079 ros::ServiceServer service = n.advertiseService("hand_srv", srv_callback);
00080
00081
00082 ros::Publisher dump_pub = n.advertise<sensorhand_speed::hand_dump>("hand_dump", 1000);
00083
00084 std::string port;
00085 if (!n.hasParam("port")) {
00086 ROS_WARN("Parameter port not received, using default value /dev/ttyUSB0");
00087 }
00088 n.param<std::string>("port", port, "/dev/ttyUSB0");
00089
00090 int baud_rate;
00091 if (!n.hasParam("baud_rate")) {
00092 ROS_WARN("Parameter baud_rate not received, using default value 19200");
00093 }
00094 n.param<int>("baud_rate", baud_rate, 19200);
00095
00096 try {
00097 device.open(port.c_str(), baud_rate);
00098 }
00099 catch(cereal::Exception& e) {
00100 ROS_FATAL("Unable to open the serial port %s.", port.c_str());
00101 ROS_BREAK();
00102 }
00103 ROS_INFO("The serial port %s is opened at %d baud", port.c_str(), baud_rate);
00104
00105
00106 char reply;
00107 char* data;
00108 size_t data_pos = 0;
00109 uint8_t data_len = 0;
00110 char cs = 0x00;
00111
00112
00113 ros::Duration(0.5).sleep();
00114 ros::spinOnce();
00115
00116 state = IDLE;
00117 ROS_INFO("state IDLE");
00118
00119
00120 Command cmd;
00121
00122
00123 device.flush();
00124
00125 cmd.param = 0.;
00126 cmd.id = RESET;
00127
00128 sendCommand(&device, &cmd);
00129 device.flush();
00130
00131 bool dump_msg = false;
00132 bool busy = false;
00133 bool waiting_for_dump;
00134
00135 ros::Rate r(100);
00136 while(ros::ok()) {
00137 if(!pending_cmd.empty() && !busy && !waiting_for_dump) {
00138 device.flush();
00139 sendCommand(&device, &(pending_cmd[0]));
00140 state = READ_FIRST;
00141 busy = true;
00142 }
00143 switch(state) {
00144 case READ_FIRST:
00145 if(readByte(&device, &reply)) {
00146 if((uint8_t) reply == 0xff) {
00147 state = READ_LEN;
00148 ROS_INFO("state READ_LEN");
00149 dump_msg = true;
00150 } else {
00151 data_len = (uint8_t) reply;
00152 ROS_INFO("data_len is %u", data_len);
00153 if(!data) free(data);
00154 data = (char*) calloc(data_len, sizeof(char));
00155 data_pos = 0;
00156 cs = reply;
00157 state = READ_DATA;
00158 ROS_INFO("state READ_DATA (from READ_FIRST)");
00159 dump_msg = false;
00160 }
00161 }
00162 break;
00163 case READ_LEN:
00164 if(readByte(&device, &reply)) {
00165 data_len = (uint8_t) reply;
00166 ROS_INFO("data_len is %u", data_len);
00167 if(!data) free(data);
00168 data = (char*) calloc(data_len, sizeof(char));
00169 data_pos = 0;
00170 cs = reply;
00171 state = READ_DATA;
00172 ROS_INFO("state READ_DATA (from READ_LEN)");
00173 }
00174 break;
00175 case READ_DATA:
00176 if(readByte(&device, &reply)) {
00177 if(data_pos < data_len - 1) {
00178 data[data_pos] = reply;
00179 data_pos++;
00180 cs = cs + reply;
00181 if(data_pos == data_len - 1) {
00182 state = READ_CS;
00183 ROS_INFO("state READ_CS");
00184 }
00185 }
00186 }
00187 break;
00188 case READ_CS:
00189 if(readByte(&device, &reply)) {
00190 if(reply != cs) {
00191 ROS_WARN("Check sum incorrect, received data will be discharded");
00192 data_len = 0;
00193 free(data);
00194 break;
00195 }
00196 if(data_len == 2 && data[0] == 0x73) {
00197 dump_mode = true;
00198 waiting_for_dump = true;
00199 state = READ_FIRST;
00200 ROS_INFO("state READ_FIRST");
00201 }
00202 if(data_len == 2 && data[0] == 0x7a) {
00203 dump_mode = false;
00204 ROS_INFO("DUMP MODE OFF");
00205 }
00206 if(dump_msg && dump_mode) {
00207 publish_dump(dump_pub, data);
00208 cmd.id = STOP_DUMP;
00209 sendCommand(&device, &cmd);
00210 ros::Duration(0.05).sleep();
00211 device.flush();
00212 cmd.id = START_DUMP;
00213 pending_cmd.push_back(cmd);
00214 waiting_for_dump = false;
00215 } else {
00216 if(data_pos+1 != (uint8_t) pending_cmd[0].response[0]) {
00217 ROS_WARN("Response length of %u incorrect, expected %u", (uint8_t) pending_cmd[0].response[0], data_pos+1 );
00218 } else {
00219 for(size_t i = 0; i < data_pos; i++) {
00220 if(data[i] != pending_cmd[0].response[i+1]) {
00221 ROS_WARN("Response data %02x incorrect, expected %02x", (uint8_t) data[i], (uint8_t) pending_cmd[0].response[i] );
00222 }
00223 }
00224 }
00225 pending_cmd.erase(pending_cmd.begin());
00226 }
00227 if(!dump_mode) {
00228 state = IDLE;
00229 ROS_INFO("state IDLE");
00230
00231 for(size_t i = 0; i < pending_cmd.size(); i++) {
00232 if(pending_cmd[i].id == START_DUMP) {
00233 pending_cmd.erase(pending_cmd.begin() + i);
00234 i--;
00235 }
00236 }
00237
00238 }
00239 ROS_INFO("Received data is:");
00240 for(size_t i = 0; i < data_pos; i++) {
00241 ROS_INFO("%02x", (uint8_t) data[i]);
00242 }
00243 busy = false;
00244
00245 free(data);
00246 }
00247 break;
00248 default:
00249 break;
00250 }
00251
00252 ros::spinOnce();
00253 r.sleep();
00254 }
00255 free(data);
00256 return 0;
00257 }
00258
00259
00260
00261
00262
00263
00264
00265
00266 bool readByte(cereal::CerealPort* device, char* data) {
00267 try {
00268 device->readBytes(data, 1, TIMEOUT);
00269 } catch(cereal::TimeoutException& e) {
00270 ROS_ERROR("Timeout while reading from serial port.");
00271 return false;
00272 }
00273 ROS_INFO("Received %02x", (uint8_t) *data);
00274 return true;
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286 bool sendCommand(cereal::CerealPort* device, Command* cmd) {
00287 uint8_t cmd_size = 0;
00288
00289 char cmd_buffer[5];
00290
00291
00292
00293 cmd->response = (char*) calloc(8, sizeof(char));
00294
00295 switch(cmd->id) {
00296 case START_DUMP:
00297 cmd_size = 2;
00298 cmd_buffer[1] = 0x73;
00299
00300
00301
00302 cmd->response[0] = 2;
00303 cmd->response[1] = cmd_buffer[1];
00304
00305 break;
00306 case STOP_DUMP:
00307 cmd_size = 2;
00308 cmd_buffer[1] = 0x7a;
00309
00310
00311
00312 cmd->response[0] = 2;
00313 cmd->response[1] = cmd_buffer[1];
00314
00315
00316 break;
00317 case OPEN:
00318 cmd_size = 4;
00319 cmd_buffer[1] = 0x75;
00320 {
00321 cmd->param = std::min(std::max(fabs(cmd->param), 0.), 1.0);
00322 cmd_buffer[2] = (char) (0x31 + cmd->param*(0x85 - 0x31));
00323 }
00324 cmd_buffer[3] = 0x00;
00325
00326
00327
00328 cmd->response[0] = 3;
00329 cmd->response[1] = cmd_buffer[2];
00330 cmd->response[2] = cmd_buffer[3];
00331 break;
00332 case CLOSE:
00333 cmd_size = 4;
00334 cmd_buffer[1] = 0x75;
00335 cmd_buffer[2] = 0x00;
00336 {
00337 cmd->param = std::min(std::max(fabs(cmd->param), 0.), 1.0);
00338 cmd_buffer[3] = (char) (0x31 + cmd->param*(0x85 - 0x31));
00339 }
00340
00341
00342
00343 cmd->response[0] = 3;
00344 cmd->response[1] = cmd_buffer[2];
00345 cmd->response[2] = cmd_buffer[3];
00346 break;
00347 case STOP:
00348 cmd_size = 4;
00349 cmd_buffer[1] = 0x75;
00350 cmd_buffer[2] = 0x00;
00351 cmd_buffer[3] = 0x00;
00352
00353
00354
00355 cmd->response[0] = 3;
00356 cmd->response[1] = cmd_buffer[2];
00357 cmd->response[2] = cmd_buffer[3];
00358 break;
00359 case GET_SN:
00360 cmd_size = 2;
00361 cmd_buffer[1] = 0x76;
00362
00363
00364
00365
00366 cmd->response[0] = 8;
00367 cmd->response[1] = 0x31;
00368 cmd->response[2] = 0x31;
00369 cmd->response[3] = 0x30;
00370 cmd->response[4] = 0x2c;
00371 cmd->response[5] = 0x30;
00372 cmd->response[6] = 0x2e;
00373 cmd->response[7] = 0x35;
00374 break;
00375 case RESET:
00376 cmd_size = 2;
00377 cmd_buffer[1] = 0x6d;
00378
00379
00380
00381 cmd->response[0] = 2;
00382 cmd->response[1] = 0x6d;
00383 break;
00384 case PRGM:
00385 cmd_size = 3;
00386 cmd_buffer[1] = 0x61;
00387 cmd_buffer[2] = (char) (cmd->param);
00388
00389
00390
00391 cmd->response[0] = 3;
00392 cmd->response[1] = 0x61;
00393 cmd->response[2] = cmd_buffer[2];
00394 break;
00395 default:
00396 ;
00397 }
00398 cmd_buffer[0] = cmd_size;
00399 cmd_buffer[cmd_size] = 0;
00400
00401
00402 for(uint8_t i = 0; i < cmd_size; i++) {
00403 cmd_buffer[cmd_size] = cmd_buffer[cmd_size] + cmd_buffer[i];
00404 }
00405
00406 std::stringstream ss;
00407 ss << "Command";
00408 char substr[4];
00409 for(uint8_t i = 0; i <= cmd_size; i++) {
00410 snprintf(substr, 4, " %02x", cmd_buffer[i]);
00411 ss << substr;
00412 }
00413 if(device->write(cmd_buffer, cmd_size + 1) == cmd_size + 1) {
00414 ss << " sent successfully";
00415 ROS_INFO_STREAM(ss.str());
00416 return true;
00417 } else {
00418 ss << " NOT successful";
00419 ROS_INFO_STREAM(ss.str());
00420 return false;
00421 }
00422
00423 }
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 bool srv_callback(sensorhand_speed::hand_cmd::Request& request, sensorhand_speed::hand_cmd::Response& response) {
00435 ROS_INFO("Hand service called");
00436
00437 Command cmd;
00438 cmd.param = request.param;
00439 cmd.id = (Command_id) request.cmd;
00440 pending_cmd.push_back(cmd);
00441
00442 response.success = true;
00443 return true;
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 void publish_dump(ros::Publisher& dump_pub, char* data) {
00464 sensorhand_speed::hand_dump msg;
00465 msg.V_open = 1.5/85 * (uint8_t) data[0];
00466 msg.V_close = 1.5/85 * (uint8_t) data[1];
00467 msg.V_bat = 8.4/238 * (uint8_t) data[2];
00468 msg.state = (uint8_t) data[3];
00469 msg.F_bracket = 120./110 * (uint8_t) data[4];
00470 msg.F_pad1 = 120./110 * (uint8_t) data[5];
00471 msg.F_pad2 = 120./110 * (uint8_t) data[6];
00472 msg.F_pad3 = 120./110 * (uint8_t) data[7];
00473 msg.I = 1.5/141 * (uint8_t) data[8];
00474
00475 dump_pub.publish(msg);
00476 }