File bpearl_v3.hpp
File List > decoders > bpearl_v3.hpp
Go to the documentation of this file
// Copyright 2024 TIER IV, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "nebula_decoders/nebula_decoders_robosense/decoders/robosense_packet.hpp"
#include "nebula_decoders/nebula_decoders_robosense/decoders/robosense_sensor.hpp"
#include "boost/endian/buffers.hpp"
#include <bitset>
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory>
#include <string>
using namespace boost::endian; // NOLINT(build/namespaces)
namespace nebula::drivers
{
namespace robosense_packet
{
namespace bpearl_v3
{
#pragma pack(push, 1)
struct Timestamp
{
big_uint8_buf_t year;
big_uint8_buf_t month;
big_uint8_buf_t day;
big_uint8_buf_t hour;
big_uint8_buf_t minute;
big_uint8_buf_t second;
big_uint16_buf_t millisecond;
big_uint16_buf_t microsecond;
[[nodiscard]] uint64_t get_time_in_ns() const
{
std::tm tm{};
tm.tm_year = year.value() + 100;
tm.tm_mon = month.value() - 1; // starts from 0 in C
tm.tm_mday = day.value();
tm.tm_hour = hour.value();
tm.tm_min = minute.value();
tm.tm_sec = second.value();
const uint64_t time = timegm(&tm) * 1000000000ULL + millisecond.value() * 1000000ULL +
microsecond.value() * 1000ULL;
return time;
}
};
struct Header
{
big_uint64_buf_t header_id;
big_uint32_buf_t checksum;
big_uint32_buf_t packet_count;
big_uint32_buf_t reserved_first;
Timestamp timestamp;
big_uint8_buf_t lidar_model;
uint8_t reserved_second[7];
big_uint16_buf_t temperature;
big_uint16_buf_t top_board_temperature;
};
struct Packet : public PacketBase<12, 32, 2, 100>
{
typedef Body<Block<Unit, Packet::n_channels>, Packet::n_blocks> body_t;
Header header;
body_t body;
big_uint48_buf_t tail;
};
struct OperatingStatus
{
big_uint48_buf_t reserved;
big_uint16_buf_t v_dat_0v5;
big_uint16_buf_t v_dat_12v;
big_uint16_buf_t v_dat_5v;
big_uint16_buf_t v_dat_1v25;
big_uint16_buf_t v_dat_0v;
big_uint16_buf_t v_dat_1v;
};
struct FaultDiagnosis
{
uint8_t reserved_first[11];
big_uint16_buf_t manc_err1;
big_uint16_buf_t manc_err2;
big_uint8_buf_t gps_st;
big_uint8_buf_t temperature1;
big_uint8_buf_t temperature2;
uint8_t reserved_second[2];
big_uint8_buf_t temperature3;
big_uint8_buf_t temperature4;
big_uint8_buf_t temperature5;
big_uint8_buf_t temperature6;
uint8_t reserved_third[7];
big_uint8_buf_t r_rpm1;
big_uint8_buf_t r_rpm2;
uint8_t reserved_fourth[7];
};
struct InfoPacket
{
big_uint64_buf_t header;
big_uint16_buf_t motor_speed;
Ethernet ethernet;
FovSetting fov_setting;
big_uint16_buf_t tcp_msop_port;
big_uint16_buf_t phase_lock;
FirmwareVersion top_firmware_version;
FirmwareVersion bottom_firmware_version;
FirmwareVersion bottom_software_version;
FirmwareVersion motor_firmware_version;
uint8_t reserved_first[230];
big_uint16_buf_t reverse_zero_angle_offset;
SerialNumber serial_number;
big_uint16_buf_t zero_angle_offset;
big_uint8_buf_t return_mode;
big_uint8_buf_t time_sync_mode;
big_uint8_buf_t sync_status;
Timestamp time;
OperatingStatus operating_status;
uint8_t reserved_second[6];
big_uint8_buf_t rotation_direction;
big_uint32_buf_t elapsed_time_flag;
FaultDiagnosis fault_diagnosis;
big_uint8_buf_t gprmc[86];
SensorCalibration sensor_calibration;
uint8_t reserved_fourth[586];
big_uint16_buf_t tail;
};
#pragma pack(pop)
} // namespace bpearl_v3
template <>
inline double get_dis_unit<bpearl_v3::Packet>(const bpearl_v3::Packet & /* packet */)
{
return 0.005;
}
} // namespace robosense_packet
class BpearlV3 : public RobosenseSensor<
robosense_packet::bpearl_v3::Packet, robosense_packet::bpearl_v3::InfoPacket>
{
private:
static constexpr int firing_time_offset_ns_single[12][32]{
{0, 256, 512, 768, 1024, 1280, 1536, 1792, 2568, 2824, 3080, 3336, 3592, 3848, 4104, 4360,
128, 384, 640, 896, 1152, 1408, 1664, 1920, 2696, 2952, 3208, 3464, 3720, 3976, 4232, 4488},
{5552, 5808, 6064, 6320, 6576, 6832, 7088, 7344, 8120, 8376, 8632,
8888, 9144, 9400, 9656, 9912, 5680, 5936, 6192, 6448, 6704, 6960,
7216, 7472, 8248, 8504, 8760, 9016, 9272, 9528, 9784, 10040},
{11104, 11360, 11616, 11872, 12128, 12384, 12640, 12896, 13672, 13928, 14184,
14440, 14696, 14952, 15208, 15464, 11232, 11488, 11744, 12000, 12256, 12512,
12768, 13024, 13800, 14056, 14312, 14568, 14824, 15080, 15336, 15592},
{16656, 16912, 17168, 17424, 17680, 17936, 18192, 18448, 19224, 19480, 19736,
19992, 20248, 20504, 20760, 21016, 16784, 17040, 17296, 17552, 17808, 18064,
18320, 18576, 19352, 19608, 19864, 20120, 20376, 20632, 20888, 21144},
{22208, 22464, 22720, 22976, 23232, 23488, 23744, 24000, 24776, 25032, 25288,
25544, 25800, 26056, 26312, 26568, 22336, 22592, 22848, 23104, 23360, 23616,
23872, 24128, 24904, 25160, 25416, 25672, 25928, 26184, 26440, 26696},
{27760, 28016, 28272, 28528, 28784, 29040, 29296, 29552, 30328, 30584, 30840,
31096, 31352, 31608, 31864, 32120, 27888, 28144, 28400, 28656, 28912, 29168,
29424, 29680, 30456, 30712, 30968, 31224, 31480, 31736, 31992, 32248},
{33312, 33568, 33824, 34080, 34336, 34592, 34848, 35104, 35880, 36136, 36392,
36648, 36904, 37160, 37416, 37672, 33440, 33696, 33952, 34208, 34464, 34720,
34976, 35232, 36008, 36264, 36520, 36776, 37032, 37288, 37544, 37800},
{38864, 39120, 39376, 39632, 39888, 40144, 40400, 40656, 41432, 41688, 41944,
42200, 42456, 42712, 42968, 43224, 38992, 39248, 39504, 39760, 40016, 40272,
40528, 40784, 41560, 41816, 42072, 42328, 42584, 42840, 43096, 43352},
{44416, 44672, 44928, 45184, 45440, 45696, 45952, 46208, 46984, 47240, 47496,
47752, 48008, 48264, 48520, 48776, 44544, 44800, 45056, 45312, 45568, 45824,
46080, 46336, 47112, 47368, 47624, 47880, 48136, 48392, 48648, 48904},
{49968, 50224, 50480, 50736, 50992, 51248, 51504, 51760, 52536, 52792, 53048,
53304, 53560, 53816, 54072, 54328, 50096, 50352, 50608, 50864, 51120, 51376,
51632, 51888, 52664, 52920, 53176, 53432, 53688, 53944, 54200, 54456},
{55520, 55776, 56032, 56288, 56544, 56800, 57056, 57312, 58088, 58344, 58600,
58856, 59112, 59368, 59624, 59880, 55648, 55904, 56160, 56416, 56672, 56928,
57184, 57440, 58216, 58472, 58728, 58984, 59240, 59496, 59752, 60008},
{61072, 61328, 61584, 61840, 62096, 62352, 62608, 62864, 63640, 63896, 64152,
64408, 64664, 64920, 65176, 65432, 61200, 61456, 61712, 61968, 62224, 62480,
62736, 62992, 63768, 64024, 64280, 64536, 64792, 65048, 65304, 65560}};
static constexpr int firing_time_offset_ns_dual[12][32]{
{0, 256, 512, 768, 1024, 1280, 1536, 1792, 2568, 2824, 3080, 3336, 3592, 3848, 4104, 4360,
128, 384, 640, 896, 1152, 1408, 1664, 1920, 2696, 2952, 3208, 3464, 3720, 3976, 4232, 4488},
{0, 256, 512, 768, 1024, 1280, 1536, 1792, 2568, 2824, 3080, 3336, 3592, 3848, 4104, 4360,
128, 384, 640, 896, 1152, 1408, 1664, 1920, 2696, 2952, 3208, 3464, 3720, 3976, 4232, 4488},
{5552, 5808, 6064, 6320, 6576, 6832, 7088, 7344, 8120, 8376, 8632,
8888, 9144, 9400, 9656, 9912, 5680, 5936, 6192, 6448, 6704, 6960,
7216, 7472, 8248, 8504, 8760, 9016, 9272, 9528, 9784, 10040},
{5552, 5808, 6064, 6320, 6576, 6832, 7088, 7344, 8120, 8376, 8632,
8888, 9144, 9400, 9656, 9912, 5680, 5936, 6192, 6448, 6704, 6960,
7216, 7472, 8248, 8504, 8760, 9016, 9272, 9528, 9784, 10040},
{11104, 11360, 11616, 11872, 12128, 12384, 12640, 12896, 13672, 13928, 14184,
14440, 14696, 14952, 15208, 15464, 11232, 11488, 11744, 12000, 12256, 12512,
12768, 13024, 13800, 14056, 14312, 14568, 14824, 15080, 15336, 15592},
{11104, 11360, 11616, 11872, 12128, 12384, 12640, 12896, 13672, 13928, 14184,
14440, 14696, 14952, 15208, 15464, 11232, 11488, 11744, 12000, 12256, 12512,
12768, 13024, 13800, 14056, 14312, 14568, 14824, 15080, 15336, 15592},
{16656, 16912, 17168, 17424, 17680, 17936, 18192, 18448, 19224, 19480, 19736,
19992, 20248, 20504, 20760, 21016, 16784, 17040, 17296, 17552, 17808, 18064,
18320, 18576, 19352, 19608, 19864, 20120, 20376, 20632, 20888, 21144},
{16656, 16912, 17168, 17424, 17680, 17936, 18192, 18448, 19224, 19480, 19736,
19992, 20248, 20504, 20760, 21016, 16784, 17040, 17296, 17552, 17808, 18064,
18320, 18576, 19352, 19608, 19864, 20120, 20376, 20632, 20888, 21144},
{22208, 22464, 22720, 22976, 23232, 23488, 23744, 24000, 24776, 25032, 25288,
25544, 25800, 26056, 26312, 26568, 22336, 22592, 22848, 23104, 23360, 23616,
23872, 24128, 24904, 25160, 25416, 25672, 25928, 26184, 26440, 26696},
{22208, 22464, 22720, 22976, 23232, 23488, 23744, 24000, 24776, 25032, 25288,
25544, 25800, 26056, 26312, 26568, 22336, 22592, 22848, 23104, 23360, 23616,
23872, 24128, 24904, 25160, 25416, 25672, 25928, 26184, 26440, 26696},
{27760, 28016, 28272, 28528, 28784, 29040, 29296, 29552, 30328, 30584, 30840,
31096, 31352, 31608, 31864, 32120, 27888, 28144, 28400, 28656, 28912, 29168,
29424, 29680, 30456, 30712, 30968, 31224, 31480, 31736, 31992, 32248},
{27760, 28016, 28272, 28528, 28784, 29040, 29296, 29552, 30328, 30584, 30840,
31096, 31352, 31608, 31864, 32120, 27888, 28144, 28400, 28656, 28912, 29168,
29424, 29680, 30456, 30712, 30968, 31224, 31480, 31736, 31992, 32248}};
static constexpr uint8_t dual_return_flag = 0x00;
static constexpr uint8_t strongest_return_flag = 0x01;
static constexpr uint8_t last_return_flag = 0x02;
static constexpr uint8_t sync_mode_gps_flag = 0x00;
static constexpr uint8_t sync_mode_e2_e_flag = 0x01;
static constexpr uint8_t sync_mode_p2_p_flag = 0x02;
static constexpr uint8_t sync_mode_gptp_flag = 0x03;
static constexpr uint8_t sync_status_invalid_flag = 0x00;
static constexpr uint8_t sync_status_gps_success_flag = 0x01;
static constexpr uint8_t sync_status_ptp_success_flag = 0x02;
public:
static constexpr float min_range = 0.1f;
static constexpr float max_range = 30.f;
static constexpr size_t max_scan_buffer_points = 1152000;
int get_packet_relative_point_time_offset(
const uint32_t block_id, const uint32_t channel_id,
const std::shared_ptr<const RobosenseSensorConfiguration> & sensor_configuration) override
{
if (sensor_configuration->return_mode == ReturnMode::DUAL)
return firing_time_offset_ns_dual[block_id][channel_id];
else
return firing_time_offset_ns_single[block_id][channel_id];
}
ReturnMode get_return_mode(const robosense_packet::bpearl_v3::InfoPacket & info_packet) override
{
switch (info_packet.return_mode.value()) {
case dual_return_flag:
return ReturnMode::DUAL;
case strongest_return_flag:
return ReturnMode::SINGLE_STRONGEST;
case last_return_flag:
return ReturnMode::SINGLE_LAST;
default:
return ReturnMode::UNKNOWN;
}
}
RobosenseCalibrationConfiguration get_sensor_calibration(
const robosense_packet::bpearl_v3::InfoPacket & info_packet) override
{
return info_packet.sensor_calibration.get_calibration();
}
bool get_sync_status(const robosense_packet::bpearl_v3::InfoPacket & info_packet) override
{
switch (info_packet.sync_status.value()) {
case sync_status_invalid_flag:
return false;
case sync_status_gps_success_flag:
return true;
case sync_status_ptp_success_flag:
return true;
default:
return false;
}
}
std::map<std::string, std::string> get_sensor_info(
const robosense_packet::bpearl_v3::InfoPacket & info_packet) override
{
std::map<std::string, std::string> sensor_info;
sensor_info["motor_speed"] = std::to_string(info_packet.motor_speed.value());
sensor_info["lidar_ip"] = info_packet.ethernet.lidar_ip.to_string();
sensor_info["dest_pc_ip"] = info_packet.ethernet.dest_pc_ip.to_string();
sensor_info["mac_addr"] = info_packet.ethernet.mac_addr.to_string();
sensor_info["lidar_out_msop_port"] =
std::to_string(info_packet.ethernet.lidar_out_msop_port.value());
sensor_info["lidar_out_difop_port"] =
std::to_string(info_packet.ethernet.lidar_out_difop_port.value());
sensor_info["fov_start"] =
robosense_packet::get_float_value(info_packet.fov_setting.fov_start.value());
sensor_info["fov_end"] =
robosense_packet::get_float_value(info_packet.fov_setting.fov_end.value());
sensor_info["tcp_msop_port"] = std::to_string(info_packet.tcp_msop_port.value());
sensor_info["phase_lock"] = std::to_string(info_packet.phase_lock.value());
sensor_info["top_firmware_version"] = info_packet.top_firmware_version.to_string();
sensor_info["bottom_firmware_version"] = info_packet.bottom_firmware_version.to_string();
sensor_info["bottom_software_version"] = info_packet.bottom_software_version.to_string();
sensor_info["motor_firmware_version"] = info_packet.motor_firmware_version.to_string();
sensor_info["reverse_zero_angle_offset"] =
std::to_string(info_packet.reverse_zero_angle_offset.value());
sensor_info["serial_number"] = info_packet.serial_number.to_string();
sensor_info["zero_angle_offset"] = std::to_string(info_packet.zero_angle_offset.value());
switch (info_packet.return_mode.value()) {
case dual_return_flag:
sensor_info["return_mode"] = "dual";
break;
case strongest_return_flag:
sensor_info["return_mode"] = "strongest";
break;
case last_return_flag:
sensor_info["return_mode"] = "last";
break;
default:
sensor_info["return_mode"] = "n/a";
break;
}
switch (info_packet.time_sync_mode.value()) {
case sync_mode_gps_flag:
sensor_info["time_sync_mode"] = "gps";
break;
case sync_mode_e2_e_flag:
sensor_info["time_sync_mode"] = "e2e";
break;
case sync_mode_p2_p_flag:
sensor_info["time_sync_mode"] = "p2p";
break;
case sync_mode_gptp_flag:
sensor_info["time_sync_mode"] = "gptp";
break;
default:
sensor_info["time_sync_mode"] = "n/a";
break;
}
switch (info_packet.sync_status.value()) {
case sync_status_invalid_flag:
sensor_info["sync_status"] = "time_sync_invalid";
break;
case sync_status_gps_success_flag:
sensor_info["sync_status"] = "gps_time_sync_successful";
break;
case sync_status_ptp_success_flag:
sensor_info["sync_status"] = "ptp_time_sync_successful";
break;
default:
sensor_info["sync_status"] = "n/a";
}
sensor_info["time"] = std::to_string(info_packet.time.get_time_in_ns());
sensor_info["v_dat_0v5"] =
robosense_packet::get_float_value(info_packet.operating_status.v_dat_0v5.value());
sensor_info["v_dat_12v"] =
robosense_packet::get_float_value(info_packet.operating_status.v_dat_12v.value());
sensor_info["v_dat_5v"] =
robosense_packet::get_float_value(info_packet.operating_status.v_dat_5v.value());
sensor_info["v_dat_1v25"] =
robosense_packet::get_float_value(info_packet.operating_status.v_dat_1v25.value());
sensor_info["v_dat_0v"] =
robosense_packet::get_float_value(info_packet.operating_status.v_dat_0v.value());
sensor_info["v_dat_1v"] =
robosense_packet::get_float_value(info_packet.operating_status.v_dat_1v.value());
sensor_info["rotation_direction"] = std::to_string(info_packet.rotation_direction.value());
sensor_info["elapsed_time_flag"] = std::to_string(info_packet.elapsed_time_flag.value());
sensor_info["manc_err1"] = std::to_string(info_packet.fault_diagnosis.manc_err1.value());
sensor_info["manc_err2"] = std::to_string(info_packet.fault_diagnosis.manc_err2.value());
const std::bitset<8> gps_st_bits{info_packet.fault_diagnosis.gps_st.value()};
if (gps_st_bits[0])
sensor_info["pps_lock"] = "valid";
else
sensor_info["pps_lock"] = "invalid";
if (gps_st_bits[1])
sensor_info["gprmc_lock"] = "valid";
else
sensor_info["gprmc_lock"] = "invalid";
if (gps_st_bits[2])
sensor_info["utc_lock"] = "synchronized";
else
sensor_info["utc_lock"] = "not_synchronized";
if (gps_st_bits[3])
sensor_info["gprmc_input_status"] = "received_gprmc";
else
sensor_info["gprmc_input_status"] = "no_gprmc";
if (gps_st_bits[4])
sensor_info["pps_input_status"] = "received_pps";
else
sensor_info["pps_input_status"] = "no_pps";
/*
* From the manual, here is the formula for calculating bottom board temperature:
* Temp =(Value(temp1)* 256 + Value(temp2)& 0Xffff)* 503.975 / 4096.0 - 273.15
*/
sensor_info["bottom_board_temp"] = std::to_string(
(static_cast<float>(info_packet.fault_diagnosis.temperature1.value()) * 256 +
static_cast<float>(info_packet.fault_diagnosis.temperature2.value())) *
503.975 / 4096.0 -
273.15);
/*
* From the manual, here is the formula for calculating APD temperature:
* When Value ≤ 32768, the temperature value is positive; otherwise negative.
* Temp = ( (value(362) * 256 + value(363) ) & 0x7FF8 ) / 128.0
*/
double apd_temp = ((info_packet.fault_diagnosis.temperature3.value() * 256 +
info_packet.fault_diagnosis.temperature4.value()) &
0x7FF8) /
128.0;
if (
((info_packet.fault_diagnosis.temperature3.value() << 8)) +
info_packet.fault_diagnosis.temperature4.value() >
32768)
apd_temp = -apd_temp;
sensor_info["apd_temp"] = std::to_string(apd_temp);
/*
* From the manual, here is the formula for calculating top board temperature:
* When Value ≤ 32768, the temperature value is positive; otherwise negative.
* Temp= ( (value(362) * 256 + value(363) ) & 0x7FF8 ) / 128.0
*/
double top_board_temp = ((info_packet.fault_diagnosis.temperature5.value() * 256 +
info_packet.fault_diagnosis.temperature6.value()) &
0x7FF8) /
128.0;
if (
((info_packet.fault_diagnosis.temperature5.value() << 8)) +
info_packet.fault_diagnosis.temperature6.value() >
32768)
top_board_temp = -top_board_temp;
sensor_info["top_board_temp"] = std::to_string(top_board_temp);
/*
* From the manual, here is the formula for calculating real time rotation speed:
* Speed = (256 * r_rpm1 + r_rpm2) / 6
*/
sensor_info["real_time_rot_speed"] = std::to_string(
(info_packet.fault_diagnosis.r_rpm1.value() * 256 +
info_packet.fault_diagnosis.r_rpm2.value()) /
6);
std::string gprmc_string;
for (auto i : info_packet.gprmc) {
gprmc_string += static_cast<char>(i.value());
}
sensor_info["gprmc_string"] = gprmc_string;
return sensor_info;
}
};
} // namespace nebula::drivers