ardupilot支持不同厂商的传感器,如雷达,声呐,激光,相机等;
I2C,
SPI,
UART (aka Serial)
CANBUS
ardupilot中传感器驱动的重要结构是前后分离;
Library库调用前端程序;
前端程序调用后端程序;
后端程序一般是个for循环??
通过串口协议实现通讯,即实现数据位的收发;
驱动程序的作用:
#if HAL_PROXIMITY_ENABLED
SCHED_TASK_CLASS(AP_Proximity, &copter.g2.proximity, update, 200, 50, 36),
#endif
for (uint8_t i=0; i<num_instances; i++) {
if (!valid_instance(i)) {
continue;
}
drivers[i]->update();
}
利用understand软件来帮助查看!!
选中num_instances,右键 vie imformastion,左下角选择data flow in即可查看 num_instances 的赋值,可知其在 init 中被赋值,在类AP_Proximity中被定义:
将右上角的variant切换成cluster模式看着更清晰:
for (uint8_t instance=0; instance<PROXIMITY_MAX_INSTANCES; instance++) {
switch (get_type(instance)) {
case Type::None:
break;
case Type::RPLidarA2:
if (AP_Proximity_RPLidarA2::detect(serial_instance)) {
state[instance].instance = instance;
drivers[instance] = new AP_Proximity_RPLidarA2(*this, state[instance], params[instance], serial_instance);
serial_instance++;
}
break;
......
}
PROXIMITY_MAX_INSTANCES为3,在定义时被赋值,即最多可接3个接近传感器;
问题1:get_type(instance)返回什么?
AP_Proximity::Type AP_Proximity::get_type(uint8_t instance) const
{
if (instance < PROXIMITY_MAX_INSTANCES) {
return (Type)((uint8_t)params[instance].type);
}
return Type::None;
}
返回值与数组params有关,进类中查看并寻找它的赋值语句,如果找不到初始化则应该在构造函数中查找!
// parameters for backends
AP_Proximity_Params params[PROXIMITY_MAX_INSTANCES];
可知params类型是AP_Proximity_Params :
class AP_Proximity_Params {
public:
static const struct AP_Param::GroupInfo var_info[];
AP_Proximity_Params(void);
/* Do not allow copies */
CLASS_NO_COPY(AP_Proximity_Params);
AP_Int8 type; // type of sensor
AP_Int8 orientation; // orientation (e.g. right-side-up or upside-down)
AP_Int16 yaw_correction; // yaw correction in degrees
AP_Int16 ignore_angle_deg[PROXIMITY_MAX_IGNORE]; // angle (in degrees) of area that should be ignored by sensor (i.e. leg shows up)
AP_Int8 ignore_width_deg[PROXIMITY_MAX_IGNORE]; // width of beam (in degrees) that should be ignored
AP_Float max_m; // maximum range in meters
AP_Float min_m; // minimum range in meters
AP_Int8 address; // proximity address (for AP_Periph CAN)
};
在AP_Proximity中查看params是如何被赋值的,构造函数:
AP_Proximity::AP_Proximity()
{
AP_Param::setup_object_defaults(this, var_info);
}
其中this是类当前的实例,var_info包含了???信息?
var_info的类型为AP_Param::GroupInfo:
struct GroupInfo {
const char *name;
ptrdiff_t offset; // offset within the object
union {
const struct GroupInfo *group_info;
const struct GroupInfo **group_info_ptr; // when AP_PARAM_FLAG_INFO_POINTER is set in flags
const float def_value;
ptrdiff_t def_value_offset; // Default value offset from param object, when AP_PARAM_FLAG_DEFAULT_POINTER is set in flags
};
uint16_t flags;
uint8_t idx; // identifier within the group
uint8_t type; // AP_PARAM_*
};
数组 var_info[ ] 赋值语句:
// table of user settable parameters
const AP_Param::GroupInfo AP_Proximity::var_info[] = {
AP_GROUPINFO_FRAME("_IGN_GND", 16, AP_Proximity, _ign_gnd_enable, 0, AP_PARAM_FRAME_COPTER | AP_PARAM_FRAME_HELI | AP_PARAM_FRAME_TRICOPTER),
AP_GROUPINFO("_LOG_RAW", 17, AP_Proximity, _raw_log_enable, 0),
AP_GROUPINFO("_FILT", 18, AP_Proximity, _filt_freq, 0.25f),
AP_GROUPINFO_FRAME("_ALT_MIN", 25, AP_Proximity, _alt_min, 1.0f, AP_PARAM_FRAME_COPTER | AP_PARAM_FRAME_HELI | AP_PARAM_FRAME_TRICOPTER),
AP_SUBGROUPINFO(params[0], "1", 21, AP_Proximity, AP_Proximity_Params),
AP_SUBGROUPINFO(params[1], "2", 22, AP_Proximity, AP_Proximity_Params),
AP_SUBGROUPINFO(params[2], "3", 23, AP_Proximity, AP_Proximity_Params),
AP_SUBGROUPINFO(params[3], "4", 24, AP_Proximity, AP_Proximity_Params),
AP_GROUPEND
};
var_info[] 数组的每个元素(每一行宏定义)代表每个独立参数的信息合集合;可知一共有三种不同的宏定义可以使用,下面分别解析;
AP_GROUPINFO_FRAME("_IGN_GND", 16, AP_Proximity, _ign_gnd_enable, 0, AP_PARAM_FRAME_COPTER | AP_PARAM_FRAME_HELI | AP_PARAM_FRAME_TRICOPTER)
AP_GROUPINFO("_LOG_RAW", 17, AP_Proximity, _raw_log_enable, 0),
AP_SUBGROUPINFO(params[0], "1", 21, AP_Proximity, AP_Proximity_Params),
题外话:ptrdiff_t是C/C++标准库中定义的一个与机器相关的数据类型。ptrdiff_t类型变量通常用来保存两个指针减法操作的结果。
小结:
var_info[] 数组每个元素分别保存了类AP_Proximity中的params、_alt_min、_filt_freq、_ign_gnd_enable等这几个成员的相关信息(包括变量名称,默认值,地址偏移量,数据类型等信息),以便传递给构造函数根据地面站的用户设置进行赋值;
比如,用户在地面站上设定参数AP_Proximity_IGN_GND为0,则代码将会把PRX_IGN_GND的值通过名称匹配地址匹配的方式赋值给当前AP_Proximity实例中的成员_ign_gnd_enable!!
那么问题来了,这个赋值过程是怎么样的呢??
这就要看看类AP_Proximity构造函数中的 AP_Param::setup_object_defaults(this, var_info) 了!
this:当前实例对象的指针有了;
var_info:要给哪些参数赋值也懂了;
就看底层怎么操作了:
// load default values for scalars in a group. This does not recurse
// into other objects. This is a static function that should be called
// in the objects constructor
void AP_Param::setup_object_defaults(const void *object_pointer, const struct GroupInfo *group_info)
{
ptrdiff_t base = (ptrdiff_t)object_pointer;
uint8_t type;
for (uint8_t i=0;
(type=group_info[i].type) != AP_PARAM_NONE;
i++) {
if (type <= AP_PARAM_FLOAT) {
void *ptr = (void *)(base + group_info[i].offset);
set_value((enum ap_var_type)type, ptr,
get_default_value((const AP_Param *)ptr, group_info[i]));
} else if (type == AP_PARAM_VECTOR3F) {
// Single default for all components
void *ptr = (void *)(base + group_info[i].offset);
const float default_val = get_default_value((const AP_Param *)ptr, group_info[i]);
((AP_Vector3f *)ptr)->set(Vector3f{default_val, default_val, default_val});
}
}
}
很羞耻地说,上面这19行c++代码我拿出了28年的所有真才实学仍旧没看明白!
看了上面的if else if 后,貌似要拉闸?AP_Param的构造函数中并没有对AP_Proximity::params进行赋值??!params的类型并不满足if也不满足else if啊!那params是如何被初始化的啊?答案只有一个,params的类型是类AP_Proximity_Params,那去这个类的构造函数看看!
果不其然啊!!类AP_Proximity_Params有自己的构造函数,并且有自己的AP_Proximity_Params::var_info,params在构造函数中初始化:
// table of user settable parameters
const AP_Param::GroupInfo AP_Proximity_Params::var_info[] = {
AP_GROUPINFO_FLAGS("_TYPE", 1, AP_Proximity_Params, type, 0, AP_PARAM_FLAG_ENABLE),
AP_GROUPINFO("_ORIENT", 2, AP_Proximity_Params, orientation, 0),
......
}
AP_Proximity_Params::AP_Proximity_Params(void) {
AP_Param::setup_object_defaults(this, var_info);
}
从这个var_info[]可知,_TYPE被初始化成了0,也就是sensor type为none!这也回答了一开的问题1:get_type(instance)返回什么的问题!
小结:
问题2:除了初始化外,这些参数如何被mavlink消息覆盖的呢?
用户通过地面站对参数进行设置,去线程SCHED_TASK_CLASS(GCS, (GCS*)&copter._gcs, update_receive, 400, 180, 102)中一探究竟!!
再往下阅读之前建议读者还可以浅浅参考本人之前写过的一篇博文:ardupilot参数的从mavlink消息到底层参数赋值
这里重新梳理一下这个赋值过程和逻辑,毕竟不同时期有不同的理解:
从前期工作“ardupilot参数的从mavlink消息到底层参数赋值”中可知,某些参数的赋值在函数handle_param_set中进行,上下游的调用流程为:
SCHED_TASK_CLASS(GCS, (GCS*)&copter._gcs, update_receive, 400, 180, 102)~>
update_receive ~> packetReceived ~> packetReceived ~> handleMessage ~> handle_common_message ~> handle_common_param_message ~> handle_param_set()
那么现在直接去handle_param_set()中查看:
void GCS_MAVLINK::handle_param_set(const mavlink_message_t &msg)
{
mavlink_param_set_t packet;
mavlink_msg_param_set_decode(&msg, &packet);
enum ap_var_type var_type;
// set parameter
AP_Param *vp;
char key[AP_MAX_NAME_SIZE+1];
strncpy(key, (char *)packet.param_id, AP_MAX_NAME_SIZE);
key[AP_MAX_NAME_SIZE] = 0;
// find existing param so we can get the old value
uint16_t parameter_flags = 0;
vp = AP_Param::find(key, &var_type, ¶meter_flags);
if (vp == nullptr || isnan(packet.param_value) || isinf(packet.param_value)) {
return;
}
float old_value = vp->cast_to_float(var_type);
if (parameter_flags & AP_PARAM_FLAG_INTERNAL_USE_ONLY) {
// the user can set BRD_OPTIONS to enable set of internal
// parameters, for developer testing or unusual use cases
if (AP_BoardConfig::allow_set_internal_parameters()) {
parameter_flags &= ~AP_PARAM_FLAG_INTERNAL_USE_ONLY;
}
}
if ((parameter_flags & AP_PARAM_FLAG_INTERNAL_USE_ONLY) || vp->is_read_only()) {
gcs().send_text(MAV_SEVERITY_WARNING, "Param write denied (%s)", key);
// send the readonly value
send_parameter_value(key, var_type, old_value);
return;
}
// set the value
vp->set_float(packet.param_value, var_type);
/*
we force the save if the value is not equal to the old
value. This copes with the use of override values in
constructors, such as PID elements. Otherwise a set to the
default value which differs from the constructor value doesn't
save the change
*/
bool force_save = !is_equal(packet.param_value, old_value);
// save the change
vp->save(force_save);
if (force_save && (parameter_flags & AP_PARAM_FLAG_ENABLE)) {
AP_Param::invalidate_count();
}
AP_Logger *logger = AP_Logger::get_singleton();
if (logger != nullptr) {
logger->Write_Parameter(key, vp->cast_to_float(var_type));
}
}
最主要的就是下面这两个函数:
言归正传,我们还是继续看驱动后台如何被调用的吧!!
继续嗑void AP_Proximity::init()函数:
阅读到这已经懂得switch (get_type(instance))的get_type(instance)是什么,那么就可以知道要执行哪个case了;
以case Type::RPLidarA2为例,接下来要弄懂的是:
AP_Proximity_RPLidarA2::detect(serial_instance)是如何检测雷达是否正常接入的?
很坑!类AP_Proximity_RPLidarA2中找死都找不到detect函数!
原来是在AP_Proximity_RPLidarA2的父类AP_Proximity_Backend_Serial中:
class AP_Proximity_Backend_Serial : public AP_Proximity_Backend
{
public:
AP_Proximity_Backend_Serial(AP_Proximity &_frontend,
AP_Proximity::Proximity_State &_state,
AP_Proximity_Params& _params,
uint8_t serial_instance);
// static detection function
// detect if a proximity sensor is connected by looking for a configured serial port
// serial_instance affects which serial port is used. Should be 0 or 1 depending on whether this is the 1st or 2nd proximity sensor with a serial interface
static bool detect(uint8_t serial_instance);
protected:
virtual uint16_t rxspace() const { return 0; };
AP_HAL::UARTDriver *_uart; // uart for communicating with sensor
};
我哭死!终于找到了从获取雷达数据到上传到用于避障的数据库的调用结构:
知道了可行性后,下面开始尝试将一个新的驱动代码集成到ardupilot中!!
集成新的驱动代码到ardupilot(以RPLidarS1为例):
运行update之前肯定init函数先被调用,init只在reboot时调用?所以在地面站更改串口协议参数时需要reboot??
假如要在init中的Switch中增加一个case,以增加RPLidarS1雷达的驱动为例:
// Proximity driver types
enum class Type {
None = 0,
// 1 was SF40C_v09
#if AP_PROXIMITY_MAV_ENABLED
MAV = 2,
#endif
#if AP_PROXIMITY_TERARANGERTOWER_ENABLED
TRTOWER = 3,
#endif
#if AP_PROXIMITY_RANGEFINDER_ENABLED
RangeFinder = 4,
#endif
#if AP_PROXIMITY_RPLIDARA2_ENABLED
RPLidarA2 = 5,
#endif
#if AP_PROXIMITY_TERARANGERTOWEREVO_ENABLED
TRTOWEREVO = 6,
#endif
#if AP_PROXIMITY_LIGHTWARE_SF40C_ENABLED
SF40C = 7,
#endif
#if AP_PROXIMITY_LIGHTWARE_SF45B_ENABLED
SF45B = 8,
#endif
#if AP_PROXIMITY_SITL_ENABLED
SITL = 10,
#endif
#if AP_PROXIMITY_AIRSIMSITL_ENABLED
AirSimSITL = 12,
#endif
#if AP_PROXIMITY_CYGBOT_ENABLED
CYGBOT_D1 = 13,
#endif
#if AP_PROXIMITY_DRONECAN_ENABLED
DroneCAN = 14,
#endif
};
这个枚举与地面站参数PRX#_TYPE相关!!
注意:get_type(instance)只会检测用户是否配置了参数PRX#_TYPE ,与传感器是否连接飞控连接后正不正常都无关!!
#if AP_PROXIMITY_RPLIDARA2_ENABLED
case Type::RPLidarA2:
if (AP_Proximity_RPLidarA2::detect(serial_instance)) {
state[instance].instance = instance;
drivers[instance] = new AP_Proximity_RPLidarA2(*this, state[instance], params[instance], serial_instance);
serial_instance++;
}
break;
#endif
AP_Proximity_Backend_Serial(AP_Proximity &_frontend,
AP_Proximity::Proximity_State &_state,
AP_Proximity_Params& _params,
uint8_t serial_instance);
所以并不需要添加一个AP_Proximity_RPLidarS1 构造函数,只需要类AP_Proximity_RPLidarS1 继承类AP_Proximity_Backend_Serial即可使用!
send_request_for_device_info();
_state = State::AWAITING_RESPONSE;
2)执行case State::AWAITING_RESPONSE:
_state = State::AWAITING_DEVICE_INFO;
3)执行case State::AWAITING_DEVICE_INFO:
parse_response_device_info();
consume_bytes(sizeof(_payload.device_info));
其中 parse_response_device_info()要执行以下语句:
send_scan_mode_request();
_state = State::AWAITING_RESPONSE;
4)执行执行case State::AWAITING_RESPONSE:
_state = State::AWAITING_SCAN_DATA;
5)执行case State::AWAITING_SCAN_DATA:
parse_response_data();//解码扫描数据
consume_bytes(sizeof(_payload.sensor_scan));
其中parse_response_data()要执行以下语句:
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);//计算扫描点我雷达坐标系的距离
// update OA database
database_push(_last_angle_deg, _last_distance_m);
写了一些注释的完整代码请参考附录。
下面代码没明白:S1 9? A1A2A3 63???
// request device info 3sec after reset
// required for S1 support that sends only 9 bytes after a reset (A1,A2 send 63)
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;//reset后清除已读取到_payload的数据
}
A2和S1的命令字节格式是否一样?不一样是否需要改动?改动哪里?
#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
// Commands without payload but have response
#define RPLIDAR_CMD_GET_DEVICE_INFO 0x50
#define RPLIDAR_CMD_GET_DEVICE_HEALTH 0x52
// Commands with payload and have response
#define RPLIDAR_CMD_EXPRESS_SCAN 0x82
void AP_Proximity_RPLidarA2::update(void)
{
//要区别两种reset: (1) _state = State::RESET (2) reset_rplidar();
// 第一种reset是清除已读取到_payload的数据,令_byte_count = 0就可以;
//第二种,要调用reset_rplidar(),不仅要_state = State::RESET;_byte_count = 0;还要_uart->write(tx_buffer, 2);
if (_uart == nullptr) {
return;
}
// request device info 3sec after reset
// required for S1 support that sends only 9 bytes after a reset (A1,A2 send 63)
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;//reset后清除已读取到_payload的数据
}
get_readings();
// check for timeout and set health status
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);
}
}
void AP_Proximity_RPLidarA2::get_readings()
{
Debug(2, " CURRENT STATE: %u ", (unsigned)_state);
const uint32_t nbytes = _uart->available();//返回可从队列前面读取的对象数
if (nbytes == 0) {
return;
}
//_payload:接收串口数据的buffer,是个数组,类型是个union,根据不同响应接收到的字节数是不一样的!
//sizeof(_payload):_payload能容纳的最大字节数
//_byte_count:已经读取到_payload中的字节数
//sizeof(_payload)-_byte_count:剩余容纳的字节数
//nbytes:串口buffer可用的字节数
//bytes_to_read:本次要读取到_payload的字节数
//bytes_read:本次成功读取到_payload的字节数,不出意外的话bytes_read和bytes_to_read应该相等
//注意:buffer和_payload的区别,buffer是串口的实时缓存,_payload是存放从buffer中读取到数据的变量
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) {
// this is bad; we were told there were bytes available
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
reset();
return;
}
_byte_count += bytes_read;//成功将bytes_read个串口字节读取到 _payload,则更改_byte_count
uint32_t previous_loop_byte_count = UINT32_MAX;//previous_loop_byte_count:上一次循环_payload中的字节数,为了防止无限循环而引入的变量,具体使用往下看
while (_byte_count) {
if (_byte_count >= previous_loop_byte_count) {
// this is a serious error, we should always consume some
// bytes. Avoid looping forever.
INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
_uart = nullptr;
return;
}
previous_loop_byte_count = _byte_count;
switch(_state){
case State::RESET: {
// looking for 0x52 at start of buffer; the 62 following
// bytes are "information"
if (!make_first_byte_in_payload('R')) { // that's 'R' as in RPiLidar
return;
}
if (_byte_count < 63) {
return;
}
#if RP_DEBUG_LEVEL
// optionally spit out via mavlink the 63-bytes of cruft
// that is spat out on device reset
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
// 63 is the magic number of bytes in the spewed-out
// reset data ... so now we'll just drop that stuff on
// the floor.
consume_bytes(63);
send_request_for_device_info();
_state = State::AWAITING_RESPONSE;
continue;
}
case State::AWAITING_RESPONSE:
//reset()后( send_request_for_device_info()后 ),串口接收到的第一个字节应该是RPLIDAR_PREAMBLE,即 0xA5
//如果不是则判定为协议错误!
if (_payload[0] != RPLIDAR_PREAMBLE) {
// this is a protocol error. Reset.
reset();
return;
}
// reset()后( send_request_for_device_info()后 ),串口buffer接收到的第一个packet应该是_descriptor,并且_descriptor应该是7个字节
// descriptor packet has 7 byte in total
if (_byte_count < sizeof(_descriptor)) {
return;
}
// identify the payload data after the descriptor
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");
//根据第一个字节()判断设备状态,以判断便下一步应该做什么动作!!
//memcmp:memcmp(const void *str1, const void *str2, size_t n))其功能是把存储区 str1 和存储区 str2 的前 n 个字节进行比较;如果返回值 = 0,则表示 str1 等于 str2
if (memcmp((void*)&_payload[0], SCAN_DATA_DESCRIPTOR, sizeof(_descriptor)) == 0) { //if成立则表明_payload[0]==SCAN_DATA_DESCRIPTOR,下面的else if 则同理
_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 {
// unknown descriptor. Ignore it.
}
consume_bytes(sizeof(_descriptor)); //将读取到的数据从_payload中清除,以便后续的buffer数据读取进来
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://重要的case分支,等待扫描数据的读取!!
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_data()
{
if (_sync_error) {
// out of 5-byte sync mask -> catch new revolution
Debug(1, " OUT OF SYNC");
// on first revolution bit 1 = 1, bit 2 = 0 of the first byte
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]); //show HEX values
// check if valid SCAN packet: a valid packet starts with startbits which are complementary plus a checkbit in byte+1
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);
//Face是什么?临时保存的3D边界信息,包括layer和sector
// uint8_t layer; // vertical "steps" on the 3D Boundary. 0th layer is the bottom most layer, 1st layer is 30 degrees above (in body frame) and so on
// uint8_t sector; // horizontal "steps" on the 3D Boundary. 0th sector is directly in front of the vehicle. Each sector is 45 degrees wide.
if (face != _last_face) {
// distance is for a new face, the previous one can be updated now
if (_last_distance_valid) {
frontend.boundary.set_face_attributes(_last_face, _last_angle_deg, _last_distance_m, state.instance);
} else {
// reset distance from last face
frontend.boundary.reset_face(face, state.instance);
}
// initialize the new face
_last_face = face;
_last_distance_valid = false;
}
if (distance_m > distance_min()) {
// update shortest distance
if (!_last_distance_valid || (distance_m < _last_distance_m)) {
_last_distance_m = distance_m;
_last_distance_valid = true;
_last_angle_deg = angle_deg;
}
// update OA database
database_push(_last_angle_deg, _last_distance_m);
}
}
}