Go to the documentation of this file.
22 #define _WINSOCK_DEPRECATED_NO_WARNINGS
23 #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x600)
25 #define _WIN32_WINNT 0x600 // Minimum: Windows Vista (required to pollfd)
32 #pragma comment(lib, "WS2_32.LIB")
36 #define INVALID_SOCKET (-1)
38 #include <sys/socket.h>
42 #include <sys/types.h>
43 #include <sys/ioctl.h>
45 #include <arpa/inet.h>
46 #include <netinet/in.h>
47 #include <netinet/tcp.h>
53 #if !defined(PCAP_NETMASK_UNKNOWN) // for older pcap versions
54 #define PCAP_NETMASK_UNKNOWN 0xffffffff
72 static bool init =
false;
80 return modelProperties;
89 it != lst.end(); ++it)
100 m_pos_packets_min_period(0.5),
101 m_pos_packets_timing_timeout(30.0),
103 m_return_frames(true),
104 m_pcap_verbose(true),
108 m_pcap_dumper(nullptr),
109 m_pcap_bpf_program(nullptr),
110 m_pcap_file_empty(true),
111 m_pcap_read_once(false),
112 m_pcap_read_fast(false),
113 m_pcap_read_full_scan_delay_ms(100),
114 m_pcap_repeat_delay(0.0),
115 m_hDataSock(INVALID_SOCKET),
116 m_hPositionSock(INVALID_SOCKET),
119 m_lidar_return(UNCHANGED)
129 WORD wVersionRequested = MAKEWORD(2, 0);
131 if (WSAStartup(wVersionRequested, &wsaData))
194 if (lstModels.find(
m_model) == lstModels.end())
198 "Unrecognized `model` parameter: `%u` . Known values are: %s",
199 static_cast<unsigned int>(
m_model),
228 data_pkt_timestamp, rx_pkt, pos_pkt_timestamp, rx_pos_pkt);
239 mrpt::make_aligned_shared<mrpt::obs::CObservationGPS>();
243 gps_obs->originalReceivedTimestamp = pos_pkt_timestamp;
251 gps_obs->has_satellite_timestamp =
false;
252 gps_obs->timestamp = pos_pkt_timestamp;
277 if ((rx_pkt_start_angle <
278 m_rx_scan->scan_packets.rbegin()->blocks[0].rotation) ||
288 std::this_thread::sleep_for(
289 std::chrono::duration<double, std::milli>(
311 if (it != lstModels.end())
313 m_rx_scan->maxRange = it->second.maxRange;
325 m_rx_scan->originalReceivedTimestamp = data_pkt_timestamp;
354 m_rx_scan->has_satellite_timestamp =
true;
358 m_rx_scan->has_satellite_timestamp =
false;
359 m_rx_scan->timestamp = data_pkt_timestamp;
364 m_rx_scan->scan_packets.push_back(rx_pkt);
371 cerr <<
"[CVelodyneScanner::getObservation] Returning false due to "
374 cerr << e.what() << endl;
393 cerr <<
"ERROR receiving data from Velodyne devic!" << endl;
416 "Could not find default calibration data for the given LIDAR "
417 "`model` name. Please, specify a valid `model` or load a valid "
418 "XML configuration file first.");
439 if (INVALID_SOCKET == (
m_hDataSock = socket(PF_INET, SOCK_DGRAM, 0)))
442 "Error creating UDP socket:\n%s",
445 struct sockaddr_in bindAddr;
446 memset(&bindAddr, 0,
sizeof(bindAddr));
447 bindAddr.sin_family = AF_INET;
449 bindAddr.sin_addr.s_addr = INADDR_ANY;
451 if (
int(INVALID_SOCKET) ==
453 m_hDataSock, (
struct sockaddr*)(&bindAddr),
sizeof(sockaddr)))
457 unsigned long non_block_mode = 1;
458 if (ioctlsocket(
m_hDataSock, FIONBIO, &non_block_mode))
460 "Error entering non-blocking mode with ioctlsocket().");
465 oldflags |= O_NONBLOCK | FASYNC;
472 if (INVALID_SOCKET ==
476 "Error creating UDP socket:\n%s",
481 if (
int(INVALID_SOCKET) == ::bind(
483 (
struct sockaddr*)(&bindAddr),
490 "Error entering non-blocking mode with ioctlsocket().");
495 oldflags |= O_NONBLOCK | FASYNC;
503 char errbuf[PCAP_ERRBUF_SIZE];
507 "\n[CVelodyneScanner] Opening PCAP file \"%s\"\n",
518 "(udp dst port %d || udp dst port %d)",
525 "[CVelodyneScanner] Error calling pcap_compile: ";
539 reinterpret_cast<pcap_t*
>(
m_pcap),
541 filter_str.c_str(), 1, PCAP_NETMASK_UNKNOWN) < 0)
542 pcap_perror(
reinterpret_cast<pcap_t*
>(
m_pcap), &sMsgError[0]);
550 "Velodyne: Reading from PCAP requires building MRPT with libpcap "
588 pcap_close(
reinterpret_cast<pcap_t*
>(
m_pcap));
593 pcap_dump_close(
reinterpret_cast<pcap_dumper_t*
>(
m_pcap_dumper));
598 pcap_close(
reinterpret_cast<pcap_t*
>(
m_pcap_out));
607 const uint16_t LidarPacketHeader[21] = {0xffff, 0xffff, 0xffff, 0x7660, 0x0088,
608 0x0000, 0x0008, 0x0045, 0xd204, 0x0000,
609 0x0040, 0x11ff, 0xaab4, 0xa8c0, 0xc801,
613 0xffff, 0x4009, 0x4009, 0xbe04, 0x0000};
614 const uint16_t PositionPacketHeader[21] = {
615 0xffff, 0xffff, 0xffff, 0x7660, 0x0088, 0x0000, 0x0008, 0x0045, 0xd204,
616 0x0000, 0x0040, 0x11ff, 0xaab4, 0xa8c0, 0xc801, 0xffff,
620 0xffff, 0x7420, 0x7420, 0x0802, 0x0000};
623 #if defined(_WIN32) && MRPT_HAS_LIBPCAP
624 int gettimeofday(
struct timeval* tp,
void*)
627 ::GetSystemTimeAsFileTime(&ft);
629 (
static_cast<long long>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
630 t -= 116444736000000000LL;
632 tp->tv_sec =
static_cast<long>(
t / 1000000UL);
633 tp->tv_usec =
static_cast<long>(
t % 1000000UL);
646 CObservationVelodyneScan::POS_PACKET_SIZE);
649 CObservationVelodyneScan::PACKET_SIZE);
655 data_pkt_timestamp, (
uint8_t*)&out_data_pkt, pos_pkt_timestamp,
662 CObservationVelodyneScan::PACKET_SIZE,
m_device_ip);
665 CObservationVelodyneScan::POS_PACKET_SIZE,
m_device_ip);
675 char errbuf[PCAP_ERRBUF_SIZE];
679 string sFilePostfix =
"_";
681 "%04u-%02u-%02u_%02uh%02um%02us", (
unsigned int)parts.
year,
682 (
unsigned int)parts.
month, (
unsigned int)parts.
day,
683 (
unsigned int)parts.
hour, (
unsigned int)parts.
minute,
684 (
unsigned int)parts.
second);
685 const string sFileName =
690 m_pcap_out = pcap_open_dead(DLT_EN10MB, 65535);
692 m_pcap_out !=
nullptr,
"Error creating PCAP live capture handle");
695 "\n[CVelodyneScanner] Writing to PCAP file \"%s\"\n",
698 reinterpret_cast<pcap_t*
>(
m_pcap_out), sFileName.c_str())) ==
702 "Error creating PCAP live dumper: '%s'", errbuf);
706 "Velodyne: Writing PCAP files requires building MRPT with libpcap "
715 struct pcap_pkthdr
header;
716 struct timeval currentTime;
717 gettimeofday(¤tTime,
nullptr);
718 std::vector<unsigned char> packetBuffer;
724 CObservationVelodyneScan::PACKET_SIZE + 42;
725 packetBuffer.resize(
header.caplen);
728 memcpy(&(packetBuffer[0]), LidarPacketHeader, 42);
730 &(packetBuffer[0]) + 42, (
uint8_t*)&out_data_pkt,
731 CObservationVelodyneScan::PACKET_SIZE);
739 CObservationVelodyneScan::POS_PACKET_SIZE + 42;
740 packetBuffer.resize(
header.caplen);
743 memcpy(&(packetBuffer[0]), PositionPacketHeader, 42);
745 &(packetBuffer[0]) + 42, (
uint8_t*)&out_pos_pkt,
746 CObservationVelodyneScan::POS_PACKET_SIZE);
756 #if MRPT_IS_BIG_ENDIAN
760 for (
int i = 0; i < CObservationVelodyneScan::BLOCKS_PER_PACKET; i++)
764 for (
int k = 0; k < CObservationVelodyneScan::SCANS_PER_BLOCK; k++)
802 const size_t expected_packet_size,
const std::string& filter_only_from_IP)
804 if (hSocket == INVALID_SOCKET)
806 "Error: UDP socket is not open yet! Have you called initialize() "
809 unsigned long devip_addr = 0;
810 if (!filter_only_from_IP.empty())
811 devip_addr = inet_addr(filter_only_from_IP.c_str());
815 struct pollfd fds[1];
817 fds[0].events = POLLIN;
818 static const int POLL_TIMEOUT = 1;
820 sockaddr_in sender_address;
821 socklen_t sender_address_len =
sizeof(sender_address);
852 (fds, 1, POLL_TIMEOUT);
858 "Error in UDP poll():\n%s",
865 if ((fds[0].revents & POLLERR) || (fds[0].revents & POLLHUP) ||
866 (fds[0].revents & POLLNVAL))
869 "Error in UDP poll() (seems Velodyne device error?)");
871 }
while ((fds[0].revents & POLLIN) == 0);
875 int nbytes = recvfrom(
876 hSocket, (
char*)&out_buffer[0], expected_packet_size, 0,
877 (sockaddr*)&sender_address, &sender_address_len);
883 else if ((
size_t)nbytes == expected_packet_size)
888 if (!filter_only_from_IP.empty() &&
889 sender_address.sin_addr.s_addr != devip_addr)
896 <<
"[CVelodyneScanner] Warning: incomplete Velodyne packet read: "
897 << nbytes <<
" bytes\n";
917 char errbuf[PCAP_ERRBUF_SIZE];
918 struct pcap_pkthdr*
header;
919 const u_char* pkt_data;
924 if ((
res = pcap_next_ex(
925 reinterpret_cast<pcap_t*
>(
m_pcap), &
header, &pkt_data)) >= 0)
931 if (pcap_offline_filter(
937 <<
"[CVelodyneScanner] DEBUG: Filtering out packet #"
946 ntohs(*
reinterpret_cast<const uint16_t*
>(pkt_data + 0x24));
951 std::cout <<
"[CVelodyneScanner] DEBUG: Packet #"
953 <<
" in PCAP file is POSITION pkt.\n";
955 out_pos_buffer, pkt_data + 42,
956 CObservationVelodyneScan::POS_PACKET_SIZE);
963 std::cout <<
"[CVelodyneScanner] DEBUG: Packet #"
965 <<
" in PCAP file is DATA pkt.\n";
967 out_data_buffer, pkt_data + 42,
968 CObservationVelodyneScan::PACKET_SIZE);
974 std::cerr <<
"[CVelodyneScanner] ERROR: Packet "
976 <<
" in PCAP file passed the filter but does not "
977 "match expected UDP port numbers! Skipping it.\n";
985 "[CVelodyneScanner] Maybe the PCAP file is empty? Error %d "
986 "reading Velodyne packet: `%s`\n",
987 res, pcap_geterr(
reinterpret_cast<pcap_t*
>(
m_pcap)));
995 "[CVelodyneScanner] INFO: end of file reached -- done "
997 std::this_thread::sleep_for(250ms);
1005 "[CVelodyneScanner] INFO: end of file reached -- delaying "
1008 std::this_thread::sleep_for(
1009 std::chrono::duration<double, std::milli>(
1014 printf(
"[CVelodyneScanner] INFO: replaying Velodyne dump file.\n");
1017 pcap_close(
reinterpret_cast<pcap_t*
>(
m_pcap));
1027 "MRPT needs to be built against libpcap to enable this functionality")
1048 strRet =
"Strongest";
1109 !
m_device_ip.empty(),
"A device IP address must be specified first!");
1113 std::vector<uint8_t> post_out;
1114 string post_err_str;
1121 extra_headers[
"Upgrade-Insecure-Requests"] =
"1";
1122 extra_headers[
"Content-Type"] =
"application/x-www-form-urlencoded";
1127 post_err_str, 80 ,
string(),
string(),
1128 &http_rep_code, &extra_headers, &out_headers);
1131 (http_rep_code == 200 || http_rep_code == 204);
mrpt::obs::CObservationVelodyneScan::Ptr m_rx_scan
In progress RX scan.
void * m_pcap_dumper
opaque ptr: "pcap_dumper_t *"
bool m_return_frames
Default: true Output whole frames and not data packets
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)
double 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.
bool loadFromXMLFile(const std::string &velodyne_calibration_xml_filename)
Loads calibration from file, in the format supplied by the manufacturer.
std::map< model_t, TModelProperties > model_properties_list_t
uint16_t header
Block id: UPPER_BANK or LOWER_BANK.
int8_t validity_char
This will be: 'A'=OK or 'V'=void.
mrpt::obs::gnss::Message_NMEA_RMC m_last_gps_rmc
mrpt::system::TTimeStamp getDateAsTimestamp() const
Build an MRPT timestamp with the year/month/day of this observation.
const Scalar * const_iterator
laser_return_t laser_returns[SCANS_PER_BLOCK]
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...
bool getNextObservation(mrpt::obs::CObservationVelodyneScan::Ptr &outScan, mrpt::obs::CObservationGPS::Ptr &outGPS)
Polls the UDP port for incoming data packets.
mrpt::system::TTimeStamp m_last_gps_rmc_age
unsigned __int16 uint16_t
#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...
static short int VELODYNE_POSITION_UDP_PORT
Default: 8308.
mrpt::system::TTimeStamp m_last_pos_packet_timestamp
One unit of data from the scanner (the payload of one UDP DATA packet)
#define INVALID_TIMESTAMP
Represents an invalid timestamp, where applicable.
mrpt::system::TTimeStamp buildTimestampFromParts(const mrpt::system::TTimeParts &p)
Builds a timestamp from the parts (Parts are in UTC)
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)
double second
Minute (0-59)
mrpt::system::TTimeStamp now()
A shortcut for system::getCurrentTime.
std::shared_ptr< T > make_aligned_shared(Args &&... args)
Creates a shared_ptr with aligned memory via aligned_allocator_cpp11<>.
Contains classes for various device interfaces.
ERRORCODE_HTTP http_request(const string &http_method, const string &http_send_content, const string &url, std::vector< uint8_t > &out_content, string &out_errormsg, int port=80, const string &auth_user=string(), const string &auth_pass=string(), int *out_http_responsecode=nullptr, mrpt::system::TParameters< string > *extra_headers=nullptr, mrpt::system::TParameters< string > *out_headers=nullptr, int timeout_ms=1000)
Generic function for HTTP GET & POST methods.
platform_socket_t m_hPositionSock
nv_oem6_header_t header
Novatel frame: NV_OEM6_BESTPOS.
void * m_pcap_bpf_program
opaque ptr: bpf_program*
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.
static std::string getListKnownModels()
Return human-readable string: "`VLP16`,`XXX`,...".
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
bool empty() const
Returns true if no calibration has been loaded yet.
#define THROW_EXCEPTION(msg)
#define ASSERT_(f)
Defines an assertion mechanism.
bool m_pcap_verbose
Default: true Output PCAP Info msgs.
model_t
LIDAR model types.
bool m_pcap_read_fast
(Default: false) If false, will use m_pcap_read_full_scan_delay_ms
This namespace contains representation of robot actions and observations.
bool m_pcap_read_once
Default: false.
void close()
Close the UDP sockets set-up in initialize().
static const model_properties_list_t & get()
Singleton access.
The parts of a date/time (it's like the standard 'tm' but with fractions of seconds).
platform_socket_t m_hDataSock
#define MRPT_COMPILE_TIME_ASSERT(expression)
uint64_t TTimeStamp
A system independent time type, it holds the the number of 100-nanosecond intervals since January 1,...
std::string fileNameStripInvalidChars(const std::string &filename, const char replacement_to_invalid_chars='_')
Replace invalid filename chars by underscores ('_') or any other user-given char.
void 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.
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...
#define MRPT_LOAD_HERE_CONFIG_VAR( variableName, variableType, targetVariable, configFileObject, sectionNameStr)
bool internal_send_http_post(const std::string &post_data)
virtual void initialize()
Tries to initialize the sensor driver, after setting all the parameters with a call to loadConfig.
A C++ interface to Velodyne laser scanners (HDL-64, HDL-32, VLP-16), working on Linux and Windows.
return_type_t m_lidar_return
std::shared_ptr< CObservationVelodyneScan > Ptr
ERRORCODE_HTTP
Possible returns from a HTTP request.
This class allows loading and storing values and vectors of different types from a configuration text...
content_t fields
Message content, accesible by individual fields.
double m_pcap_repeat_delay
Default: 0 (in seconds)
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
For usage when passing a dynamic number of (numeric) arguments to a function, by name.
mrpt::obs::VelodyneCalibration m_velodyne_calib
Device calibration file (supplied by vendor in an XML file)
void setFramePublishing(bool on)
Switches whole frame (points in a single revolution) on/off publication to data packet publication.
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
std::string m_pcap_output_file
Default: "" (do not dump to an offline file)
void reverseBytesInPlace(bool &v_in_out)
Reverse the order of the bytes of a given type (useful for transforming btw little/big endian)
uint32_t gps_timestamp
us from top of hour
raw_block_t blocks[BLOCKS_PER_PACKET]
void * m_pcap_out
opaque ptr: "pcap_t*"
static short int VELODYNE_DATA_UDP_PORT
Default: 2368.
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*"
std::shared_ptr< CObservationGPS > Ptr
double m_pos_packets_min_period
Default: 0.5 seconds.
void appendObservation(const mrpt::serialization::CSerializable::Ptr &obj)
Like appendObservations() but for just one observation.
double m_pos_packets_timing_timeout
Default: 30 seconds.
bool setLidarOnOff(bool on)
Switches the LASER on/off (saves energy when not measuring) (via HTTP post interface).
std::string m_sensorLabel
See CGenericSensor.
bool setLidarReturnType(return_type_t ret_type)
Changes among STRONGEST, LAST, DUAL return types (via HTTP post interface).
virtual ~CVelodyneScanner()
unsigned int m_pcap_read_count
number of pkts read from the file so far (for debugging)
float read_float(const std::string §ion, const std::string &name, float defaultValue, bool failIfNotFound=false) const
std::string m_pcap_input_file
Default: "" (do not operate from an offline file)
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...
char NMEA_GPRMC[72+234]
the full $GPRMC message, as received by Velodyne, terminated with "\r\n\0"
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism.
#define IMPLEMENTS_GENERIC_SENSOR(class_name, NameSpace)
This must be inserted in all CGenericSensor classes implementation files:
std::string getLastSocketErrorStr()
Returns a description of the last Sockets error.
std::string m_device_ip
Default: "" (no IP-based filtering)
Payload of one POSITION packet.
int fprintf(FILE *fil, const char *format,...) noexcept MRPT_printf_format_check(2
An OS-independent version of fprintf.
void loadConfig_sensorSpecific(const mrpt::config::CConfigFileBase &configSource, const std::string §ion)
See the class documentation at the top for expected parameters.
uint32_t platform_socket_t
Handles for the UDP sockets, or INVALID_SOCKET (-1)
return_type_t
LIDAR return type.
uint16_t rotation
0-35999, divide by 100 to get degrees
model_t m_model
Default: "VLP16".
bool loadCalibrationFile(const std::string &velodyne_xml_calib_file_path)
Returns false on error.
uint8_t minute
Hour (0-23)
void doProcess()
This method will be invoked at a minimum rate of "process_rate" (Hz)
GLsizei const GLchar ** string
UTC_time UTCTime
The GPS sensor measured timestamp (in UTC time)
mrpt::poses::CPose3D m_sensorPose
A set of useful routines for networking.
bool setLidarRPM(int rpm)
Changes Lidar RPM (valid range: 300-600) (via HTTP post interface).
A CObservation-derived class for RAW DATA (and optionally, point cloud) of scans from 3D Velodyne LID...
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
double DEG2RAD(const double x)
Degrees to radians.
Page generated by Doxygen 1.8.17 for MRPT 1.9.9 Git: ad3a9d8ae Tue May 1 23:10:22 2018 -0700 at miƩ 12 jul 2023 10:03:34 CEST | |