添加了自己的一些理解与注释
AP_Proximity_RPLidarA2.cpp
#include "AP_Proximity_config.h"
#if AP_PROXIMITY_RPLIDARA2_ENABLED
#include "AP_Proximity_RPLidarA2.h"
#include
#include "AP_Proximity_RPLidarA2.h"
#include
#include
#include
#define RP_DEBUG_LEVEL 0
#include
#if RP_DEBUG_LEVEL
#define Debug(level, fmt, args ...) do { if (level <= RP_DEBUG_LEVEL) { gcs().send_text(MAV_SEVERITY_INFO, fmt, ## args); } } while (0)
#else
#define Debug(level, fmt, args ...)
#endif
#define COMM_ACTIVITY_TIMEOUT_MS 200
#define RPLIDAR_PREAMBLE 0xA5
#define RPLIDAR_CMD_STOP 0x25
#define RPLIDAR_CMD_SCAN 0x20
#define RPLIDAR_CMD_FORCE_SCAN 0x21
#define RPLIDAR_CMD_RESET 0x40
#define RPLIDAR_CMD_GET_DEVICE_INFO 0x50
#define RPLIDAR_CMD_GET_DEVICE_HEALTH 0x52
#define RPLIDAR_CMD_EXPRESS_SCAN 0x82
extern const AP_HAL::HAL& hal;
void AP_Proximity_RPLidarA2::update(void)
{
if (_uart == nullptr) {
return;
}
uint32_t now_ms = AP_HAL::millis();
if ((_state == State::RESET) && (now_ms - _last_reset_ms > 3000)) {
send_request_for_device_info();
_state = State::AWAITING_RESPONSE;
_byte_count = 0;
}
get_readings();
if (AP_HAL::millis() - _last_distance_received_ms > COMM_ACTIVITY_TIMEOUT_MS) {
set_status(AP_Proximity::Status::NoData);
Debug(1, "LIDAR NO DATA");
if (AP_HAL::millis() - _last_reset_ms > 10000) {
reset_rplidar();
}
} else {
set_status(AP_Proximity::Status::Good);
}
}
float AP_Proximity_RPLidarA2::distance_max() const
{
switch (model) {
case Model::UNKNOWN:
return 0.0f;
case Model::A1:
return 8.0f;
case Model::A2:
return 16.0f;
case Model::S1:
return 40.0f;
}
return 0.0f;
}
float AP_Proximity_RPLidarA2::distance_min() const
{
switch (model) {
case Model::UNKNOWN:
return 0.0f;
case Model::A1:
return 0.2f;
case Model::A2:
case Model::S1:
return 0.2f;
}
return 0.0f;
}
void AP_Proximity_RPLidarA2::reset_rplidar()
{
static const uint8_t tx_buffer[2] {RPLIDAR_PREAMBLE, RPLIDAR_CMD_RESET};
_uart->write(tx_buffer, 2);
Debug(1, "LIDAR reset");
_last_reset_ms = AP_HAL::millis();
reset();
}
void AP_Proximity_RPLidarA2::send_scan_mode_request()
{
static const uint8_t tx_buffer[2] {RPLIDAR_PREAMBLE, RPLIDAR_CMD_SCAN};
_uart->write(tx_buffer, 2);
Debug(1, "Sent scan mode request");
}
void AP_Proximity_RPLidarA2::send_request_for_health()
{
static const uint8_t tx_buffer[2] {RPLIDAR_PREAMBLE, RPLIDAR_CMD_GET_DEVICE_HEALTH};
_uart->write(tx_buffer, 2);
Debug(1, "Sent health request");
}
void AP_Proximity_RPLidarA2::send_request_for_device_info()
{
static const uint8_t tx_buffer[2] {RPLIDAR_PREAMBLE, RPLIDAR_CMD_GET_DEVICE_INFO};
_uart->write(tx_buffer, 2);
Debug(1, "Sent device information request");
}
void AP_Proximity_RPLidarA2::consume_bytes(uint16_t count)
{
if (count > _byte_count) {
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
_byte_count = 0;
return;
}
_byte_count -= count;
if (_byte_count) {
memmove((void*)&_payload[0], (void*)&_payload[count], _byte_count);
}
}
void AP_Proximity_RPLidarA2::reset()
{
_state = State::RESET;
_byte_count = 0;
}
bool AP_Proximity_RPLidarA2::make_first_byte_in_payload(uint8_t desired_byte)
{
if (_byte_count == 0) {
return false;
}
if (_payload[0] == desired_byte) {
return true;
}
for (auto i=1; i<_byte_count; i++) {
if (_payload[i] == desired_byte) {
consume_bytes(i);
return true;
}
}
_byte_count = 0;
return false;
}
void AP_Proximity_RPLidarA2::get_readings()
{
Debug(2, " CURRENT STATE: %u ", (unsigned)_state);
const uint32_t nbytes = _uart->available();
if (nbytes == 0) {
return;
}
const uint32_t bytes_to_read = MIN(nbytes, sizeof(_payload)-_byte_count);
if (bytes_to_read == 0) {
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
reset();
return;
}
const uint32_t bytes_read = _uart->read(&_payload[_byte_count], bytes_to_read);
if (bytes_read == 0) {
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
reset();
return;
}
_byte_count += bytes_read;
uint32_t previous_loop_byte_count = UINT32_MAX;
while (_byte_count) {
if (_byte_count >= previous_loop_byte_count) {
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
_uart = nullptr;
return;
}
previous_loop_byte_count = _byte_count;
switch(_state){
case State::RESET: {
if (!make_first_byte_in_payload('R')) {
return;
}
if (_byte_count < 63) {
return;
}
#if RP_DEBUG_LEVEL
Debug(1, "Got RPLidar Information");
char xbuffer[64]{};
memcpy((void*)xbuffer, (void*)&_payload.information, 63);
gcs().send_text(MAV_SEVERITY_INFO, "RPLidar: (%s)", xbuffer);
#endif
consume_bytes(63);
send_request_for_device_info();
_state = State::AWAITING_RESPONSE;
continue;
}
case State::AWAITING_RESPONSE:
if (_payload[0] != RPLIDAR_PREAMBLE) {
reset();
return;
}
if (_byte_count < sizeof(_descriptor)) {
return;
}
static const _descriptor SCAN_DATA_DESCRIPTOR[] {
{ RPLIDAR_PREAMBLE, 0x5A, 0x05, 0x00, 0x00, 0x40, 0x81 }
};
static const _descriptor HEALTH_DESCRIPTOR[] {
{ RPLIDAR_PREAMBLE, 0x5A, 0x03, 0x00, 0x00, 0x00, 0x06 }
};
static const _descriptor DEVICE_INFO_DESCRIPTOR[] {
{ RPLIDAR_PREAMBLE, 0x5A, 0x14, 0x00, 0x00, 0x00, 0x04 }
};
Debug(2,"LIDAR descriptor found");
if (memcmp((void*)&_payload[0], SCAN_DATA_DESCRIPTOR, sizeof(_descriptor)) == 0) {
_state = State::AWAITING_SCAN_DATA;
} else if (memcmp((void*)&_payload[0], DEVICE_INFO_DESCRIPTOR, sizeof(_descriptor)) == 0) {
_state = State::AWAITING_DEVICE_INFO;
} else if (memcmp((void*)&_payload[0], HEALTH_DESCRIPTOR, sizeof(_descriptor)) == 0) {
_state = State::AWAITING_HEALTH;
} else {
}
consume_bytes(sizeof(_descriptor));
break;
case State::AWAITING_DEVICE_INFO:
if (_byte_count < sizeof(_payload.device_info)) {
return;
}
parse_response_device_info();
consume_bytes(sizeof(_payload.device_info));
break;
case State::AWAITING_SCAN_DATA:
if (_byte_count < sizeof(_payload.sensor_scan)) {
return;
}
parse_response_data();
consume_bytes(sizeof(_payload.sensor_scan));
break;
case State::AWAITING_HEALTH:
if (_byte_count < sizeof(_payload.sensor_health)) {
return;
}
parse_response_health();
consume_bytes(sizeof(_payload.sensor_health));
break;
}
}
}
void AP_Proximity_RPLidarA2::parse_response_device_info()
{
Debug(1, "Received DEVICE_INFO");
const char *device_type = "UNKNOWN";
switch (_payload.device_info.model) {
case 0x18:
model = Model::A1;
device_type = "A1";
break;
case 0x28:
model = Model::A2;
device_type = "A2";
break;
case 0x61:
model = Model::S1;
device_type = "S1";
break;
default:
Debug(1, "Unknown device (%u)", _payload.device_info.model);
}
GCS_SEND_TEXT(MAV_SEVERITY_INFO, "RPLidar %s hw=%u fw=%u.%u", device_type, _payload.device_info.hardware, _payload.device_info.firmware_minor, _payload.device_info.firmware_major);
send_scan_mode_request();
_state = State::AWAITING_RESPONSE;
}
void AP_Proximity_RPLidarA2::parse_response_data()
{
if (_sync_error) {
Debug(1, " OUT OF SYNC");
if ((_payload[0] & 0x03) == 0x01) {
_sync_error = 0;
Debug(1, " RESYNC");
} else {
return;
}
}
Debug(2, "UART %02x %02x%02x %02x%02x", _payload[0], _payload[2], _payload[1], _payload[4], _payload[3]);
if (!((_payload.sensor_scan.startbit == !_payload.sensor_scan.not_startbit) && _payload.sensor_scan.checkbit)) {
Debug(1, "Invalid Payload");
_sync_error++;
return;
}
const float angle_sign = (params.orientation == 1) ? -1.0f : 1.0f;
const float angle_deg = wrap_360(_payload.sensor_scan.angle_q6/64.0f * angle_sign + params.yaw_correction);
const float distance_m = (_payload.sensor_scan.distance_q2/4000.0f);
#if RP_DEBUG_LEVEL >= 2
const float quality = _payload.sensor_scan.quality;
Debug(2, " D%02.2f A%03.1f Q%0.2f", distance_m, angle_deg, quality);
#endif
_last_distance_received_ms = AP_HAL::millis();
if (!ignore_reading(angle_deg, distance_m)) {
const AP_Proximity_Boundary_3D::Face face = frontend.boundary.get_face(angle_deg);
if (face != _last_face) {
if (_last_distance_valid) {
frontend.boundary.set_face_attributes(_last_face, _last_angle_deg, _last_distance_m, state.instance);
} else {
frontend.boundary.reset_face(face, state.instance);
}
_last_face = face;
_last_distance_valid = false;
}
if (distance_m > distance_min()) {
if (!_last_distance_valid || (distance_m < _last_distance_m)) {
_last_distance_m = distance_m;
_last_distance_valid = true;
_last_angle_deg = angle_deg;
}
database_push(_last_angle_deg, _last_distance_m);
}
}
}
void AP_Proximity_RPLidarA2::parse_response_health()
{
if (_payload.sensor_health.status == 3) {
Debug(1, "LIDAR Error");
}
Debug(1, "LIDAR Healthy");
}
#endif