0
点赞
收藏
分享

微信扫一扫

UAVCAN速成大法

茗越 2022-03-11 阅读 99
c++

1.UAVCAN基本概念

1.1框架

  • 理念

UAVCAN设计理念是为泛载具、机器类应用提供基础的,非领域限定的一种通信机制,并为该类应用中大量使用的设备定义了通用协议。UAVCAN不涉及到具体设备的应用。UAVCAN设计为低状态机架构,增强可靠性。

  • 通信机制

广播消息:节点以一个端口ID,发布信息;也可以订阅任一端口对应的信息;

服务消息:节点可以向另一个节点发送请求消息,类似于CS架构;

注:每个接入设备为一个节点(node),消息及协议以端口(port)区分。广播消息端口(message--使用subject identifier)和服务消息端口(service--使用service identifier),统称为端口(port identifier)。

  • 节点

单个设备可以占用并实现单个或多个节点。

  • DSDL语言(本文不涉及定制协议,未深入研究)

DSDL语言是一个类C语言的语义解释器,用于将这种类C语言的描述,使用python工具生成协议。UAVCAN由此定义协议,包括广播消息和服务消息。DSDL中可使用文件路径类似命名完成像C中include的操作,进而引用其它文件中定义的类型(不一定是这个目的,猜测),并由此完成类型定义与协议描述文件拆分(不一定是这个目的,猜测)。即DSDL所有协议均为静态生成。

协议文件名中显示定义了协议的端口和版本:

  • 协议端口定义

V1.0协议端口,分另为标准端口(UAVCAN定义),注册端口(各领域自定义,UAVCAN/SIG审核),开放端口。

V0协议端口

1.2底层传输协议

底层传输协议V0(旧版本协议,当前设备here3和CUAV的GPS使用)

仅描述使用CAN使用发送通道的情况,不描述使用UDP、serial等。

支持CAN2.0,使用扩展帧,最大包负载长度8字节。

支持CAN FD,使用扩展帧,最大包负载长度64字节。(未尝试)

  • 帧头占用扩展帧,定义如下:

Priority优先级:0为最高优先级,31最低,与CAN基础协议定义一致

Message type ID消息ID:即协议中的消息ID,查阅协议具体定义。

Service type ID服务ID:即协议中服务ID,查阅协议具体定义。

Node ID节点ID:设备节点号,0为保留ID,代表未知节点或所有节点。该节点ID在自动分配ID的过程中,未分配成功时为0。

Discriminator区分码:在ID自动分配的过程中,未完成分配前,所有未分配的节点ID为0,即会产生ID重复冲突。为避免这种情况,每个设备在未被分配时,会随机生成一个区分码,并广播自己的12位设备唯一码的前6位,请求分配员给自己分配ID,分配成功后,一般不再发送匿名广播消息(anonymous message frame)。

  • 帧尾

单帧数据量太小,为适应多帧发送,便于拼接,在帧尾增加拆分信息。

发送单帧时,起始与结束标志均为1,翻转标志为0。

发送多帧时,第一帧数据中前两个字节为CRC,起始标志为1,结束标志为0,翻转标志为0。

中间数据帧起始标志为0,结束标志为0,翻转标志翻转。

尾帧数据帧起始标志为0,结束标志为1,翻转标志翻转。

  • 底层传输协议V1.0(未深入研究,思路体与V0一致)

 

1.3节点ID动态分配

待分配节点逻辑:

分配示例:

Time   CAN ID     CAN data field

1.117  1EEE8100   01 44 C0 8B 63 5E 05 C0

1.117  1E000101   00 44 C0 8B 63 5E 05 C0

1.406  1EEBE500   00 F4 BC 10 96 DF 11 C1

1.406  1E000101   05 B0 00 44 C0 8B 63 81

1.406  1E000101   5E 05 F4 BC 10 96 DF 21

1.406  1E000101   11 41

1.485  1E41E100   00 A8 BA 54 47 C2

1.485  1E000101   29 BA FA 44 C0 8B 63 82

1.485  1E000101   5E 05 F4 BC 10 96 DF 22

1.485  1E000101   11 A8 BA 54 47 42

当前CAN总线上有两个节点,其中一个是分配员,一个是待分配节点。

分配员是1E000101,其1E000101中,01表示节点ID是1;其1E000101中,表示协议类型是1,即uavcan.protocol.dynamic_node_id.Allocation协议(https://legacy.uavcan.org/Specification/7._List_of_standard_data_types/  中直接搜索Allocation);

待分配节点是1EEE8100,其1EEE8100中,EE80为Discriminator区分码,是一个随机码(防止多个节点冲突,见上文),1是广播消息ID的低2位,即uavcan.protocol.dynamic_node_id.Allocation协议。

协议中删除注释后,如下

uint16 MAX_REQUEST_PERIOD_MS = 1000 待分配者最大请求间隔时间

uint16 MIN_REQUEST_PERIOD_MS = 600 待分配者最小请求间隔时间

uint16 MAX_FOLLOWUP_DELAY_MS = 400 不清楚,猜测为分配员多帧间间隔要求

uint16 MIN_FOLLOWUP_DELAY_MS = 0

uint16 FOLLOWUP_TIMEOUT_MS = 500 分配员最大跟随延迟即待分配者发送请求后,分配员须在该时限内回复

uint8 MAX_LENGTH_OF_UNIQUE_ID_IN_REQUEST = 6 单帧最大唯一ID发送数量

uint7 ANY_NODE_ID = 0 匿名ID

uint7 node_id

bool first_part_of_unique_id

 uint8[<=16] unique_id

  • 分析第一条消息

1.117  1EEE8100   01 44 C0 8B 63 5E 05 C0

表示 uint7 node_id 为0    

bool first_part_of_unique_id 为真,即当前数据为待分配节点自身16位唯一码中的第一部分,也就是前6位

  • 分析第二条消息

1.117  1E000101   00 44 C0 8B 63 5E 05 C0

分配员回复相同的唯一ID,让待分配节点发送下一段唯一码

  • 分析第三条消息

1.406  1EEBE500   00 F4 BC 10 96 DF 11 C1

待分配节点发送第二部分节点ID

  • 分析第四条消息

1.406  1E000101   05 B0 00 44 C0 8B 63 81

1.406  1E000101   5E 05 F4 BC 10 96 DF 21

1.406  1E000101   11 41

分配员回复,这是一个多帧消息包,唯一码已经拼装好为12位。

1.406  1E000101   05 B0 00 44 C0 8B 63 81

1.406  1E000101   5E 05 F4 BC 10 96 DF 21

1.406  1E000101   11 41

多帧CRC

  • 分析第五条消息

1.485  1E41E100   00 A8 BA 54 47 C2

待分配节点发送第三部分节点ID

  • 分析第六条消息

1.485  1E000101   29 BA FA 44 C0 8B 63 82

1.485  1E000101   5E 05 F4 BC 10 96 DF 22

1.485  1E000101   11 A8 BA 54 47 42

其中标红部分为节点唯一码

1.485  1E000101   29 BA FA 44 C0 8B 63 82

1.485  1E000101   5E 05 F4 BC 10 96 DF 22

1.485  1E000101   11 A8 BA 54 47 42

0xFA为0x7D << 1 ,即分配员为该节点分配ID为125(0x7D)

2.UAVCAN-V0(注意是老版本)移植AOA-F(imx6-linux)

2.1代码收集

为适配here3,查阅其使用说明,发现该设备直接与开源飞控连接,使用飞控进行配置。为避免错误代码版本,于是直接拉取开源飞控git库。git库拉取很慢,发现网友使用免费代理:GitHub Proxy 代理加速

使用方法很简单:

git clone https://ghproxy.com/https://github.com/ardupilot/ardupilot.git

对于.gitmodule,将里面的链接全部替换即可,将所有子模块都更新好进入下一步。

2.2UAVCAN交叉编译

阅读readme后,按步骤操作(肯定是不成功的,不要踩雷了)

成功的步骤是,在zlg-ubuntu18.04虚拟机中,wsl+vscode也可以

mkdir build

cd build

使用vim打开source /opt/poky/1.7/enviriment*****

将其中export  $PYTHONHOME删除,不使用该工具链的python,使用虚拟机自带的,python2.7.3。工具链中python并不完整,无法完成编译。

source /opt/poky/1.7/enviriment*****

最后运行

 cmake .. -DPYTHON_EXECUTABLE=/usr/bin/python2.7 

-DCMAKE_INSTALL_PREFIX=./install

make

make install

到此编译完成

​​​​​​​2.3Libuavcan_linux交叉编译

https://ghproxy.com/https://github.com/UAVCAN/libuavcan_linux

阅读readme后,按步骤操作(肯定是不成功的,不要踩雷了)

修改CMakelist.txt,增加

link_directories(/mnt/d/project/AOA-F/temp/ardupilot-direct/modules/uavcan/build/install/lib/)

include_directories(/mnt/d/project/AOA-F/temp/ardupilot-direct/modules/libuavcan_drivers/posix/include)

include_directories(/mnt/d/project/AOA-F/temp/ardupilot-direct/modules/uavcan/build/install/include)

替换自己的路径

cmake .. -DUAVCAN_LIB=uavcan

make

​​​​​​​2.4工具使用

使用编译生成的uavcan_dynamic_node_id_server

./uavcan_dynamic_node_id_server   01  can0  -c 1 -s  ./test_output

启用后待分配节点即可完成分配  

Cmakelist.txt如下,红色为修改部分

#

# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>

#

cmake_minimum_required(VERSION 2.8)

project(libuavcan_linux)

#

# Library (header only)

#

install(DIRECTORY include/uavcan_linux DESTINATION include)

set(CMAKE_VERBOSE_MAKEFILE on)

#

# Scripts

#

install(DIRECTORY scripts/

        USE_SOURCE_PERMISSIONS

        DESTINATION bin)

link_directories(/mnt/d/project/AOA-F/temp/ardupilot-direct/modules/uavcan/build/install/lib/)

include_directories(/mnt/d/project/AOA-F/temp/ardupilot-direct/modules/libuavcan_drivers/posix/include)

include_directories(/mnt/d/project/AOA-F/temp/ardupilot-direct/modules/uavcan/build/install/include)

#

# System dependecies

#

find_package(Threads REQUIRED)

#

# Finding libuavcan - it will be a target if we're running from the top-level CMakeLists.txt,

# otherwise try to find it in the system directories.

#

if (TARGET uavcan)

    message(STATUS "Using uavcan target; source dir: ${libuavcan_SOURCE_DIR}")

    set(UAVCAN_LIB uavcan)

    include_directories(${libuavcan_SOURCE_DIR}/include

                        ${libuavcan_SOURCE_DIR}/include/dsdlc_generated)

    message(STATUS "POSIX source dir: ${libuavcan_posix_SOURCE_DIR}")

    include_directories(${libuavcan_posix_SOURCE_DIR}/include)

else ()

    message(STATUS "Using installed uavcan library")

    find_library(UAVCAN_LIB uavcan REQUIRED)

    set(UAVCAN_LIB uavcan)

    message(STATUS "UAVCAN_LIB: ${UAVCAN_LIB}")

endif ()

#

# Applications - tests, tools.

#

include_directories(include)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -std=c++11")  # GCC or Clang

if(CMAKE_BUILD_TYPE STREQUAL "Debug")

    add_definitions(-DUAVCAN_DEBUG=1)

endif()

#

# Tests

# These aren't installed, an average library user should not care about them.

#

add_executable(test_clock apps/test_clock.cpp)

target_link_libraries(test_clock ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(test_socket apps/test_socket.cpp)

target_link_libraries(test_socket ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(test_node apps/test_node.cpp)

target_link_libraries(test_node ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(test_time_sync apps/test_time_sync.cpp)

target_link_libraries(test_time_sync ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(test_system_utils apps/test_system_utils.cpp)

target_link_libraries(test_system_utils ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(test_posix apps/test_posix.cpp)

target_link_libraries(test_posix ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(test_dynamic_node_id_client apps/test_dynamic_node_id_client.cpp)

target_link_libraries(test_dynamic_node_id_client ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(test_file_server apps/test_file_server.cpp)

target_link_libraries(test_file_server ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(test_multithreading apps/test_multithreading.cpp)

target_link_libraries(test_multithreading ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

#

# Tools

#

add_executable(uavcan_monitor apps/uavcan_monitor.cpp)

target_link_libraries(uavcan_monitor ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(uavcan_nodetool apps/uavcan_nodetool.cpp)

target_link_libraries(uavcan_nodetool ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

add_executable(uavcan_dynamic_node_id_server apps/uavcan_dynamic_node_id_server.cpp)

target_link_libraries(uavcan_dynamic_node_id_server ${UAVCAN_LIB} rt ${CMAKE_THREAD_LIBS_INIT})

install(TARGETS uavcan_monitor

                uavcan_nodetool

                uavcan_dynamic_node_id_server

        RUNTIME DESTINATION bin)

        

举报

相关推荐

0 条评论