void hokuyo::Laser::queryVersionInformation() { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); if (sendCmd("VV",1000) != 0) HOKUYO_EXCEPT(hokuyo::Exception, "Error requesting version information"); char buf[100]; vendor_name_ = laserReadlineAfter(buf, 100, "VEND:"); vendor_name_ = vendor_name_.substr(0,vendor_name_.length() - 3); product_name_ = laserReadlineAfter(buf, 100, "PROD:"); product_name_ = product_name_.substr(0,product_name_.length() - 3); firmware_version_ = laserReadlineAfter(buf, 100, "FIRM:"); firmware_version_ = firmware_version_.substr(0,firmware_version_.length() - 3); protocol_version_ = laserReadlineAfter(buf, 100, "PROT:"); protocol_version_ = protocol_version_.substr(0,protocol_version_.length() - 3); // This crazy naming scheme is for backward compatibility. Initially // the serial number always started with an H. Then it got changed to a // zero. For a while the driver was removing the leading zero in the // serial number. This is fine as long as it is indeed a zero in front. // The current behavior is backward compatible but will accomodate full // length serial numbers. serial_number_ = laserReadlineAfter(buf, 100, "SERI:"); serial_number_ = serial_number_.substr(0,serial_number_.length() - 3); if (serial_number_[0] == '0') serial_number_[0] = 'H'; else if (serial_number_[0] != 'H') serial_number_ = 'H' + serial_number_; }
int hokuyo::Laser::requestScans(bool intensity, double min_ang, double max_ang, int cluster, int skip, int count, int timeout) { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); int status; if (cluster == 0) cluster = 1; int min_i = (int)(afrt_ + min_ang*ares_/(2.0*M_PI)); int max_i = (int)(afrt_ + max_ang*ares_/(2.0*M_PI)); char cmdbuf[MAX_CMD_LEN]; char intensity_char = 'D'; if (intensity) intensity_char = 'E'; sprintf(cmdbuf,"M%c%.4d%.4d%.2d%.1d%.2d", intensity_char, min_i, max_i, cluster, skip, count); status = sendCmd(cmdbuf, timeout); return status; }
long long hokuyo::Laser::calcLatency(bool intensity, double min_ang, double max_ang, int clustering, int skip, int num, int timeout) { offset_ = 0; if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); if (num <= 0) num = 10; int ckreps = 1; int scanreps = 1; long long int start = getHokuyoClockOffset(ckreps, timeout); long long int pre = 0; std::vector<long long int> samples(num); for (int i = 0; i < num; i++) { long long int scan = getHokuyoScanStampToSystemStampOffset(intensity, min_ang, max_ang, clustering, skip, scanreps, timeout) - start; long long int post = getHokuyoClockOffset(ckreps, timeout) - start; samples[i] = scan - (post+pre)/2; //printf("%lli %lli %lli %lli %lli\n", samples[i], post, pre, scan, pre - post); //fflush(stdout); pre = post; } offset_ = median(samples); //printf("%lli\n", median(samples)); return offset_; }
void hokuyo::Laser::querySensorConfig() { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); if (sendCmd("PP",1000) != 0) HOKUYO_EXCEPT(hokuyo::Exception, "Error requesting configuration information"); char buf[100]; char* ind; ind = laserReadlineAfter(buf,100,"DMIN:",-1); sscanf(ind, "%d", &dmin_); ind = laserReadlineAfter(buf,100,"DMAX:",-1); sscanf(ind, "%d", &dmax_); ind = laserReadlineAfter(buf,100,"ARES:",-1); sscanf(ind, "%d", &ares_); ind = laserReadlineAfter(buf,100,"AMIN:",-1); sscanf(ind, "%d", &amin_); ind = laserReadlineAfter(buf,100,"AMAX:",-1); sscanf(ind, "%d", &amax_); ind = laserReadlineAfter(buf,100,"AFRT:",-1); sscanf(ind, "%d", &afrt_); ind = laserReadlineAfter(buf,100,"SCAN:",-1); sscanf(ind, "%d", &rate_); return; }
int hokuyo::Laser::sendCmd(const char* cmd, int timeout) { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); char buf[100]; //printf("sendreq: %s\n", cmd); laserWrite(cmd); laserWrite("\n");; laserReadlineAfter(buf, 100, cmd, timeout); laserReadline(buf,100,timeout); //printf("chksum: %s",buf); if (!checkSum(buf,4)) { //printf("chksum error\n"); HOKUYO_EXCEPT(hokuyo::CorruptedDataException, "Checksum failed on status code."); } buf[2] = 0; //printf("sendreq_end: %s\n", cmd); if (buf[0] - '0' >= 0 && buf[0] - '0' <= 9 && buf[1] - '0' >= 0 && buf[1] - '0' <= 9) return (buf[0] - '0')*10 + (buf[1] - '0'); else HOKUYO_EXCEPT(hokuyo::Exception, "Hokuyo error code returned. Cmd: %s -- Error: %s", cmd, buf); }
void hokuyo::Laser::close () { int retval = 0; if (portOpen()) { //Try to be a good citizen and completely shut down the laser before we shutdown communication try { reset(); } catch (hokuyo::Exception& e) { //Exceptions here can be safely ignored since we are closing the port anyways } #if HOKUYO_INTERFACE_ETHERNET tcpclient_close(&tcpclient); #else retval = ::close(laser_fd_); // Automatically releases the lock. #endif } laser_fd_ = -1; if (retval != 0) HOKUYO_EXCEPT(hokuyo::Exception, "Failed to close port properly -- error = %d: %s\n", errno, strerror(errno)); }
bool hokuyo::Laser::isIntensitySupported() { hokuyo::LaserScan scan; if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); // Try an intensity command. try { requestScans(1, 0, 0, 0, 0, 1); serviceScan(scan, 1000); return true; } catch (hokuyo::Exception &e) {} // Try an intensity command. try { requestScans(0, 0, 0, 0, 0, 1); serviceScan(scan, 1000); return false; } catch (hokuyo::Exception &e) { HOKUYO_EXCEPT(hokuyo::Exception, "Exception whil trying to determine if intensity scans are supported.") } }
std::string hokuyo::Laser::getID() { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); return serial_number_; }
std::string hokuyo::Laser::getFirmwareVersion() { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); return firmware_version_; }
std::string hokuyo::Laser::getProtocolVersion() { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); return protocol_version_; }
std::string hokuyo::Laser::getVendorName() { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); return vendor_name_; }
std::string hokuyo::Laser::getProductName() { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); return product_name_; }
bool SerialPortControl::openPort (void) { this->portInit(); bool result = 0; result = serialPort->open(open_mode); if (result) emit portOpen(); return(result); }
void hokuyo::Laser::open(const char * tcphost, const int tcpport) { if (portOpen()) close(); // Make IO non blocking. This way there are no race conditions that // cause blocking when a badly behaving process does a read at the same // time as us. Will need to switch to blocking for writes or errors // occur just after a replug event. laser_fd_ = tcpclient_open(&tcpclient,tcphost, tcpport);//::open(port_name, O_RDWR | O_NONBLOCK | O_NOCTTY); //laser_fd_ = tcpclient_open(&tcpclient,"127.0.0.1", 10001);//::open(port_name, O_RDWR | O_NONBLOCK | O_NOCTTY); read_buf_start = read_buf_end = 0; if (laser_fd_ < 0) { HOKUYO_EXCEPT(hokuyo::Exception, "Failed to open tcp_client: %s:%d. %s (errno = %d)", tcphost,tcpport, strerror(errno), errno); } laser_fd_ = tcpclient.sock_desc; try { // Some models (04LX) need to be told to go into SCIP2 mode... laserFlush(); // Just in case a previous failure mode has left our Hokuyo // spewing data, we send reset the laser to be safe. try { reset(); } catch (hokuyo::Exception &e) { // This might be a device that needs to be explicitely placed in // SCIP2 mode. // Note: Not tested: a device that is currently scanning in SCIP1.1 // mode might not manage to switch to SCIP2.0. setToSCIP2(); // If this fails then it wasn't a device that could be switched to SCIP2. reset(); // If this one fails, it really is an error. } querySensorConfig(); queryVersionInformation(); // In preparation for calls to get various parts of the version info. } catch (hokuyo::Exception& e) { // These exceptions mean something failed on open and we should close if (laser_fd_ != -1) tcpclient_close(&tcpclient); laser_fd_ = -1; throw e; } }
int cereal::CerealPort::available() { if (!portOpen()) { return 0; } int count = 0; if (-1 == ioctl (fd_, TIOCINQ, &count)) { CEREAL_EXCEPT(cereal::Exception, "Available error -- error = %d: %s\n", errno, strerror(errno)); } else { return static_cast<size_t> (count); } }
void hokuyo::Laser::setToSCIP2() { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); const char * cmd = "SCIP2.0"; char buf[100]; laserWrite(cmd); laserWrite("\n"); laserReadline(buf, 100, 1000); ROS_DEBUG("Laser comm protocol changed to %s \n", buf); //printf ("Laser comm protocol changed to %s \n", buf); }
int hokuyo::Laser::pollScan(hokuyo::LaserScan& scan, double min_ang, double max_ang, int cluster, int timeout) { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); int status; // Always clear ranges/intensities so we can return easily in case of erro scan.ranges.clear(); scan.intensities.clear(); // clustering of 0 and 1 are actually the same if (cluster == 0) cluster = 1; int min_i = (int)(afrt_ + min_ang*ares_/(2.0*M_PI)); int max_i = (int)(afrt_ + max_ang*ares_/(2.0*M_PI)); char cmdbuf[MAX_CMD_LEN]; sprintf(cmdbuf,"GD%.4d%.4d%.2d", min_i, max_i, cluster); status = sendCmd(cmdbuf, timeout); scan.system_time_stamp = timeHelper() + offset_; if (status != 0) return status; // Populate configuration scan.config.min_angle = (min_i - afrt_) * (2.0*M_PI)/(ares_); scan.config.max_angle = (max_i - afrt_) * (2.0*M_PI)/(ares_); scan.config.ang_increment = cluster*(2.0*M_PI)/(ares_); scan.config.time_increment = (60.0)/(double)(rate_ * ares_); scan.config.scan_time = 0.0; scan.config.min_range = dmin_ / 1000.0; scan.config.max_range = dmax_ / 1000.0; readData(scan, false, timeout); long long inc = (long long)(min_i * scan.config.time_increment * 1000000000); scan.system_time_stamp += inc; scan.self_time_stamp += inc; return 0; }
std::string hokuyo::Laser::getStatus() { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); if (sendCmd("II",1000) != 0) HOKUYO_EXCEPT(hokuyo::Exception, "Error requesting device information information"); char buf[100]; char* stat = laserReadlineAfter(buf, 100, "STAT:"); std::string statstr(stat); statstr = statstr.substr(0,statstr.length() - 3); return statstr; }
void hokuyo::Laser::reset () { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); laserFlush(); try { sendCmd("TM2", 1000); } catch (hokuyo::Exception &e) {} // Ignore. If the laser was scanning TM2 would fail try { sendCmd("RS", 1000); } catch (hokuyo::Exception &e) {} // Ignore. If the command coincided with a scan we might get garbage. laserFlush(); sendCmd("RS", 1000); // This one should just work. }
SerialPort::~SerialPort() { if (portOpen()) close(); }
long long hokuyo::Laser::calcLatency(bool intensity, double min_ang, double max_ang, int clustering, int skip, int num, int timeout) { ROS_DEBUG("Entering calcLatency."); if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); static const std::string buggy_version = "1.16.02(19/Jan./2010)"; if (firmware_version_ == buggy_version) { ROS_INFO("Hokuyo firmware version %s detected. Using hard-coded time offset of -23 ms.", buggy_version.c_str()); offset_ = -23000000; } else { offset_ = 0; uint64_t comp_time = 0; uint64_t laser_time = 0; long long diff_time = 0; long long drift_time = 0; long long tmp_offset1 = 0; long long tmp_offset2 = 0; int count = 0; sendCmd("TM0",timeout); count = 100; for (int i = 0; i < count;i++) { usleep(1000); sendCmd("TM1",timeout); comp_time = timeHelper(); try { laser_time = readTime(); diff_time = comp_time - laser_time; tmp_offset1 += diff_time / count; } catch (hokuyo::RepeatedTimeException &e) { // We expect to get Repeated Time's when hammering on the time server continue; } } uint64_t start_time = timeHelper(); usleep(5000000); sendCmd("TM1;a",timeout); sendCmd("TM1;b",timeout); comp_time = timeHelper(); drift_time = comp_time - start_time; laser_time = readTime() + tmp_offset1; diff_time = comp_time - laser_time; double drift_rate = double(diff_time) / double(drift_time); sendCmd("TM2",timeout); if (requestScans(intensity, min_ang, max_ang, clustering, skip, num, timeout) != 0) HOKUYO_EXCEPT(hokuyo::Exception, "Error requesting scans during latency calculation"); hokuyo::LaserScan scan; count = 200; for (int i = 0; i < count;i++) { try { serviceScan(scan, 1000); } catch (hokuyo::CorruptedDataException &e) { continue; } comp_time = scan.system_time_stamp; drift_time = comp_time - start_time; laser_time = scan.self_time_stamp + tmp_offset1 + (long long)(drift_time*drift_rate); diff_time = laser_time - comp_time; tmp_offset2 += diff_time / count; } offset_ = tmp_offset2; stopScanning(); } ROS_DEBUG("Leaving calcLatency."); return offset_; }
void hokuyo::Laser::open(const char * port_name) { if (portOpen()) close(); laser_port_ = fopen(port_name, "r+"); if (laser_port_ == NULL) { const char *extra_msg = ""; switch (errno) { case EACCES: extra_msg = "You probably don't have premission to open the port for reading and writing."; break; case ENOENT: extra_msg = "The requested port does not exist. Is the hokuyo connected? Was the port name misspelled?"; break; } HOKUYO_EXCEPT(hokuyo::Exception, "Failed to open port: %s. %s (errno = %d). %s", port_name, strerror(errno), errno, extra_msg); } try { laser_fd_ = fileno (laser_port_); if (laser_fd_ == -1) HOKUYO_EXCEPT(hokuyo::Exception, "Failed to get file descriptor -- error = %d: %s", errno, strerror(errno)); // Make IO non blocking. This way there are no race conditions that // cause blocking when a badly behaving process does a read at the same // time as us. Will need to switch to blocking for writes or errors // occur just after a replug event. // No error checking. This really shouldn't fail, and even if it does, // we aren't so badly off. fcntl(laser_fd_, F_SETFL, fcntl(laser_fd_,F_GETFL,0) | O_NONBLOCK); struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = getpid(); if (fcntl(laser_fd_, F_SETLK, &fl) != 0) HOKUYO_EXCEPT(hokuyo::Exception, "Device %s is already locked. Try 'lsof | grep %s' to find other processes that currently have the port open.", port_name, port_name); // Settings for USB? struct termios newtio; memset (&newtio, 0, sizeof (newtio)); newtio.c_cflag = CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = ICANON; // activate new settings tcflush (laser_fd_, TCIFLUSH); if (tcsetattr (laser_fd_, TCSANOW, &newtio) < 0) HOKUYO_EXCEPT(hokuyo::Exception, "Unable to set serial port attributes. The port you specified (%s) may not be a serial port.", port_name); /// @todo tcsetattr returns true if at least one attribute was set. Hence, we might not have set everything on success. usleep (200000); // Some models (04LX) need to be told to go into SCIP2 mode... laserFlush(); // Just in case a previous failure mode has left our Hokuyo // spewing data, we send reset the laser to be safe. try { reset(); } catch (hokuyo::Exception &e) { // This might be a device that needs to be explicitely placed in // SCIP2 mode. // Note: Not tested: a device that is currently scanning in SCIP1.1 // mode might not manage to switch to SCIP2.0. setToSCIP2(); // If this fails then it wasn't a device that could be switched to SCIP2. reset(); // If this one fails, it really is an error. } querySensorConfig(); queryVersionInformation(); // In preparation for calls to get various parts of the version info. } catch (hokuyo::Exception& e) { // These exceptions mean something failed on open and we should close if (laser_port_ != NULL) fclose(laser_port_); laser_port_ = NULL; laser_fd_ = -1; throw e; } }
int hokuyo::Laser::serviceScan(hokuyo::LaserScan& scan, int timeout) { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); // Always clear ranges/intensities so we can return easily in case of erro scan.ranges.clear(); scan.intensities.clear(); char buf[100]; bool intensity = false; int min_i; int max_i; int cluster; int skip; int left; char* ind; int status = -1; //printf("in serviceReques!\n"); do { //printf("in serviceReques1!\n"); ind = laserReadlineAfter(buf, 100, "M",timeout); //printf("in serviceReques2!\n"); scan.system_time_stamp = timeHelper() + offset_; // //printf("buf: %s\n",buf); // //printf("in serviceReques3!\n"); if (ind[0] == 'D') intensity = false; else if (ind[0] == 'E') intensity = true; else { //printf("in serviceReques4!\n"); continue; } ind++; sscanf(ind, "%4d%4d%2d%1d%2d", &min_i, &max_i, &cluster, &skip, &left); //99b //02]I8 //0^k0ij0Hm0>W1851:C1DN08018m1E11:^1Ao0GV0c?0Kg13j0E@0YF0h81C\1A_0X laserReadline(buf,100,timeout); buf[4] = 0; if (!checkSum(buf, 4)) HOKUYO_EXCEPT(hokuyo::CorruptedDataException, "Checksum failed on status code: %s", buf); sscanf(buf, "%2d", &status); if (status != 99) return status; } while(status != 99); //printf("in serviceReques5!\n"); scan.config.min_angle = (min_i - afrt_) * (2.0*M_PI)/(ares_); scan.config.max_angle = (max_i - afrt_) * (2.0*M_PI)/(ares_); scan.config.ang_increment = cluster*(2.0*M_PI)/(ares_); scan.config.time_increment = (60.0)/(double)(rate_ * ares_); scan.config.scan_time = (60.0 * (skip + 1))/((double)(rate_)); scan.config.min_range = dmin_ / 1000.0; scan.config.max_range = dmax_ / 1000.0; readData(scan, intensity, timeout); long long inc = (long long)(min_i * scan.config.time_increment * 1000000000); scan.system_time_stamp += inc; scan.self_time_stamp += inc; // printf("Scan took %lli.\n", -scan.system_time_stamp + timeHelper() + offset_); return 0; }
cereal::cereal_port::~cereal_port() { if(portOpen()) close(); }
hokuyo::Laser::~Laser () { if (portOpen()) close(); }
cereal::CerealPort::~CerealPort() { if(portOpen()) close(); }
void cereal::CerealPort::open(const char * port_name, int baud_rate) { if(portOpen()) close(); // Make IO non blocking. This way there are no race conditions that // cause blocking when a badly behaving process does a read at the same // time as us. Will need to switch to blocking for writes or errors // occur just after a replug event. fd_ = ::open(port_name, O_RDWR | O_NONBLOCK | O_NOCTTY); if(fd_ == -1) { const char *extra_msg = ""; switch(errno) { case EACCES: extra_msg = "You probably don't have premission to open the port for reading and writing."; break; case ENOENT: extra_msg = "The requested port does not exist. Is the hokuyo connected? Was the port name misspelled?"; break; } CEREAL_EXCEPT(cereal::Exception, "Failed to open port: %s. %s (errno = %d). %s", port_name, strerror(errno), errno, extra_msg); } try { struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = getpid(); if(fcntl(fd_, F_SETLK, &fl) != 0) CEREAL_EXCEPT(cereal::Exception, "Device %s is already locked. Try 'lsof | grep %s' to find other processes that currently have the port open.", port_name, port_name); // Settings for USB? struct termios newtio; tcgetattr(fd_, &newtio); memset (&newtio.c_cc, 0, sizeof (newtio.c_cc)); newtio.c_cflag = CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; cfsetspeed(&newtio, baud_rate); baud_ = baud_rate; // Activate new settings tcflush(fd_, TCIFLUSH); if(tcsetattr(fd_, TCSANOW, &newtio) < 0) CEREAL_EXCEPT(cereal::Exception, "Unable to set serial port attributes. The port you specified (%s) may not be a serial port.", port_name); /// @todo tcsetattr returns true if at least one attribute was set. Hence, we might not have set everything on success. usleep (200000); } catch(cereal::Exception& e) { // These exceptions mean something failed on open and we should close if(fd_ != -1) ::close(fd_); fd_ = -1; throw e; } }
int hokuyo::Laser::serviceScan(hokuyo::LaserScan& scan, int timeout) { if (!portOpen()) HOKUYO_EXCEPT(hokuyo::Exception, "Port not open."); // Always clear ranges/intensities so we can return easily in case of erro scan.ranges.clear(); scan.intensities.clear(); char buf[100]; bool intensity = false; int min_i; int max_i; int cluster; int skip; int left; char* ind; int status = -1; do { ind = laserReadlineAfter(buf, 100, "M",timeout); scan.system_time_stamp = timeHelper() + offset_; if (ind[0] == 'D') intensity = false; else if (ind[0] == 'E') intensity = true; else continue; ind++; sscanf(ind, "%4d%4d%2d%1d%2d", &min_i, &max_i, &cluster, &skip, &left); laserReadline(buf,100,timeout); buf[4] = 0; if (!checkSum(buf, 4)) HOKUYO_EXCEPT(hokuyo::CorruptedDataException, "Checksum failed on status code: %s", buf); sscanf(buf, "%2d", &status); if (status != 99) return status; } while(status != 99); scan.config.min_angle = (min_i - afrt_) * (2.0*M_PI)/(ares_); scan.config.max_angle = (max_i - afrt_) * (2.0*M_PI)/(ares_); scan.config.ang_increment = cluster*(2.0*M_PI)/(ares_); scan.config.time_increment = (60.0)/(double)(rate_ * ares_); scan.config.scan_time = (60.0 * (skip + 1))/((double)(rate_)); scan.config.min_range = dmin_ / 1000.0; scan.config.max_range = dmax_ / 1000.0; readData(scan, intensity, timeout); long long inc = (long long)(min_i * scan.config.time_increment * 1000000000); scan.system_time_stamp += inc; scan.self_time_stamp += inc; return 0; }