20 #ifdef MRPT_OS_WINDOWS 21 #define _WINSOCK_DEPRECATED_NO_WARNINGS 22 #if defined(_WIN32_WINNT) && (_WIN32_WINNT<0x600) 24 #define _WIN32_WINNT 0x600 // Minimum: Windows Vista (required to pollfd) 28 typedef int socklen_t;
30 # if defined(__BORLANDC__) || defined(_MSC_VER) 31 # pragma comment (lib,"WS2_32.LIB") 35 #define INVALID_SOCKET (-1) 37 #include <sys/socket.h> 41 #include <sys/types.h> 42 #include <sys/ioctl.h> 44 #include <arpa/inet.h> 45 #include <netinet/in.h> 46 #include <netinet/tcp.h> 52 # if !defined(PCAP_NETMASK_UNKNOWN) // for older pcap versions 53 # define PCAP_NETMASK_UNKNOWN 0xffffffff 70 static bool init =
false;
77 return modelProperties;
91 m_pos_packets_min_period(0.5),
92 m_pos_packets_timing_timeout(30.0),
99 m_pcap_bpf_program(NULL),
100 m_pcap_file_empty(true),
101 m_pcap_read_once(false),
102 m_pcap_read_fast(false),
103 m_pcap_read_full_scan_delay_ms(100),
104 m_pcap_repeat_delay(0.0),
109 m_lidar_return(UNCHANGED)
117 #ifdef MRPT_OS_WINDOWS 119 WORD wVersionRequested = MAKEWORD( 2, 0 );
121 if (WSAStartup( wVersionRequested, &wsaData ) )
129 #ifdef MRPT_OS_WINDOWS 174 if (!calibration_file.empty())
179 if (lstModels.find(
m_model)==lstModels.end()) {
181 static_cast<unsigned int>(
m_model),
193 mrpt::obs::CObservationVelodyneScanPtr & outScan,
194 mrpt::obs::CObservationGPSPtr & outGPS
202 outScan = mrpt::obs::CObservationVelodyneScanPtr();
203 outGPS = mrpt::obs::CObservationGPSPtr();
209 bool rx_all_ok = this->
receivePackets(data_pkt_timestamp,rx_pkt, pos_pkt_timestamp,rx_pos_pkt);
222 gps_obs->originalReceivedTimestamp = pos_pkt_timestamp;
228 gps_obs->has_satellite_timestamp =
false;
229 gps_obs->timestamp = pos_pkt_timestamp;
251 if (rx_pkt_start_angle < m_rx_scan->scan_packets.rbegin()->blocks[0].rotation )
274 if (it!=lstModels.end())
276 m_rx_scan->maxRange = it->second.maxRange;
288 m_rx_scan->originalReceivedTimestamp = data_pkt_timestamp;
305 m_rx_scan->has_satellite_timestamp =
true;
309 m_rx_scan->has_satellite_timestamp =
false;
310 m_rx_scan->timestamp = data_pkt_timestamp;
315 m_rx_scan->scan_packets.push_back(rx_pkt);
322 cerr <<
"[CVelodyneScanner::getObservation] Returning false due to exception: " << endl;
323 cerr << e.what() << endl;
330 CObservationVelodyneScanPtr obs;
331 CObservationGPSPtr obs_gps;
342 cerr <<
"ERROR receiving data from Velodyne devic!" << endl;
359 THROW_EXCEPTION(
"Could not find default calibration data for the given LIDAR `model` name. Please, specify a valid `model` or load a valid XML configuration file first.");
381 struct sockaddr_in bindAddr;
382 memset(&bindAddr,0,
sizeof(bindAddr));
383 bindAddr.sin_family = AF_INET;
385 bindAddr.sin_addr.s_addr = INADDR_ANY;
390 #ifdef MRPT_OS_WINDOWS 391 unsigned long non_block_mode = 1;
392 if (ioctlsocket(
m_hDataSock, FIONBIO, &non_block_mode) )
THROW_EXCEPTION(
"Error entering non-blocking mode with ioctlsocket()." );
395 if (oldflags == -1)
THROW_EXCEPTION(
"Error retrieving fcntl() of socket." );
396 oldflags |= O_NONBLOCK | FASYNC;
410 #ifdef MRPT_OS_WINDOWS 414 if (oldflags == -1)
THROW_EXCEPTION(
"Error retrieving fcntl() of socket." );
415 oldflags |= O_NONBLOCK | FASYNC;
422 char errbuf[PCAP_ERRBUF_SIZE];
438 static std::string sMsgError =
"[CVelodyneScanner] Error calling pcap_compile: ";
439 if (pcap_compile( reinterpret_cast<pcap_t*>(
m_pcap), reinterpret_cast<bpf_program*>(
m_pcap_bpf_program), filter_str.c_str(), 1, PCAP_NETMASK_UNKNOWN) <0)
440 pcap_perror(reinterpret_cast<pcap_t*>(
m_pcap), &sMsgError[0] );
447 THROW_EXCEPTION(
"Velodyne: Reading from PCAP requires building MRPT with libpcap support!");
463 #ifdef MRPT_OS_WINDOWS 474 #ifdef MRPT_OS_WINDOWS 483 pcap_close( reinterpret_cast<pcap_t*>(
m_pcap) );
487 pcap_dump_close(reinterpret_cast<pcap_dumper_t*>(
m_pcap_dumper));
491 pcap_close( reinterpret_cast<pcap_t*>(
m_pcap_out) );
500 const uint16_t LidarPacketHeader[21] = {
501 0xffff, 0xffff, 0xffff, 0x7660,
502 0x0088, 0x0000, 0x0008, 0x0045,
503 0xd204, 0x0000, 0x0040, 0x11ff,
504 0xaab4, 0xa8c0, 0xc801, 0xffff,
505 0xffff, 0x4009, 0x4009, 0xbe04, 0x0000};
506 const uint16_t PositionPacketHeader[21] = {
507 0xffff, 0xffff, 0xffff, 0x7660,
508 0x0088, 0x0000, 0x0008, 0x0045,
509 0xd204, 0x0000, 0x0040, 0x11ff,
510 0xaab4, 0xa8c0, 0xc801, 0xffff,
511 0xffff, 0x7420, 0x7420, 0x0802, 0x0000};
514 #if defined(MRPT_OS_WINDOWS) && MRPT_HAS_LIBPCAP 515 int gettimeofday(
struct timeval * tp,
void *)
518 ::GetSystemTimeAsFileTime( &ft );
519 long long t = (
static_cast<long long>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
520 t -= 116444736000000000LL;
522 tp->tv_sec =
static_cast<long>(
t / 1000000UL);
523 tp->tv_usec =
static_cast<long>(
t % 1000000UL);
542 data_pkt_timestamp, (
uint8_t*)&out_data_pkt,
543 pos_pkt_timestamp, (
uint8_t*)&out_pos_pkt);
557 char errbuf[PCAP_ERRBUF_SIZE];
561 string sFilePostfix =
"_";
562 sFilePostfix +=
format(
"%04u-%02u-%02u_%02uh%02um%02us",(
unsigned int)parts.
year, (
unsigned int)parts.
month, (
unsigned int)parts.
day, (
unsigned int)parts.
hour, (
unsigned int)parts.
minute, (
unsigned int)parts.
second );
565 m_pcap_out = pcap_open_dead(DLT_EN10MB, 65535);
568 printf(
"\n[CVelodyneScanner] Writing to PCAP file \"%s\"\n", sFileName.c_str());
573 THROW_EXCEPTION(
"Velodyne: Writing PCAP files requires building MRPT with libpcap support!");
580 struct pcap_pkthdr
header;
581 struct timeval currentTime;
582 gettimeofday(¤tTime, NULL);
583 std::vector<unsigned char> packetBuffer;
588 header.caplen =
header.len = CObservationVelodyneScan::PACKET_SIZE+42;
589 packetBuffer.resize(
header.caplen);
592 memcpy(&(packetBuffer[0]), LidarPacketHeader, 42);
593 memcpy(&(packetBuffer[0]) + 42, (
uint8_t*)&out_data_pkt, CObservationVelodyneScan::PACKET_SIZE);
594 pcap_dump((u_char*)this->
m_pcap_dumper, &header, &(packetBuffer[0]));
599 header.caplen =
header.len = CObservationVelodyneScan::POS_PACKET_SIZE+42;
600 packetBuffer.resize(
header.caplen);
603 memcpy(&(packetBuffer[0]), PositionPacketHeader, 42);
604 memcpy(&(packetBuffer[0]) + 42, (
uint8_t*)&out_pos_pkt, CObservationVelodyneScan::POS_PACKET_SIZE);
605 pcap_dump((u_char*)this->
m_pcap_dumper, &header, &(packetBuffer[0]));
612 #if MRPT_IS_BIG_ENDIAN 616 for (
int i=0;i<CObservationVelodyneScan::BLOCKS_PER_PACKET;i++)
620 for (
int k=0;k<CObservationVelodyneScan::SCANS_PER_BLOCK;k++) {
653 const size_t expected_packet_size,
657 THROW_EXCEPTION(
"Error: UDP socket is not open yet! Have you called initialize() first?");
659 unsigned long devip_addr = 0;
660 if (!filter_only_from_IP.empty())
661 devip_addr = inet_addr(filter_only_from_IP.c_str());
665 struct pollfd fds[1];
667 fds[0].events = POLLIN;
668 static const int POLL_TIMEOUT = 1;
670 sockaddr_in sender_address;
671 socklen_t sender_address_len =
sizeof(sender_address);
696 #if !defined(MRPT_OS_WINDOWS) 701 (fds, 1, POLL_TIMEOUT);
711 if ((fds[0].revents & POLLERR)
712 || (fds[0].revents & POLLHUP)
713 || (fds[0].revents & POLLNVAL))
715 THROW_EXCEPTION(
"Error in UDP poll() (seems Velodyne device error?)");
717 }
while ((fds[0].revents & POLLIN) == 0);
721 int nbytes = recvfrom(hSocket, (
char*)&out_buffer[0],
722 expected_packet_size, 0,
723 (sockaddr*) &sender_address, &sender_address_len);
727 if (errno != EWOULDBLOCK)
730 else if ((
size_t) nbytes == expected_packet_size)
735 if( !filter_only_from_IP.empty() && sender_address.sin_addr.s_addr != devip_addr )
741 std::cerr <<
"[CVelodyneScanner] Warning: incomplete Velodyne packet read: " << nbytes <<
" bytes\n";
762 char errbuf[PCAP_ERRBUF_SIZE];
763 struct pcap_pkthdr *
header;
764 const u_char *pkt_data;
769 if ((
res = pcap_next_ex(reinterpret_cast<pcap_t*>(
m_pcap), &
header, &pkt_data)) >= 0)
783 const uint16_t udp_dst_port = ntohs( *reinterpret_cast<const uint16_t *>(pkt_data + 0x24) );
787 memcpy(out_pos_buffer, pkt_data+42, CObservationVelodyneScan::POS_PACKET_SIZE);
793 memcpy(out_data_buffer, pkt_data+42, CObservationVelodyneScan::PACKET_SIZE);
798 std::cerr <<
"[CVelodyneScanner] ERROR: Packet "<<
m_pcap_read_count <<
" in PCAP file passed the filter but does not match expected UDP port numbers! Skipping it.\n";
804 fprintf(stderr,
"[CVelodyneScanner] Maybe the PCAP file is empty? Error %d reading Velodyne packet: `%s`\n",
res, pcap_geterr(reinterpret_cast<pcap_t*>(
m_pcap) ));
810 if (
m_pcap_verbose) printf(
"[CVelodyneScanner] INFO: end of file reached -- done reading.\n");
821 if (
m_pcap_verbose) printf(
"[CVelodyneScanner] INFO: replaying Velodyne dump file.\n");
824 pcap_close( reinterpret_cast<pcap_t*>(
m_pcap) );
831 THROW_EXCEPTION(
"MRPT needs to be built against libpcap to enable this functionality")
851 case STRONGEST: strRet =
"Strongest";
break;
852 case DUAL: strRet =
"Dual";
break;
853 case LAST: strRet =
"Last";
break;
905 extra_headers[
"Upgrade-Insecure-Requests"] =
"1";
906 extra_headers[
"Content-Type"] =
"application/x-www-form-urlencoded";
uint64_t TTimeStamp
A system independent time type, it holds the the number of 100-nanosecond intervals since January 1...
void BASE_IMPEXP memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) MRPT_NO_THROWS
An OS and compiler independent version of "memcpy".
std::map< model_t, TModelProperties > model_properties_list_t
ERRORCODE_HTTP
Possible returns from a HTTP request.
void BASE_IMPEXP timestampToParts(TTimeStamp t, TTimeParts &p, bool localTime=false)
Gets the individual parts of a date/time (days, hours, minutes, seconds) - UTC time or local time...
content_t fields
Message content, accesible by individual fields.
bool loadFromXMLFile(const std::string &velodyne_calibration_xml_filename)
Loads calibration from file, in the format supplied by the manufacturer.
unsigned __int16 uint16_t
For usage when passing a dynamic number of (numeric) arguments to a function, by name.
A C++ interface to Velodyne laser scanners (HDL-64, HDL-32, VLP-16), working on Linux and Windows...
mrpt::system::TTimeStamp getAsTimestamp(const mrpt::system::TTimeStamp &date) const
Build an MRPT timestamp with the hour/minute/sec of this structure and the date from the given timest...
static short int VELODYNE_POSITION_UDP_PORT
Default: 8308. Change it if required.
std::vector< uint8_t > vector_byte
raw_block_t blocks[BLOCKS_PER_PACKET]
double DEG2RAD(const double x)
Degrees to radians.
void BASE_IMPEXP reverseBytesInPlace(bool &v_in_out)
Reverse the order of the bytes of a given type (useful for transforming btw little/big endian) ...
int platform_socket_t
Handles for the UDP sockets, or INVALID_SOCKET (-1)
float read_float(const std::string §ion, const std::string &name, float defaultValue, bool failIfNotFound=false) const
platform_socket_t m_hPositionSock
uint32_t gps_timestamp
us from top of hour
std::string m_sensorLabel
See CGenericSensor.
#define THROW_EXCEPTION(msg)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
bool internal_read_PCAP_packet(mrpt::system::TTimeStamp &data_pkt_time, uint8_t *out_data_buffer, mrpt::system::TTimeStamp &pos_pkt_time, uint8_t *out_pos_buffer)
mrpt::system::TTimeStamp BASE_IMPEXP buildTimestampFromParts(const mrpt::system::TTimeParts &p)
Builds a timestamp from the parts (Parts are in UTC)
static std::string getListKnownModels()
Return human-readable string: "`VLP16`,`XXX`,...".
void close()
Close the UDP sockets set-up in initialize().
bool m_pcap_read_once
Default: false.
mrpt::system::TTimeStamp now()
A shortcut for system::getCurrentTime.
Contains classes for various device interfaces.
void * m_pcap_bpf_program
opaque ptr: bpf_program*
int BASE_IMPEXP fprintf(FILE *fil, const char *format,...) MRPT_NO_THROWS MRPT_printf_format_check(2
An OS-independent version of fprintf.
std::string BASE_IMPEXP fileNameStripInvalidChars(const std::string &filename, const char replacement_to_invalid_chars='_')
Replace invalid filename chars by underscores ('_') or any other user-given char. ...
const Scalar * const_iterator
static CObservationGPSPtr Create()
model_t
LIDAR model types.
int8_t validity_char
This will be: 'A'=OK or 'V'=void.
bool m_pcap_read_fast
(Default: false) If false, will use m_pcap_read_full_scan_delay_ms
void loadConfig_sensorSpecific(const mrpt::utils::CConfigFileBase &configSource, const std::string §ion)
See the class documentation at the top for expected parameters.
UTC_time UTCTime
The GPS sensor measured timestamp (in UTC time)
mrpt::system::TTimeStamp m_last_pos_packet_timestamp
char NMEA_GPRMC[72+234]
the full $GPRMC message, as received by Velodyne, terminated with "\r\n\0"
This class allows loading and storing values and vectors of different types from a configuration text...
double m_pcap_repeat_delay
Default: 0 (in seconds)
mrpt::obs::VelodyneCalibration m_velodyne_calib
Device calibration file (supplied by vendor in an XML file)
virtual void initialize()
Tries to initialize the sensor driver, after setting all the parameters with a call to loadConfig...
double m_pos_packets_min_period
Default: 0.5 seconds.
return_type_t m_lidar_return
bool setLidarOnOff(bool on)
Switches the LASER on/off (saves energy when not measuring) (via HTTP post interface).
A helper class that can convert an enum value into its textual representation, and viceversa...
void BASE_IMPEXP sleep(int time_ms) MRPT_NO_THROWS
An OS-independent method for sending the current thread to "sleep" for a given period of time...
nv_oem6_header_t header
Novatel frame: NV_OEM6_BESTPOS.
bool receivePackets(mrpt::system::TTimeStamp &data_pkt_timestamp, mrpt::obs::CObservationVelodyneScan::TVelodyneRawPacket &out_data_pkt, mrpt::system::TTimeStamp &pos_pkt_timestamp, mrpt::obs::CObservationVelodyneScan::TVelodynePositionPacket &out_pos_pkt)
Users normally would prefer calling getNextObservation() instead.
The parts of a date/time (it's like the standard 'tm' but with fractions of seconds).
std::string BASE_IMPEXP getLastSocketErrorStr()
Returns a description of the last Sockets error.
static CObservationVelodyneScanPtr Create()
virtual ~CVelodyneScanner()
unsigned int m_pcap_read_count
number of pkts read from the file so far (for debugging)
std::string m_pcap_output_file
Default: "" (do not dump to an offline file)
static const model_properties_list_t & get()
Singleton access.
This namespace contains representation of robot actions and observations.
A set of useful routines for networking.
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
bool m_pcap_verbose
Default: true Output PCAP Info msgs.
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
platform_socket_t m_hDataSock
bool setLidarReturnType(return_type_t ret_type)
Changes among STRONGEST, LAST, DUAL return types (via HTTP post interface).
GLsizei const GLchar ** string
uint16_t header
Block id: UPPER_BANK or LOWER_BANK.
std::string m_pcap_input_file
Default: "" (do not operate from an offline file)
#define IMPLEMENTS_GENERIC_SENSOR(class_name, NameSpace)
This must be inserted in all CGenericSensor classes implementation files:
static bool parse_NMEA(const std::string &cmd_line, mrpt::obs::CObservationGPS &out_obs, const bool verbose=false)
Parses one line of NMEA data from a GPS receiver, and writes the recognized fields (if any) into an o...
ENUMTYPE read_enum(const std::string §ion, const std::string &name, const ENUMTYPE &defaultValue, bool failIfNotFound=false) const
Reads an "enum" value, where the value in the config file can be either a numerical value or the symb...
#define INVALID_TIMESTAMP
Represents an invalid timestamp, where applicable.
Payload of one POSITION packet.
double second
Minute (0-59)
#define MRPT_COMPILE_TIME_ASSERT(f)
void * m_pcap_out
opaque ptr: "pcap_t*"
bool internal_send_http_post(const std::string &post_data)
mrpt::system::TTimeStamp getDateAsTimestamp() const
Build an MRPT timestamp with the year/month/day of this observation.
#define MRPT_LOAD_CONFIG_VAR(variableName, variableType, configFileObject, sectionNameStr)
An useful macro for loading variables stored in a INI-like file under a key with the same name that t...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
double m_pos_packets_timing_timeout
Default: 30 seconds.
laser_return_t laser_returns[SCANS_PER_BLOCK]
uint8_t minute
Hour (0-23)
#define MRPT_LOAD_HERE_CONFIG_VAR(variableName, variableType, targetVariable, configFileObject, sectionNameStr)
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
One unit of data from the scanner (the payload of one UDP DATA packet)
bool getNextObservation(mrpt::obs::CObservationVelodyneScanPtr &outScan, mrpt::obs::CObservationGPSPtr &outGPS)
Polls the UDP port for incoming data packets.
bool empty() const
Returns true if no calibration has been loaded yet.
static short int VELODYNE_DATA_UDP_PORT
Default: 2368. Change it if required.
double m_pcap_read_full_scan_delay_ms
(Default:100 ms) delay after each full scan read from a PCAP log
void * m_pcap
opaque ptr: "pcap_t*"
ERRORCODE_HTTP BASE_IMPEXP http_request(const string &http_method, const string &http_send_content, const string &url, vector_byte &out_content, string &out_errormsg, int port=80, const string &auth_user=string(), const string &auth_pass=string(), int *out_http_responsecode=NULL, mrpt::utils::TParameters< string > *extra_headers=NULL, mrpt::utils::TParameters< string > *out_headers=NULL, int timeout_ms=1000)
Generic function for HTTP GET & POST methods.
void doProcess()
This method will be invoked at a minimum rate of "process_rate" (Hz)
void appendObservation(const mrpt::utils::CSerializablePtr &obj)
Like appendObservations() but for just one observation.
uint16_t rotation
0-35999, divide by 100 to get degrees
double BASE_IMPEXP timeDifference(const mrpt::system::TTimeStamp t_first, const mrpt::system::TTimeStamp t_later)
Returns the time difference from t1 to t2 (positive if t2 is posterior to t1), in seconds...
void * m_pcap_dumper
opaque ptr: "pcap_dumper_t *"
std::string m_device_ip
Default: "" (no IP-based filtering)
mrpt::obs::CObservationVelodyneScanPtr m_rx_scan
In progress RX scan.
bool loadCalibrationFile(const std::string &velodyne_xml_calib_file_path)
Returns false on error.
#define ASSERTMSG_(f, __ERROR_MSG)
return_type_t
LIDAR return type.
mrpt::poses::CPose3D m_sensorPose
mrpt::system::TTimeStamp m_last_gps_rmc_age
static mrpt::system::TTimeStamp internal_receive_UDP_packet(platform_socket_t hSocket, uint8_t *out_buffer, const size_t expected_packet_size, const std::string &filter_only_from_IP)
model_t m_model
Default: "VLP16".
mrpt::obs::gnss::Message_NMEA_RMC m_last_gps_rmc
bool setLidarRPM(int rpm)
Changes Lidar RPM (valid range: 300-600) (via HTTP post interface).