分类 UAV 下的文章

APM总结

总结一下APM相关的知识,方便以后的查阅.

常用网站

Mavlink相关

APM初始设置

  1. APM接线图

  2. 安装固件

  3. 加速度计校准,包括校准加速度计和校准水平。

  4. 罗盘注意选择内置罗盘、外置罗盘或双罗盘,在现场校准的时候是上下左右360°旋转,采集1000左右个点,GPS点再水平面的上方,所有的点组合为一个球形

  5. 遥控器校准:CH1:横滚;CH2:俯仰;CH3:油门;CH4:偏航,注意CH2的通道与控制杆方向正好相反,富斯遥控器设置6个档位

  6. 飞行模式设置

  7. 故障保护,设置电池没电和电台距离太远时怎么办


暂时先写这些,以后在进行补充。

GPS--构造你所需要的GPS

需求

现有的GPS数据已经封装好了,再将其还原成GPS传感器出来的数据

基础知识

GPS模块输出信息可能分为几种格式:

  • GGA:时间、位置、定位类型

  • GLL:UTC时间、经度

  • GSA:GPS接收机操作模式、定位使用的卫星、DOP值

  • GSV:可见GPS卫星信息、仰角、方位角、信噪比(SNR)

  • RMC:时间、日期、位置、速度

注意:输出的信息、频率与设置有关

GGA
这里介绍一下GGA的格式

在定位没有成功时,输出的样例数据
$GPGGA,,,,,,0,00,99.99,,,,,,*18

异或校验

将所有的异或校验代码写出来了,得到的结果和例子中的结果比较就是不对,浪费了好多时间发现是进制不对,我也是醉了。还是经验不够啊。
重点是校验出来的结果一定要是十六进制
贴一下代码:

public static void check(string stringToCalculateTheChecksumOver)
    {
        byte checksum = 0;    //0异或任何数还是任何数
        foreach (byte b in stringToCalculateTheChecksumOver)
        {
            checksum ^= b;
        }
        //输出十六进制
        Console.WriteLine(checksum.ToString("X2"));
    }

以上就是校验的代码,GPS捏些数据都是从$开始(不包括$)到*结束(不包括*),比如

    string temp = "GPGGA,162254.00,3723.02837,N,12159.39853,W,1,03,2.36,525.6,M,-25.6,M,,";
    Console.WriteLine(Get_CheckXor(temp));

我想应该够清楚了,以下是参考过的网站:
讲.NET Xor,,没怎么认真看
维基百科,ASCII,就是从这里发现的进制问题。。。。
NEMA data格式的数据介绍这个也是
后来找到的异或代码,不错

总结

以上就是GPS方面的阶段性总结。有问题欢迎交流。

Ardupilot学习(二)

3.3 理解ArduPilot线程

一旦你学会了ArduPilot库,是时候理解ArduPilot如何处理线程了。setuploop都是从Arduino继承过来的使得ArduPilot看起来像单线程的系统,事实上不是。
ArduPilot线程取决于板子是否支持,比如APM1APM2就不支持,所以用一个简单的定时器和回掉函数完成功能。PX4Linux支持丰富的实时Posix线程模型,所以被ArduPilot广泛使用。有一些线程的核心概念需要理解.

  • The timer callbacks 定时器回调

  • HAL specific threads HAL特定线程

  • driver specific threads 驱动特定线程

  • ardupilot drivers versus platform drivers ardupilot驱动和平台驱动

  • platform specific threads and tasks 平台特定线程和任务

  • the AP_Scheduler system 调度任务

  • semaphores 信号量

  • lockless data structures 数据结构

定时器回调
每一个平台在AP_HAL中都提供一个1KHZ的定时器。任何代码都可以注册这个定时器并且使用它。所有定时器功能被顺序调用,这是个非常原始的机制,但却非常有用。注册的定时器类似这样调用hal.scheduler->register_timer_process()

hal.scheduler->register_timer_process(AP_HAL_MEMBERPRROC(&AP_Baro_MS5611::_update));

以上代码来自MS5611AP_HAL_MEMBERPROC提供了一种方式来封装一个C++成员函数作为回调参数。当一段代码运行在1KHZ以下的时候,那么应当保持它的last_called和在没有足够时间的时候立即返回。你可以使用hal.scheduler->millis()hal.scheduler->micros函数来获得系统运行的时间。
HAL 特定线程
在支持多线程的平台,AP_HAL将创见多个线程来支持基本操作。例如,在PX4上,HAL将创建如下线程:

  • UART thread 读写UART

  • timer thread 支持1khz定时器功能

  • IO 线程,支持写入到SD卡EEPROMFRAM

浏览一下Scheduler.cpp看看哪些线程被创建和现成的优先级。如果你有一个Pixhawk,你可以现在设置掉是打印连接到nsh打印。波特率57600,连接成后,使用PS命令会得到如下输出:

在这个例子中你可以看到AHRS_Test线程,可以看到定时器线程的优先级181,UART线程为60,IO线程为59.线程的一种常见用途是安排缓慢任务而不中断自主驾驶任务。例如,AP_Terrain库需要能够写文件到MicroSD卡,方法就是调用hal.sdheduler->register_io_process(),如下方式调用

hal.scheduler->register_io_process(AP_HAL_MEMBERPROC(&AP_Terrain::io_timer));

这样就设置了AP_Terrain::io_timerIO线程有规律的调用,这意味着它是一个低优先级和适合存储IO的任务。这样的缓慢IO任务不能再定时器线程上调用,否则将会造成传感器数据的延迟。
驱动特定的线程
也可以创建特定驱动程序的线程,来支持异步处理程序。目前你创建的特定线程取决于平台,如果你的程序只在特定的板子上运行这是合适的。如果你想要运行在多种AP_HAL目标,你有两种选择:

  • 你可以使用Register_io_process()register_timer_process()调度来调整现有的定时器和IO线程

  • 你可以添加显得HAL接口来提供泛型的方式在多种平台去创建线程

驱动特定线程的一个例子是ToneAlarm 线程,在AP_HAL_Linux/ToneAlarmDriver.cpp文件中
ArduPilot驱动程序和平台驱动程序
你可以看到在ArduPilot中一些驱动重复了。这样做重复的原因是因为PX4项目已经提供一系列测试良好的硬件驱动,并且我们喜欢这种和PX4合作关系来发展和深入研究这些驱动。所以当我们构建ArduPilot for PX4,我们使用了PX4驱动的优势通过写一些晓得shim驱动。如果你看libraries/AP_inertialSensor/AP_inertialSensor_PX4.CPP你会看到shim驱动来询问px4哪个IMU驱动程序在这个板子上适用,并且自动使他们全部作为ArduPilot AP_InertialSensor库的小部分。因此,如果我们的板子上面有一个MPU6000,我们使用驱动非PX4平台的AP_InertialSensor_MPU6000.CPP驱动,结果是AP_InertialSensor_px4.cpp可以工作。
平台特定线程和任务
在一些平台上将会有若干个由开始线程创建的基本任务和线程。这些都是特定平台的,这里就介绍基于PX4的板子。上面的图中可以看到有一些任务不是AP_HAL_PX4启动的。他们是:

  • Idle 空闲任务,当没有其他事情的时候运行

  • init 用来初始化系统

  • px4io 处理与PX4协处理器间的通信

  • hpwork 基于PX4驱动处理线程

  • lpwork 基于低优先级工作处理线程

  • fmuservo 在FMU上处理通信输出PWM

  • uavcan 处理uavcan CANBUS协议

所有这些任务的启动都是通过启动脚本rc.APM script。脚本在PX4启动的时候运行,负责发现PX4板子型号,然后加载正确的任务和驱动。它是一个nsh脚本,类似于shell脚本。
AP_Scheduler 系统
AP_Scheduler系统主要用来在主线程里面分隔时间,同时提供一些简单的机制来控制每个操作执行多长时间。工作方式就是在loop循环函数中包含类似下面的代码:

  • 等待IMU数据到达

  • 在每个IMU之间调用一系列任务

有一个调度表,每个任务都是类似AP_Scheduler::Task这样的。

#define SCHED_TASK(func, _interval_ticks, _max_time_micros) SCHED_TASK_CLASS(Rover, &rover, func, _interval_ticks, _max_time_micros)

第一个数字代表的是调用频率,是通过ins.init控制的。在ins.init中使用的频率是50HZ,所以每个操作的间隔是20ms。结合上图说就是每50个周期,1s调用一次。第三个参数是该函数预计花费的最大时间。这通常用来避免执行太长时间,除非有足够的时间去运行这个函数。
AP_Scheduler表必须有以下特性:

  • 它们不应该阻塞(ini.update()除外)

  • 在飞行的时候不能调用Sleep函数

  • 他们应该能预测最坏的执行时间

信号量
当你有多个线程的时候,你应该确保两个两个线程共享的数据结构不会冲突。在ardupilot中有三种方式,分别是semaphores信号量Lockless data structures 无锁数据结构PX4 ORBAP_HAL信号量只是包装了在特定平台上的任何可用信号量系统,并且提供了一种简单的互斥机制。例如,I2C驱动可以询问I2C总线信号量来确保同一时间只有一个I2C设备。
无锁数据结构
无锁数据结构比信号量更加高效。有两个地方使用到了无锁数据结构

  • libraries/AP_InertialSensor/AP_IertialSensor_MPU9250.CPP中的共享数据结构

  • 在许多地方使用的环形缓冲区。如libraries/DataFlash/DataFlash_File.CPP

PX4 ORB
ORB全称Object Request Broker是阻止数据从一个地方到另一个地方的一种方式,使用的是发布订阅模型,在多线程的环境中是安全的。ORB提供了一种很好的方式来声明共享的结构。两种常见的和PX4驱动通信的方式:

  • ioctl 调用(见 AP_HAL_PX4/RCOutput.cpp

  • /dev/xxx read/write 调用(见_timer_tickAP_HAL_PX4/RCOutput.cpp

3.4 Uart and the Console

很多组件都依赖UARTS,通常被用来调试输出、遥测、GPS模块或其他。
5个UART

  • uartA--打印(console),使用usb,运行Mavlink解析

  • uartB--第一个GPS

  • uartC--初级遥感(在pixhawk上是第一个电台,在apm上市第二个电台)

  • uartD--次级遥感,在Pixhawk上是第二个电台

  • uartE--第二个GPS

有些uart具有双重角色。例如有个参数SERIAL2PROTOCOL可以把uartD从Mavlink方面改为Frsky telemetry
libraries/AP_HAL/examples/UART——test例子可供学习
调试模式
除了这5个Uarts还有一个调试模式,如下

#if HAVE_OS_POSIX_IO
::printf("Hello console\n");
#endif

AP_HAL/AP_HAL_Boards.h中检查HAVE_OS_POSIX_IO设置,如果有,就可以使用::print了。在Pixhawk上,使用hal.console->printf()调试USB,使用::printf()进入专门的调试模式
Uart函数

3.5 RC输入和输出

RC输入是任何自动驾驶仪的关键部分,给了驾驶员控制权限,使得可以改变飞行模式,还可以辅助其他设备控制如摄像头等。Ardupilot支持多种类型的RC输入,这取决于具体的板子类型:

可用的通道数取决于板子上的特定硬件。
RC输出是如何控制舵机和点击。可用输出通道的数量也是取决于特定的板子,RC输出默认为50HZ pwm,但可以配置。例如,直升机代码设置的电动机输出以高得多的速度来驱动ECS - 通常超过400Hz的。

AP_HAL RC输入对象
hal.rcin为板子提供了当前正在接收通道值得低级别访问,用微秒的形式返回PWM值。可以浏览libraries/AP_HAL/examples/RCIput/RCInput.cpp获得更多信息。
AP_HAL RC输出对象
AP_HAL RC输出对象给了所有输出通道的低级别控制,具体的实现取决于板子,浏览libraries/AP_HAL/example/RCOutput/RCOutput.cpp查看
RC_Channel对象
以上hal.rcinhal.rcout都是低级别的函数,高级别的处理RC输入和输出的成为RC_Channel,这个对象使用用户配置文件(min/max/trim)配置每个通道,以及对辅助通道的支持,输入输出比例等
浏览libraries/RC_Channel/examples/RC_Channel/RC_Channel.cpp查看信息。
RC_Channel_aux对象
RC_Channel_auxRC_Channel的子类。可以添加一些额外的功能来满足用户的需要,比如用户想要通道6变为roll控制相机,他们可能会设置RC6_FUNCTION为21,意味着rudder,另一个库可能会说

RC_ChannelAux::set_servo_out(RC_Channel_aux::k_rudder,4500);

Storage and EEPROM

ArduPilot的每个板子都支持某种形式的永久数据存储,用来保存用户参数、航点信息、任务数据等等。有四种基本的方式提供对存储器的访问:

  • AP_HAL::Storage object和 hal.storage

  • StoreageManager库hal.storage在更高级别的抽象层上工作

  • DataFlash存储版上日志

  • Posix IO传统文件系统

其他需要存储的功能库都是建立在这四个之上的,比如AP_Param库用来存储用户参数,建在StorageManager,基于AP_HAL::StorageAP_Terrain库存储地形数据基于Posix IO
The AP_HAL::Storage library
AP_HAL::Storage对象在所有平台上都可以使用,不同的板子存储数据的大小不一样,所有代码都隐藏在AP_HAL::Storage API中。hal.storage API非常简单,只有三个函数

  • init() 启动存储系统

  • read_block 读取字节数据

  • Write_block 写字节数据

提供这个简单API是鼓励开发者使用StorageManager,而不是hal.storage。可用存储的大小在AP_HAL/AP_HAL_Boards.hHAL_STORAGE_SIZE设置。
The StorageManager library
hal.storage API使得把ArduPilot移植到新的板子变得简单,但实际使用可用存储的时候不方便。对于此,我们有StorageManager,提供了四种类型 的数据存储

  • parameters

  • fence points

  • waypoints

  • rally point

这些在libraries/StorageManager/StorageManager.cpp中都有介绍。在libraries/StorageManager/examples/StorageTest.CPP中有测试例子。


晕乎。。

ArduPilot源代码

简介

Doxygen是可以帮忙生成源代码文档,详细介绍见百度百科

安装Doxygen和graphviz

这里介绍linux下的安装,只需要几条命令就行:

git clone https://github.com/doxygen/doxygen.git
cd doxygen

mkdir build
cd build
cmake -G "Unix Makefiles" ..//注意两个点之前有空格,提示没有cmake,安装 sudo apt install cmake
make

make install //没有权限的话使用sudo

过程还是非常简单的,所有命令一步步下来就行了。
还得需要安装一个graphviz,一条命令

sudo apt-get install graphviz

运行脚本

README文档中写:

Run the build-libs script first,then the project you're interested in.

直接运行会有一些小问题,提示:

根据提示,运行

doxygen -u defult
//然后运行
sudo ./build-libs.sh
sudo ./build-apmrover2.sh

成功

编译生成固件

在生成固件的时候可能会出现问题,尝试
git submodule init
git submodule update

编译生成pixhawk固件
make px4-v2

这里需要注意的是,最新版本的ArduPilot已经不再支持apm了,如果需要下载支持Apm的源代码,需要下载以前的版本(我说呢,make命令不管用)。


ArduPilot系列学习(一)

所有ArduPilot文章来自于这里

1-欢迎加入ArduPilot 开发者网站

捡主要的说了

  1. Ardu来源于Arduino的一部分,原始的APM1基于Arduino平台,但我们现在已经比Arduino环境走的远了,并且不再使用Arduino运行库。ArduPilot的时间线从这里看。

  2. 我们支持的板子很多,包括PixhawkAUAV-X2Erle-BrainNAVIO+等。ArduPilot源代码是写在AP-HAL硬件抽象层上面,这使得能够支持广泛的自动驾驶板。看这里寻求更多帮助。

  3. Arduino系统由好几个不同的项目组成,下面列出

    • DroneKit -运行在自动驾驶仪、手机或者云端的app

    • Plane -自动驾驶飞机(Autopilot for planes)

    • Copter - 自动驾驶直升机

    • Rover - 自动驾驶车

    • Mission Planner - 地面站,使用C#写的

    • APM Planner 2.0 使用QTC++写的

    • MavProxy - 命令行或脚本地面站,主要由开发人员使用

    • MinimOSD 在屏幕上显示飞行数据

    • AndroPilot Android地面站

    • DroneAPI 协处理器和供网络应用程序使用的API

    • DroidPlanner android地面站

    • QGroundControl 也是使用QT库C++写的地面站

    • PX4 当运行在PX4FMU时使用的底层库

    • Mavlink 飞控协议

  4. 主要的开发语言和工具
    主要是使用C++开发的,支持工具使用的大部分是Python.主要的车辆代码用Arduino写的.PDE文件,PDE文件作为.CPP文件的预处理。

2-Working with the ArduPilot Project Code

主要介绍Git方面,从哪里获取代码和如何提交代码
ArduPilot代码地址Mission Planner代码地址

3- 学习ArduPilot代码库

### 3.1 简介
ArduPilot代码库大约70万行代码,如果熟悉C++会很快。
#### 3.1.1 教程步骤

  • 简介和代码结构

  • 草图结构

  • ArduPilot线程

  • UARTs和控制台

  • RC输入和输出

  • 存储和EEPROM管理

  • 车辆代码

    #### 3.1.2 简介和代码结构

    1. 基本结构

基本的ArduPilot结构被分成5个部分

  • vehicle directories

     定义每个车辆(Vehicle)类型的固件顶层目录,目前有四种-plane、rover、copter和AntennaTracker,和`.CPP`文件一起,都有一个`Make.inc`文件,`Make.inc`文件中列出了库的依赖。`Makefile`文件在构建(build)时候读取这个文件创建`L`和`l`标志

    • AP_HAL
      硬件抽象层使得我们能够将Ardupilot代码放到不同的平台。最顶层的在libraries/AP_HALAP_HAL定义了特定板子的接口。AP_HAL_XXX表示支持特定的类型,比如AP_HAL_AVR表示支持AVR板子,AP_HAL_PX4支持PX4板子等等。

    • libraries

    • tools directories
      杂项支持目录。里面有自动测试工具等

    • external support code
      在一些平台上需要一些外部代码,就在这里存放

      • PX4NuttxPX4板子上的核心Nuttx实时操作系统

      • PX4Firmware 基于Px4板子的中间件和驱动程序

      • uavcanardupilotCANBUS实现

      • mavlink mavlink协议和生成器

    1. 构建系统
      构建系统基于Make,但也支持老师的Arduino IDEMakefiles文件都在mk/diretory中,为每一个板子都定义了规则
      要构建特定类型的车辆,你必须使用make TARGET命令,其中TAEGET是板子类型,比如按下面方式使用:

      对于每一个构建,你还可以添加额外的限定和做一个并行构建加快速度。例如,在Copter directory目录中,你可以

      make apm2-octa -j8
      意味着在apm2上做了一个8路并行构建,你可以进入这里寻求更快的构建

      一些板子支持make完成后上传固件,比如

      make px4-v2-upload

    将会上传固件进入Pixhawk
    也有一些好心人制作了特定板子的make命令,比如

    3.2 Sketches例程

    sketch是一个主程序,后缀为CPP。想要理解代码必须知道库API(library API)惯例(conventions),使用起来library 例子是一个好的方式。可以先看下面这几个例子

    例如,下面的代码将会构建并且安装AP_GPS例子到Pixhawk

    cd libraries/AP_GPS/examples/GPS_AUTO_Test
    make px4-clean
    make px4-v2
    make px4-v2-upload

    一旦你上传后,你可以通过连接控制台查看输出。在PX4板子上就是USB连接器,所以只要连接USB就可以连接Pixhawk
    如果你安装了mavproxy,你可以按如下方式在Linux连接Pixhawk

    mavproxy.py --setup --master /dev/serial/by-id/usb-3D_Robotics_PX4_FMU_v2.x_0-if00
    

    理解sketch例子代码
    比如分析GPS_AUTO_Test代码,可以看出

    • 声明了HAL变量
      const AP_HAL::HAL& hal = AP_HAL::get_HAL();

    • setup()loop()函数

    HAL参考
    使用AP_HAL 特性的每一个文件都需要去生命一个hal引用。这如上面的AP_HAL::HAL对象,他可以访问硬件的所有特定功能,比如打印消息到控制台,休眠和I2CSPI通信。
    实际的hal变量包含在特定的AP_HAL XXX libraries文件中,在每个文件中的引用提供了一个方便的方式来使用它
    最常用的hal函数是:

    • hal.console->()hal.console->printf_P()

    • hal.scheduler->millis()hal.scheduler->micros()来获得启动时间

    • hal.scheduler->delay()hal.scheduler->delay_microseconds()来延时一段时间

    • hal.gpio->pinMode()|hal.gpio->readhal.gpio->write()来获得GPIO

    • I2C权限变量 hal.i2c

    • SPI权限变量hal.spi

    setup()和loop()函数
    每个sketch都有一个setuploop函数。setup在板子boot的时候调用。实际调用来自每个板子的HAL,所以主函数main()被写在HAL中,在板子特定的启动条件完成后调用setup()
    setup函数只被调用一次,通常初始化库。在setup()完成之后,loop()函数被调用,sketch的主要工作都在loop函数中。请注意到setuploop只是复杂代码的冰山一角,虽然看起来是单线程的,但实际上有大量线程实时启动。
    AP_HAL_MAIN() macro
    在每个sketch的地步有这样一行代码

    AP_HAL_MAIN();
    //我的是这样的
    AP_HAL_MAIN_CALLBACKS(&XX);

    这是HAL macro来声明Main函数,和板级初始化一块运行。

    代码写的很糙,大神们可以去贡献代码了

    第一部分结束。