Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

Dubbo入门简介

发表于 2020-02-24

Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

应用背景

请参考背景.

应用需求

请参考需求.

Dubbo架构

请参考架构.

服务配置

请参考应用.

参考链接

  1. Apache Dubbo,by apache.

Matlab树莓派硬件支持平台的搭建

发表于 2020-02-19 | 更新于 2021-05-19

在今天全球强调科研创新的年代,为何科学的进步与上个世纪相比,却明显进步缓慢呢?也许有人反驳,当今庞大的科研人员,层出不穷的科研成果,极大的物质财富,难道不是科学技术的进步带来的吗?与上个世纪相比,哪里进步缓慢了呢?诚然,当前科技在进步在繁荣,但这种进步繁荣是应用科学的繁荣,而不是基础科学的繁荣。如果将科学比作一棵大树,那么基础科学就是树干,枝干和树叶就是应用科学。树干的粗细决定了树枝和树叶的繁荣,不幸的是,当前基础科学已经很久没有大的进步了。基础科学的进步靠牛顿、麦克斯韦、爱因斯坦这样的天才,而应用科学的进步则靠广大的普通科研人员。那么作为一名普通的从事应用科学研究的科研人员,如何才能有所创新有所进步呢?

作为一名普通的科研人员,可能经常会有一闪而过的灵光。然而要将这一闪而过的灵光变成切实可行的创新是一个痛苦的过程。这一闪而过的灵光可能涉及很多学科知识,而大部分科研人员不是全才,可能仅在某一方面有过人之处,那么如何试验验证这一灵光就成了大难题。幸运的是,有了Matlab及其推广的基于模型的设计思想,未来应用科学方面的科研创新将不再困难。

有人说,Matlab除了不会生孩子,其他都能干。诚然,Matlab就是广大科研人员的神兵利器。Matlab或许比不上某些领域的专业软件,但胜在全面,该有的都有。科研人员只需掌握它,就可解决至少80%的问题,极大地提高科研效率。

最近在研究各种控制算法,需要安装树莓派和PX4的硬件支持包,发现最新的Matlab 2019b安装PX4硬件支持包比较方便,但无法安装树莓派硬件支持包,而Matlab 2018b则没有这样的问题。

Matlab 2019b无法下载树莓派硬件支持包的问题,可通过Matlab官方提供的下载工具解决,下载地址为Download Hardware Support Packages and Optional Features。

参考链接

  1. Simulink与树莓派-HIL(硬件在环)平台搭建,by Tomato.
  2. AUTOSAR架构深度解析,by 末离.
  3. Download Hardware Support Packages and Optional Features,by mathworks.

基于模型的设计思想

发表于 2020-02-13 | 更新于 2020-02-15

基于模型的设计(Model-Based Design,简称MBD)是一种数学及可视化的方法,可以用来处理复杂控制系统、信号处理及通讯系统的设计。基于模型的设计可以用在运动控制、工业设计、航天以及车辆应用中。基于模型的设计也是嵌入式系统设计的方法论。

基于模型的设计类似于基于组件的图形用户界面开发,可极大地提高开发的效率,并保证程序的健壮性。

简介

基于模型的设计是一种较有效率的设计方式,在支援开发过程(V模型)的同时,在设计过程中建立了沟通用的共同框架。若用这种方式设计控制系统,开发会分为以下四步骤:

  • 为受控体建模。
  • 配合受控体,分析及合成适合的控制器。
  • 针对控制器及受控体进行仿真。
  • 整合上述的步骤来布署控制器。

基于模型的设计和传统的设计方法论有很大的不同。设计者在使用基于模型的设计时,不需使用复杂的架构以及繁多的软件代码,只需利用基于模型的设计来定义系统模型,再配合连续及离散的架构方块来产生进阶的机能特性。使用仿真工具建立的模型可以进行快速应用程序开发、软件测试和验证。不但强化了测试以及验证的程序。有些情形下,可以将这个新的设计方法配合硬件在环的仿真,测试系统的动态效应,不但速度更快,也比传统的设计方法论更加有效率。

基于模型设计的步骤

基于模型设计的主要步骤如下:

  1. 受控体建模:受控体建模可以以资料驱动(data-driven)为基础,也可以依照首要原则(first principle)建模。资料驱动的建模会配合系统识别或是类似的技术。系统识别会先取得系统在真实世界中的输入输出资料,并进行处理,再配合数学算法来识别系统的模型。在系统识别后,就可以针对受控体设计适合的控制器。首要原则驱动的建模是先找到受控体的统御方程式,再创建方块图模型来实现上述的统御方程式。实体建模(physical modeling)就是一种首要原则驱动的驱动建模方式,模型中会包括许多互相连结的方块,对应实际受控体中的各个元件。
  2. 控制器分析及合成:会使用步骤1得到的数学模型来确认模型的动态特性,再依这些特性设计符合特性的控制器。
  3. 离线的仿真及实时仿真:会分析动态系统在复杂时变输入下的反应特性。这可以将受授体的简易线性非时变模型和控制器一起进行仿真,也可以用受授体的非线性模型和控制器进行仿真。仿真有助于找到规格、需求以及建模时的错误,而不是在之后实际设计控制器时才发现。实时仿真可以用步骤2的控制器进行代码自动生成(automatically generating code)来达到。代码可以布署在特殊的实时原型电脑中,这个电脑可以执行程式并且控制受控体的运作。假如无法取得受控体的原型,或是配合原型的测试有危险性或是太过昂贵,可以配合受控体模型进行自动代码生成。之后可以将代码布署到另一台电脑上,这台电脑和执行控制体的电脑相连。因此可以实时的测试控制器,不过控制的不是实际的受控体,而是实时仿真的受控体模型。
  4. 布署控制器:理想上让步骤2的控制器进行代码自动生成,即可布署控制器。不过一开始时,控制器在实际系统上的性能会和仿真时的性能不同,此时可以用迭代除错方式,分析实际系统上的结果,依分析结果更新控制器模型。配合基于模型设计的工具,可以在统一化可视环境下,进行上述的迭代除错。

优点

基于模型的设计相较于传统开发方式的优点有:

  • 基于模型的设计提供一个共同的开发环境,有助于不同的开发团队之间的一般性沟通、资料分析以及系统验证。
  • 工程师可以在系统设计早期定位出错误并且修正错误,此时系统修改造成的时间冲击及财务影响都是最小的。
  • 设计可以复用,有助于提升机能及衍生系统的扩充能力。

工具

支持MBD开发的工具主要有:

  • Matlab/Simulink

参考链接

  1. 基于模型的设计,by wikipedia.
  2. Simulink代码生成C/C++,by 小二黑.
  3. 基于模型设计——电力电子的利器,by 陈老四.

策略梯度方法笔记

发表于 2020-02-10 | 更新于 2021-06-16

使用强化学习实现机器人的连续控制,策略梯度方法是首选。下面即对强化学习中策略梯度方法进行总结。

核心概念

免模型学习(Model-Free) vs 有模型学习(Model-Based)

不同强化学习算法最重要的区分点之一就是智能体是否能完整了解或学习到所在环境的模型。 环境的模型是指一个预测状态转换和奖励的函数。

有模型学习最大的优势在于智能体能够 提前考虑来进行规划,走到每一步的时候,都提前尝试未来可能的选择,然后明确地从这些候选项中进行选择。智能体可以把预先规划的结果提取为学习策略。这其中最著名的例子就是 AlphaZero。这个方法起作用的时候,可以大幅度提升采样效率 —— 相对于那些没有模型的方法。

有模型学习最大的缺点就是智能体往往不能获得环境的真实模型。如果智能体想在一个场景下使用模型,那它必须完全从经验中学习,这会带来很多挑战。最大的挑战就是,智能体探索出来的模型和真实模型之间存在误差,而这种误差会导致智能体在学习到的模型中表现很好,但在真实的环境中表现得不好(甚至很差)。基于模型的学习从根本上讲是非常困难的,即使你愿意花费大量的时间和计算力,最终的结果也可能达不到预期的效果。

使用模型的算法叫做有模型学习,不基于模型的叫做免模型学习。虽然免模型学习放弃了有模型学习在样本效率方面的潜在收益,但是他们往往更加易于实现和调整。

同策略(on-policy) vs 异策略(off-policy)

异策略(off-policy)的代表算法Q-learning,亦称SarasMax,其采样的策略(用于执行,behavior policy) 和更新Q值的策略(用于评估,target policy)不一样,行为策略为贪心策略,而target policy为确定性策略,即选择最Q值最优的action。

同策略(on-policy)的代表算法Sarsa,亦称on-line Q-learning,其采样的策略(用于执行,behavior policy) 和更新Q值的策略(用于评估,target policy)一样,行为策略和目标策略均为贪心策略。Sarsa的每次Q值更新需要知道前一步的状态(state)、前一步的动作(action)、奖赏值(reward)、当前状态(state)、将要执行的动作(action),由此得名Sarsa算法。

在线(online) vs 离线(offline)

在计算机科学中,在线机器学习是一种机器学习的方法,其中数据按顺序可用,并且用于在每个步骤中为将来的数据更新我们的最佳预测器,而不是通过学习生成最佳预测器的批处理学习技术 一次对整个训练数据集。 在线学习是机器学习领域中的一种常用技术,在该领域中,计算无法训练整个数据集是不可行的,因此需要核心算法。 它也用于算法必须动态适应数据中的新模式的情况下,或者在数据本身随时间而变的情况下(例如,股价预测)使用。 在线学习算法可能易于遭受灾难性干扰,这一问题可以通过增量学习方法来解决。

在机器学习中,采用离线学习的系统在初始训练阶段完成后不会改变其对目标函数的近似值。这些系统通常也是渴望学习的示例。

在在线学习中,只有一组可能的元素是已知的,而在离线学习中,学习者则知道这些元素的标识以及它们显示的顺序。

强化学习分类

强化学习简单分类

图1 强化学习简单分类

在机器人学习领域,目前主要有三类有效的免模型的深度强化学习算法:

  • TRPO,PPO
  • DDPG及其拓展(D4PG,TD3等)
  • Soft Q-Learning, Soft Actor-Critic

PPO算法是TRPO(Trust Region Policy Optimization)算法的近似,该算法更能适应大规模的运算,是目前最主流的DRL算法,同时面向离散控制和连续控制,在OpenAI Five上取得了巨大成功。但是PPO是一种on-policy的算法,也就是PPO面临着严重的sample inefficiency,需要巨量的采样才能学习,这对于真实的机器人训练来说,是无法接受的。

DDPG及其拓展则是DeepMind开发的面向连续控制的off policy算法,相对PPO 更sample efficient。DDPG训练的是一种确定性策略deterministic policy,即每一个state下都只考虑最优的一个动作。

Soft Actor-Critic (SAC)是面向Maximum Entropy Reinforcement learning 开发的一种off policy算法,和DDPG相比,Soft Actor-Critic使用的是随机策略stochastic policy,相比确定性策略具有一定的优势(具体后面分析)。Soft Actor-Critic在公开的benchmark中取得了非常好的效果,并且能直接应用到真实机器人上。

符号定义

下表给出强化学习常用符号定义。

符号 含义
$s \in \mathcal{S}$ 状态。
$a \in \mathcal{A}$ 动作。
$r \in \mathcal{R}$ 回报。
$S_{t}, A_{t}, R_{t}$ 一个轨迹中第t个时间步对应的状态、动作以及回报。我可能会偶尔使用$s_t,a_t,r_t$来代替。
$\gamma$ 折扣因子;用于惩罚未来回报中的不确定性;$0<γ≤1$。
$G_{t}$ 累积回报;或者说累积折扣回报;$G_{t}=\sum_{k=0}^{\infty} \gamma^{k} R_{t+k+1}$。
$P\left(s^{\prime}, r\vert s, a\right)$ 在当前状态s下采取动作a后转移到下一个状态 s′ 并得到回报 r 的概率。
$\pi(a\vert s)$ 随机策略(智能体行为逻辑);$\pi_{\theta}( .)$代表由θ参数化的策略。
$μ(s)$ 确定性策略;虽然也可以把确定性策略记为$π(s)$,但是采用一个不同的字母可以让我们更容易分辨一个策略到底是确定性的还是随机的。π或者μ都是强化学习算法要学习的目标。
$V(s)$ 状态-值函数衡量状态s的期望累积回报;$V_{w}( .)$代表由w参数化的状态-值函数。
$V^{\pi}(s)$ 当智能体遵循策略π时状态s的期望累积回报;$V^{\pi}(s)=\mathbb{E}{a \sim \pi}\left[G{t}\vert S_{t}=s\right]$
$Q(s,a)$ 动作-值函数,与状态-值函数类似,但是它衡量在状态s下采取动作a后的期望累积回报;$Q_{w}( .)$代表由w参数化的动作-值函数。
$Q^{\pi}(s, a)$ 与$V^{\pi}(s)$类似,当智能体遵循策略π时,在状态s下采取动作a后的期望累积回报;$Q^{\pi}(s, a)=\mathbb{E}{a \sim \pi}\left[G{t}\vert S_{t}=s,A_{t}=a\right]$
$A(s, a)$ 优势函数,$A(s,a)=Q(s,a)−V(s)$;可以认为优势函数是加强版本的动作-值函数,但是由于它采用状态-值函数作为基准使得它具有更小的方差。

策略梯度方法

强化学习的目标是为智能体找到一个最优的行为策略从而获取最大的回报。策略梯度方法主要特点在于直接对策略进行建模并优化。策略通常被建模为由θ参数化的函数$\pi_{\theta}(a | s)$。回报(目标)函数的值受到该策略的直接影响,因而可以采用很多算法来对θ进行优化来最大化回报(目标)函数。

回报(目标)函数定义如下:
$$ J(\theta)=E_{\tau \sim \pi_{\theta}} [R(\tau)]=\sum_{s \in \mathcal{S}} d^{\pi}(s) V^{\pi}(s)=\sum_{s \in \mathcal{S}} d^{\pi}(s) \sum_{a \in \mathcal{A}} \pi_{\theta}(a | s) Q^{\pi}(s, a) $$

其中$d^{\pi}(s)$代表由$\pi_{\theta}$引出的马尔科夫链的平稳分布(π下的在线策略状态分布)。

使用梯度上升方法,我们可以将参数 $\theta$ 往梯度 $\nabla_{\theta} J(\theta)$ 给出的方向进行改变从而去找到最优的 $\theta$ 使得其对应的策略 $\pi_{\theta}$ 能够给智能体带来最大的期望累积回报。

$$\theta_{k+1} = \theta_k + \alpha \left. \nabla_{\theta} J(\pi_{\theta}) \right|_{\theta_k}.$$

策略性能的梯度 $\nabla_{\theta} J(\pi_{\theta})$ ,通常被称为 策略梯度 ,优化策略的算法通常被称为 策略算法 。

策略梯度定理

$$\begin{aligned} \nabla_\theta J(\theta) &\propto \sum_{s \in \mathcal{S}} d^\pi(s) \sum_{a \in \mathcal{A}} Q^\pi(s, a) \nabla_\theta \pi_\theta(a \vert s) &\ &= \sum_{s \in \mathcal{S}} d^\pi(s) \sum_{a \in \mathcal{A}} \pi_\theta(a \vert s) Q^\pi(s, a) \frac{\nabla_\theta \pi_\theta(a \vert s)}{\pi_\theta(a \vert s)} &\ &= \mathbb{E}_\pi [Q^\pi(s, a) \nabla_\theta \ln \pi_\theta(a \vert s)] & \scriptstyle{\text{; 因为 } (\ln x)’ = 1/x} \end{aligned}$$

$\mathbb{E}{\pi}$代表$\mathbb{E}{s \sim d_{\pi}, a \sim \pi_{\theta}}$,下标表示遵循策略$\pi_{\theta}$(在线策略)时状态以及动作的分布。

深度确定性策略梯度 (DDPG)

DDPG(Lillicrap, et al., 2015)是深度确定性策略梯度(Deep Deterministic Policy Gradient)的缩写,是一个结合了DPG以及DQN的无模型离线演员-评论家算法。DQN(深度Q网络)通过经验回访以及冻结目标网络的方式来稳定Q函数的训练过程。原始的DQN算法只能在离散的动作空间上使用,DDPG算法在学习一个确定性策略的同时通过演员-评论家框架将其扩展到连续的动作空间中。

深度确定性策略梯度算法伪代码

图2 深度确定性策略梯度算法伪代码

近似策略优化PPO

DQN

SAC

参考链接

  1. 策略梯度方法,by Abracadabra.
  2. A (Long) Peek into Reinforcement Learning,by Lilian Weng.
  3. 第三部分:策略优化介绍,by spinningup.
  4. 深度强化学习研究笔记,by jackhuang.
  5. 异策略(Q-learning) v.s. 同策略(Sarsa),by MOMO.
  6. Online_machine_learning,by wikipedia.
  7. 最前沿:深度解读Soft Actor-Critic 算法,by Flood Sung.
  8. 重要性采样(Importance Sampling),by 时雨.
  9. TRPO论文推导,by Ja1r0.
  10. 强化学习进阶 第七讲 TRPO,by 天津包子馅儿.
  11. 强化学习–信赖域系方法:TRPO、PPO,by 秋曾万.
  12. 强化学习(8)——DQN,by 自由而无用.
  13. 理解策略梯度算法,by SIGAI.
  14. SAC论文解读以及简易代码复现,by 已注销.
  15. PPO(Proximal Policy Optimization)近端策略优化算法,by shura_R.
  16. Policy Gradient Algorithms,by lilianweng.
  17. TRPO论文推导,by Ja1r0.
  18. 第九章:连续动作空间的确定性策略,by anesck.

科学研究的标准流程

发表于 2020-02-09

科学研究是每一个科研人必备的技能,那么科学研究应如何入手呢?通常科学研究应遵循如下标准流程:

问题牵引

形式化定义问题

问题等价转换

建立模型

已有数学模型

类似数学模型

重建数学模型

模型求解

收集数据

求解模型

验证模型

模型预测

灵敏度分析

XML解析入门

发表于 2020-01-30

最近在研究编写飞行动力学模型,发现需要使用很多用于插值的数据,这些数据可以是一维向量、二维表格或三维数据。在代码中直接硬编码存储是不合适的,降低程序的灵活性。直接使用文本文档存储也不合适,这些插值数据明显具有结构化的特征。于是想到用XML来存储表示这些数据。下面总结介绍XML解析相关知识。

XML简介

可扩展标记语言(英语:Extensible Markup Language,简称:XML)是一种标记语言。标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。如何定义这些标记,既可以选择国际通用的标记语言,比如HTML,也可以使用像XML这样由相关人士自由决定的标记语言,这就是语言的可扩展性。XML是从标准通用标记语言(SGML)中简化修改出来的。它主要用到的有可扩展标记语言、可扩展样式语言(XSL)、XBRL和XPath等。

XML结构

XML定义结构、存储信息、传送信息。下例为小张发送给大元的便条,存储为XML。

1
2
3
4
5
6
7
<?xml version="1.0"?>
<小纸条>
<收件人>大元</收件人>
<發件人>小張</發件人>
<主題>問候</主題>
<具體內容>早啊,飯吃了沒? </具體內容>
</小纸条>

每个XML文档都由XML序言开始,在前面的代码中的第一行就是XML序言,。这一行代码会告诉解析器或浏览器这个文件应该按照XML规则进行解析。

但是,根元素到底叫<小纸条>还是<小便条>,则是由文档类型定义(DTD)或XML纲要(XML Schema)定义的。如果DTD规定根元素必须叫<小便条>,那么若写作<小纸条>就不符合要求。这种不符合DTD或XML纲要的要求的XML文档,被称作不合法的XML,反之则是合法的XML。

XML文件的第二行并不一定要包含文档元素;如果有注释或者其他内容,文档元素可以迟些出现。

XML解析器

C++类型XML解析器有:

  • Boost.PropertyTree - A property tree parser/generator that can be used to parse XML/JSON/INI/Info files. [Boost]
  • Expat - An XML parser library written in C. [MIT]
  • Libxml2 - The XML C parser and toolkit of Gnome. [MIT]
  • libxml++ - An XML Parser for C++. [LGPL2]
  • Mini-XML - A small XML parsing library written in ANSI C. [LGPL2 with exceptions]
  • PugiXML - A light-weight, simple and fast XML parser for C++ with XPath support. [MIT]
  • RapidXml - An attempt to create the fastest XML parser possible, while retaining useability, portability and reasonable W3C compatibility. [Boost]
  • TinyXML - A simple, small, minimal, C++ XML parser that can be easily integrating into other programs. [zlib]
  • TinyXML2 - A simple, small, efficient, C++ XML parser that can be easily integrating into other programs. [zlib]
  • TinyXML++ - A completely new interface to TinyXML that uses MANY of the C++ strengths. Templates, exceptions, and much better error * handling. [MIT]
  • Xerces-C++ - A validating XML parser written in a portable subset of C++. [Apache2]

推荐使用TinyXML2。

参考链接

  1. C++解析xml有什么好用的轮子?,by 知乎.
  2. awesome-cpp xml,by fffaraz.
  3. XML与C++对象的相互转化,by Mr_John_Liang.
  4. JSON与XML的区别比较,by SanMaoSpace.

软件开发文档的编写方法

发表于 2020-01-22 | 更新于 2022-07-07

软件开发文档是软件开发过程的输出产物。软件开发过程的不同阶段将产生不同的软件开发文档。例如:软件需求分析阶段将产生软件需求规格说明书,软件概要设计阶段将产生概要设计说明书,软件详细设计阶段将产生详细设计说明书。按照软件工程的原则,软件开发过程输出这些文档的目的是为了保障软件开发的质量,确保软件项目能够按时完成,并保质保量。下面重点介绍各类软件开发文档的编写方法。

软件过程模型

软件过程模型是软件过程的简化表示。典型的软件过程模型有:瀑布模型、增量式开发模型和面向服用的软件工程模型。以瀑布模型为例,其涉及的开发活动如图1所示。

瀑布模型

图1 瀑布模型

各个开发活动对应产出的软件开发文档主要有:

  1. 可行性研究报告
  2. 项目开发计划
  3. 软件需求说明书
  4. 概要设计说明书
  5. 详细设计说明书
  6. 数据库设计说明书
  7. 数据要求说明书
  8. 测试计划
  9. 测试分析报告
  10. 项目开发总结报告
  11. 操作手册
  12. 用户手册
  13. 开发进度月报

软件开发文档

可行性研究报告

可行性研究报告

图2 可行性研究报告

项目开发计划

项目开发计划

图3 项目开发计划

软件需求说明书

软件需求说明书

图4 软件需求说明书

概要设计说明书

概要设计说明书

图5 概要设计说明书

详细设计说明书

详细设计说明书

图6 详细设计说明书

数据库设计说明书

数据库设计说明书

图7 数据库设计说明书

数据要求说明书

数据要求说明书

图8 数据要求说明书

测试计划

测试计划

图9 测试计划

测试分析报告

测试分析报告

图10 测试分析报告

项目开发总结报告

项目开发总结报告

图11 项目开发总结报告

操作手册

操作手册

图12 操作手册

用户手册

用户手册

图13 用户手册

软件开发文档的使用

软件文档分类

软件文档分类

图14 软件文档分类

软件文档读者

软件文档读者

图15 软件文档读者

软件文档使用

软件文档使用

图16 软件文档使用

参考链接

  1. 软件工程,by wikipedia.
  2. 软件需求,概要设计,详细设计(文档)怎么做,做什么?,by 安东尼_Anthony.
  3. 软件工程文档总结,by BONIC.
  4. 国标:计算机软件文档编制规范,by 宋哥.
  5. 软件测试流程,by HenryZ.Tang.

CPlusPlus不常用语法解析

发表于 2020-01-21

近年来C++发展很快,出现了一些新的语法和特性。熟练掌握这些语法和特性,可提高编写C++代码的效率。下面即简要介绍这些C++语法和特性。

const=0

在类声明中,会出现const=0语法,如下所示:

1
2
3
4
5
class Weapon
{
public:
virtual void attack() const = 0;
};

在此处 =0 说明该类成员函数是一个纯虚函数。而将const放在成员函数之后,表示该成员函数禁止修改该类的数据成员(mutable成员除外)。如果您无意中修改了该类的数据成员,编译器会报告一个错误。

参考链接

  1. 关于virtual:c ++:const = 0的方法原型的代码说明,by 码农家园.
  2. C++构造函数和析构函数的调用顺序,by 靖心.

CPlusPlus单元测试框架Catch入门

发表于 2020-01-15 | 更新于 2022-07-11

最近在编写一个飞行力学的类库,随着类数量的增加,代码越来越复杂,质量越来越难以控制,因此引入单元测试,通过自动化测试以保障代码质量,防止因代码修改引入新的Bug。C++已经有一些成熟的代码测试框架,例如:Google Test, Boost.Test, CppUnit, Cute,等等。通过综合分析和比较,最终选择Catch2测试框架。选择该测试框架的原因是其够轻量级,够简单。

Catch2简介

Catch2是轻量级的C++的多范式测试框架。 它也支持Objective-C(也许还有C)。 它主要作为单个头文件分发,尽管某些扩展可能需要其他头文件。

关键特征

  • 快速且非常容易上手。 只需下载catch.hpp,#include它就可以了。
  • 没有外部依赖性。 只要您可以编译C ++ 11并拥有C ++标准库即可。
  • 将测试用例编写为自注册函数(或方法,如果您愿意的话)。
  • 将测试用例划分为几个部分,每个部分都是独立运行的(消除了对夹具的需求)。
  • 使用BDD样式的“时准时限”部分以及传统的单元测试用例。
  • 仅一个核心声明宏可以进行比较。 使用标准C / C ++运算符进行比较-但是完整的表达式已分解,并且记录了lhs和rhs值。
  • 测试使用自由格式的字符串命名-合法标识符中没有其他名称。

核心特征

  • 可以对测试进行标记,以方便地运行临时的测试组。
  • 故障可能(可选)进入Windows和Mac上的调试器。
  • 输出通过模块化报告器对象。 包括基本的文本和XML报告程序。 自定义记者可以轻松添加。
  • 支持JUnit xml输出以与第三方工具(例如CI服务器)集成。
  • 提供了默认的main()函数,但您可以提供自己的控件来进行完全控制(例如,集成到自己的测试运行器GUI中)。
  • 提供了命令行解析器,如果您选择提供自己的main()函数,该解析器仍可以使用。
  • Catch可以测试自己。
  • 替代性断言宏报告失败,但不中止测试用例
  • 浮点公差比较是使用表达性的Approx()语法构建的。
  • 内部和友好的宏是隔离的,因此可以管理名称冲突
  • 匹配器

Catch示例

使用Catch进行单元测试,只需简单掌握TEST_CASE、REQUIRE、SECTION三个宏即可编写绝大部分的测试用例。简单示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {

std::vector<int> v( 5 );

REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );

SECTION( "resizing bigger changes size and capacity" ) {
v.resize( 10 );

REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 );
}
SECTION( "resizing smaller changes size but not capacity" ) {
v.resize( 0 );

REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 );
}
SECTION( "reserving bigger changes capacity but not size" ) {
v.reserve( 10 );

REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 );
}
SECTION( "reserving smaller does not change size or capacity" ) {
v.reserve( 0 );

REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
}
}

上述示例中,对于每个SECTION,TEST_CASE都是从头开始执行的,因此,当我们进入每个部分时,我们知道vector的大小为5,容量至少为5。通过REQUIRE宏在顶层确保vector大小和容量的正确性。这是可行的,因为SECTION宏包含一个if语句,该语句回调Catch来查看是否应执行该节。 通过TEST_CASE,每次运行都会执行一个叶子部分。 其他部分将被跳过。 下次执行下一个部分,依此类推,直到没有新的部分为止。

参考链接

  1. Writing Unit Tests with Catch and CMake,by filebox.
  2. Integrating catch2 with CMake and Jenkins,by mariuselvert.
  3. Catch2,by catchorg.
  4. C++单元测试入门,by pezy.
  5. Catch2 - 用于 test 的轻量级库,by Bluemultipl.

四元数与旋转矩阵

发表于 2020-01-15 | 更新于 2021-04-09

四元数是由爱尔兰数学家威廉·卢云·哈密顿在1843年创立出的数学概念。单位四元数(Unit quaternion)可以用于表示三维空间里的旋转。它与常用的另外两种表示方式(三维正交矩阵和欧拉角)是等价的,但是避免了欧拉角表示法中的万向锁问题。比起三维正交矩阵表示,四元数表示能够更方便地给出旋转的转轴与旋转角。

欧拉角

欧拉角(Euler Angles)是一种描述三维旋转的方式,根据欧拉旋转定理,任何一个旋转都可以用三个旋转的参数来表示。但欧拉角的描述方式有很多种,并没有一个统一标准。对于定义一个欧拉角,需要明确的内容包括:

  1. 三个旋转角的组合方式(是xyz还是yzx还是zxy)
  2. 旋转角度的参考坐标系统(旋转是相对于固定的坐标系还是相对于自身的坐标系)
  3. 使用旋转角度是左手系还是右手系
  4. 三个旋转角的记法

旋转角的记法

顺序 飞行器 望远镜 符号 角速度
第一 heading azimuth $θ$ yaw
第二 attitude elevation $ϕ$ pitch
第三 bank tilt $ψ$ roll

旋转矩阵

对于两个三维点 $p_1(x_1, y_1, z_1)$,$p_2(x_2,y_2,z_2)$,由点 $p_1$ 经过旋转矩阵 $R$ 旋转到 $p_2$,则有:

$$R = \left[ \begin{matrix}
r_{11} & r_{12} & r_{13}\
r_{21} & r_{22} & r_{23}\
r_{31} & r_{32} & r_{33}
\end{matrix} \right]$$

$$\left[ \begin{matrix}
x_2 \
y_2 \
z_2
\end{matrix} \right] = R
\left[ \begin{matrix}
x_1 \
y_1 \
z_1
\end{matrix} \right]$$

注:旋转矩阵为正交矩阵$RR^T=E$

  • 绕x轴旋转:

$$R_x(\theta) = \left[ \begin{matrix}
1 & 0 & 0\
0 & cos\theta & -sin\theta\
0 & sin\theta & cos\theta
\end{matrix} \right]$$

  • 绕y轴旋转:

$$R_y(\theta) = \left[ \begin{matrix}
cos\theta & 0 & sin\theta\
0 & 1 & 0\
-sin\theta & 0 & cos\theta
\end{matrix} \right]$$

  • 绕z轴旋转:

$$R_z(\theta) = \left[ \begin{matrix}
cos\theta & -sin\theta & 0\
sin\theta & cos\theta & 0\
0 & 0 & 1
\end{matrix} \right]$$

  • 任意旋转矩阵:

任何一个旋转可以表示为依次绕着三个旋转轴旋三个角度的组合。这三个角度称为欧拉角。

由欧拉角求旋转矩阵

设三个轴$x,y,z$的欧拉角分别为$θ_x,θ_y,θ_z$,正弦值、余弦值分别为$s_x, c_x, s_y, c_y, s_z, c_z$那么旋转矩阵为:

$$R(\theta_x,\theta_y,\theta_z)=R_z(\theta_z)R_y(\theta_y)R_x(\theta_x) = \left[ \begin{matrix}
c_y c_z & c_z s_x s_y - c_x s_z & s_x s_z + c_x c_z s_y\
c_y s_z & c_x c_z + s_x s_y s_z & c_x s_y s_z - c_z s_z\
-s_y & c_y s_x & c_x c_y
\end{matrix} \right]$$

由旋转矩阵求欧拉角

$$R = \left[ \begin{matrix}
r_{11} & r_{12} & r_{13}\
r_{21} & r_{22} & r_{23}\
r_{31} & r_{32} & r_{33}
\end{matrix} \right] = \left[ \begin{matrix}
c_y c_z & c_z s_x s_y - c_x s_z & s_x s_z + c_x c_z s_y\
c_y s_z & c_x c_z + s_x s_y s_z & c_x s_y s_z - c_z s_z\
-s_y & c_y s_x & c_x c_y
\end{matrix} \right]$$

解方程可得:

$$\theta_x = atan2(r_{32}, r_{33})$$
$$\theta_y = atan2(-r_{31}, \sqrt{r_{32}^2+r_{33}^2})$$
$$\theta_z = atan2(r_{21}, r_{11})$$

注意:atan2()为C++中的函数,atan2(y,x) 求的是y/x的反正切,其返回值为[-pi,+pi]之间的一个数。

四元数

三维空间的任意旋转,都可以用绕三维空间的某个轴旋转过某个角度来表示,即所谓的Axis-Angle表示方法。这种表示方法里,Axis可用一个三维向量$(x,y,z)$来表示,$θ$可以用一个角度值来表示,直观来讲,一个四维向量$(θ,x,y,z)$就可以表示出三维空间任意的旋转。注意,这里的三维向量$(x,y,z)$只是用来表示axis的方向朝向,因此更紧凑的表示方式是用一个单位向量来表示方向axis,而用该三维向量的长度来表示角度值$θ$。这样以来,可以用一个三维向量$(θ∗x,θ∗y,θ∗z)$就可以表示出三维空间任意的旋转,前提是其中$(x,y,z)$是单位向量。这就是旋转向量(Rotation Vector)的表示方式,OpenCV里大量使用的就是这种表示方法来表示旋转(见OpenCV相机标定部分的rvec)。

  • 单位向量(x,y,z)旋转θ角度后的四元数:

$$(cos \frac{\theta}{2}, xsin \frac{\theta}{2}, ysin \frac{\theta}{2}, z*sin \frac{\theta}{2})$$

  • 对于三维坐标的旋转,可以通过四元数乘法直接操作,与旋转矩阵操作可以等价,但是表示方式更加紧凑,计算量也可以小一些。

四元数求旋转矩阵

已知四元数:

$$\mathbf{q} = q_0 + q_1 i + q_2 j + q_3 k = [s, \mathbf{v}]$$

利用Rodrigues公式可以由四元数求得旋转矩阵R:

$$R = \left[ \begin{matrix}
1 - 2 q_2^2 - 2 q_3^2 & 2q_1 q_2 - 2q_0 q_3 & 2 q_1 q_3 + 2 q_0 q_2 \
2q_1 q_2 + 2q_0 q_3 & 1 - 2 q_1^2 - 2 q_3^2 & 2 q_2 q_3 - 2 q_0 q_1 \
2 q_1 q_3 - 2 q_0 q_2 & 2 q_2 q_3 + 2 q_0 q_1 & 1 - 2 q_1^2 - 2 q_2^2
\end{matrix} \right ]$$

旋转矩阵求四元数

给出其中一种情况的计算方法:

$$q_0 = \frac{\sqrt{1+r_{11}+r_{22}+r_{33}}}{2}$$
$$q_1 = \frac{r_{32}-r_{23}}{4q_0}$$
$$q_2 = \frac{r_{13}-r_{31}}{4q_0}$$
$$q_3 = \frac{r_{21}-r_{12}}{4q_0}$$

其中要满足 $q_0 \neq 0$,$1+r_{11}+r_{22}+r_{33}>0$,即 $1+tr(R)>0$

四元数进行姿态变换

假设坐标系O1上的点P1(x1, y1, z1), 存在变换矩阵R, 可计算P1点在坐标系O2上的坐标值为P2(x2, y2, z2):
$$P2=R∗P1$$

矩阵R对应的四元数为q, 则使用四元数计算为:
首先三维空间点用一个虚四元数来描述:P1=[0, x1, y1, z1], P2=[0, x2, y2, z2]
则P2和P1将计算关系为:

$$P_2=qP_1q^{-1}$$

参考链接

  1. 四元数,by wikipedia.
  2. 四元数与空间旋转,by wikipedia.
  3. 从旋转矩阵计算欧拉角,by PengChao.
  4. 旋转变换(一)旋转矩阵,by csxiaoshui.
  5. 旋转矩阵、欧拉角、四元数理论及其转换关系,by jason_ql.
  6. 旋转变换(二)欧拉角,by csxiaoshui.
  7. 欧拉角,by wikipedia.
  8. 欧拉角细节/旋转顺序/内旋外旋,by 能儿.
  9. 四元数运算与姿态变换,by Yoyo_wym.
  10. Flight Parameters and Quaternion Math,by mathwork.
上一页1…293031…53下一页

Jack Huang

521 日志
67 标签
© 2025 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse