20180402:
UAVCAN使用的主要邏輯代碼,在AP_UAVCAN.cpp文件中,AP_UAVCAN類的任務是在硬件配置支持的情況下使用UAVCAN協議,進行數據的收發。UAVCAN協議的收發邏輯代碼太過於複雜,看了幾天仍然雲裏霧裏,所以我決定轉換思路,不再過深的去了解協議的收發邏輯代碼,轉而去了解需要經過哪些步驟,使用哪些UAVCAN協議提供的API,可以完成收發任務。
接下來以GPS數據爲例,來梳理使用UAVCAN協議完成數據收發的過程:
飛控要通過UAVCAN使用GPS信息,需要添加使用UAVCAN協議中GPS數據的類,APM中此類在AP_GPS_UAVCAN.cpp和AP_GPS_UAVCAN.h中。AP_UAVCAN類讀到UAVCAN協議的GPS信息後,存儲在_gps_node_state[AP_UAVCAN_MAX_GPS_NODES]結構體數組中,通過update_gps_state函數,將GPS信息傳遞給AP_GPS_UAVCAN類。
AP_UAVCAN構造函數:
_gps_nodes[AP_UAVCAN_MAX_GPS_NODES]:存放着發送GPS信息的節點(下文簡稱爲GPS信息源)ID
_gps_node_taken[AP_UAVCAN_MAX_GPS_NODES]
_gps_listener_to_node[AP_UAVCAN_MAX_LISTENERS]
_gps_listeners[AP_UAVCAN_MAX_LISTENERS]
注:宏定義見附錄。
AP_UAVCAN::AP_UAVCAN() :
_node_allocator(
UAVCAN_NODE_POOL_SIZE, UAVCAN_NODE_POOL_SIZE)
{
AP_Param::setup_object_defaults(this, var_info);
for (uint8_t i = 0; i < UAVCAN_RCO_NUMBER; i++) {
_rco_conf[i].active = false;
}
for (uint8_t i = 0; i < AP_UAVCAN_MAX_GPS_NODES; i++) {
_gps_nodes[i] = UINT8_MAX;
_gps_node_taken[i] = 0;
}
for (uint8_t i = 0; i < AP_UAVCAN_MAX_BARO_NODES; i++) {
_baro_nodes[i] = UINT8_MAX;
_baro_node_taken[i] = 0;
}
for (uint8_t i = 0; i < AP_UAVCAN_MAX_MAG_NODES; i++) {
_mag_nodes[i] = UINT8_MAX;
_mag_node_taken[i] = 0;
}
for (uint8_t i = 0; i < AP_UAVCAN_MAX_LISTENERS; i++) {
_gps_listener_to_node[i] = UINT8_MAX;
_gps_listeners[i] = nullptr;
_baro_listener_to_node[i] = UINT8_MAX;
_baro_listeners[i] = nullptr;
_mag_listener_to_node[i] = UINT8_MAX;
_mag_listeners[i] = nullptr;
}
_rc_out_sem = hal.util->new_semaphore();
debug_uavcan(2, "AP_UAVCAN constructed\n\r");
}
這些變量在構造函數中賦值爲空或空閒,_gps_nodes[]在AP_UAVCAN.cpp的gnss_fix_cb函數中被調用的find_gps_node函數賦值。
AP_GPS::GPS_State *AP_UAVCAN::find_gps_node(uint8_t node)
{
// Check if such node is already defined
for (uint8_t i = 0; i < AP_UAVCAN_MAX_GPS_NODES; i++) {
if (_gps_nodes[i] == node) {
return &_gps_node_state[i];
}
}
// If not - try to find free space for it
for (uint8_t i = 0; i < AP_UAVCAN_MAX_GPS_NODES; i++) {
if (_gps_nodes[i] == UINT8_MAX) {
_gps_nodes[i] = node;
return &_gps_node_state[i];
}
}
// If no space is left - return nullptr
return nullptr;
}
find_gps_node函數完成兩個功能,一、如果_gps_node[]中有存放GPS信息源的節點ID,則返回,與節點ID對應的_gps_node_state[]的指針。二、如果_gps_node中並沒有存放GPS信息源的節點ID,則遍歷_gps_node[]中處於空閒的成員,將GPS信息源的節點ID賦值給找到的第一個空閒的_gps_node[]。並返回與之對應的_gps_node_state[]指針。_gps_node[]與_gps_node_state[]是一一對應的。但_gps_node[]存放着哪個GPS信息源是不固定的,是程序運行時確定的,相應的_gps_node_state[]存放這那個GPS信息源的GPS數據也是不固定的,是程序運行時確定的。
_gps_node_taken[]、_gps_listener_to_node[]、_gps_listeners[]這些變量在AP_GPS.cpp的detect_instance函數中被調用的AP_UAVCAN中的函數賦有含義的值。
#if HAL_WITH_UAVCAN
// user has to explicitly set the UAVCAN type, do not use AUTO
case GPS_TYPE_UAVCAN:
dstate->auto_detected_baud = false; // specified, not detected
if (AP_BoardConfig_CAN::get_can_num_ifaces() >= 1) {
for (uint8_t i = 0; i < MAX_NUMBER_OF_CAN_DRIVERS; i++) {
if (hal.can_mgr[i] != nullptr) {
AP_UAVCAN *uavcan = hal.can_mgr[i]->get_UAVCAN();
if (uavcan != nullptr) {
uint8_t gps_node = uavcan->find_gps_without_listener();
if (gps_node != UINT8_MAX) {
new_gps = new AP_GPS_UAVCAN(*this, state[instance], nullptr);
((AP_GPS_UAVCAN*) new_gps)->set_uavcan_manager(i);
if (uavcan->register_gps_listener_to_node(new_gps, gps_node)) {
if (AP_BoardConfig_CAN::get_can_debug() >= 2) {
printf("AP_GPS_UAVCAN registered\n\r");
}
goto found_gps;
} else {
delete new_gps;
}
}
}
}
}
}
return;
#endif
附錄
#define AP_UAVCAN_MAX_GPS_NODES 4
#define AP_UAVCAN_MAX_LISTENERS 4
AP_BoardConfig_CAN::get_can_num_ifaces(),返回啓用的CAN接口總數。