0%

弹道解算算法研究

在英雄组的技术讨论中,我们对大弹丸在远距离吊射中的弹道解算算法进行了优化和分析。弹道解算过程中,涉及多个模型,包括无空气阻力模型、一次空气阻力模型和二次空气阻力模型。本文将对这些模型进行详尽的公式推导和讨论,并介绍我们在实际应用中的优化方案。

1. 无空气阻力模型

无空气阻力模型通常适用于速度较快、射程较近的情况,比如近距离的小弹丸对装甲板的打击。由于弹道的下坠影响较低,且计算公式简单,这种模型对设备的性能要求较低。对于无空气阻力的情况下,弹道的计算公式如下:

其中, 分别为初始位置, 分别为初始速度在水平方向和竖直方向的分量, 为重力加速度。

然而,由于大弹丸重量较重,射程较远,因此无空气阻力模型不适合用于大弹丸的解算。大弹丸在远距离射击中会受到重力和空气阻力的显著影响,这使得弹道逐渐偏离简单的抛物线轨迹。

无空气阻力模型的优点是计算量低,特别适合计算能力有限的场景,如嵌入式设备或实时控制系统。然而,这种简化带来了显著的精度损失,尤其是在远距离和高重量的情况下。因此,对于更高精度需求的场景,必须引入空气阻力的影响。

2. 一次空气阻力模型

一次空气阻力模型假设空气阻力与速度成正比,这一模型能够更好地考虑空气阻力对弹道的影响。模型的计算公式如下:

其中, 为空气阻力系数, 为弹丸质量。

在应用中,我们对一次空气阻力模型进行了优化,简化为仅考虑水平方向的空气阻力,因为大弹丸在吊射时的水平行程远大于竖直行程。这样做既减少了计算量,又保持了足够的精度。

在测试中,我们发现对于上升阶段的弹速在 15.5 m/s 左右时,一次空气阻力模型能够实现对前哨站的精准打击。然而,在远距离吊射时,弹丸的下降阶段会因旋转分量的影响而产生左右的散布。由于旋转速度难以观测,且机械结构的优化对旋度的影响远大于弹道补偿,因此一次空气阻力模型并不能完美适配。

此外,在实际应用中,弹丸在射出时由于发射机构的双极摩擦轮作用,通常会带有一定的旋转。这种旋转在上升阶段对弹道的影响较小,但在下降阶段,由于速度降低和空气阻力的影响,旋转分量会导致弹道产生较为显著的偏移。这使得仅使用一次空气阻力模型无法完全准确描述远距离射击的弹道。

3. 二次空气阻力模型

二次空气阻力模型中,空气阻力与速度的平方成正比。其水平方向和竖直方向的计算公式如下:

  • 水平方向:
  • 竖直方向:

二次空气阻力模型考虑了速度平方项的空气阻力影响,因此在描述高速弹丸的运动时更加精确。我们使用二阶线性微分方程来描述弹道的轨迹。然而,由于这种方程没有封闭解析解,通常需要使用数值迭代的方法求解,这使得计算复杂,初值敏感,且不一定有解。因此,二次空气阻力模型不适合嵌入式设备。

在远距离射击场景中,二次空气阻力模型虽然可以提供更精确的弹道描述,但其计算量和对初始条件的敏感性使其在资源受限的情况下不具备可行性。此外,由于弹丸在下降阶段的复杂旋转行为,二次空气阻力模型同样面临挑战。因此,我们在实际应用中并未采用该模型,而是选择了一种折中的方法。

4. 逐段解算与曲线拟合

经过上述模型的分析和测试,我们决定对弹道的不同阶段进行逐段解算,最终拟合出最有可能的落点曲线,并据此确定云台的初始 pitch 角度。

4.1 分段模型选择与优化

在我们的优化方案中,将弹道分为三个阶段:上升阶段、最高点阶段以及下降阶段。每个阶段使用最适合的模型进行解算,从而在精度和计算负担之间找到平衡。

  • 只有上升阶段:使用一次空气阻力模型进行拟合。该模型在考虑空气阻力的基础上简化了计算,经过多次测试,落点误差在上下 0.05 m 范围内。对于英雄机器人打击前哨站的任务,这一精度是可以接受的。
  • 最高点阶段:在弹道达到最高点时,弹速降至最低,空气阻力的作用也相对较小。在这一阶段,我们可以认为空气阻力的影响较为可忽略,因此使用无空气阻力模型对这一阶段进行简单计算。
  • 既有上升又有下降阶段:在下降阶段对落点进行大量测试,拟合出适合英雄机器人的落点散布曲线。在下降阶段,由于弹速降低,旋转对弹道的影响变得显著,我们采用了基于实验数据的拟合曲线来描述弹道的偏移,从而确保打击的准确性。

这种逐段解算与曲线拟合的方法,不仅减少了计算负担,还能够保证在远距离吊射中的精度要求。通过对不同阶段采用不同的模型,我们能够更加精确地描述弹丸的运动行为,尤其是在旋转分量对弹道产生影响的情况下。

4.2 实际应用中的实验验证

在实验过程中,我们对上述逐段解算方法进行了多次测试。实验结果表明,对于不同的目标距离和高度,该方法能够有效地提高打击精度。特别是在模拟实战条件下,英雄机器人能够在不同高度和距离的目标上保持稳定的命中率。

此外,我们还对逐段解算与曲线拟合方法进行了压力测试,以评估其在实时控制系统中的表现。结果表明,该方法在计算量和响应时间上均符合系统的实时性要求,为英雄机器人在复杂环境中的应用提供了有力支持。

5. 主要计算代码示例

以下为主要计算代码的简化示例,用于逐段解算弹道并拟合最终的落点曲线:

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
function [success, angle] = solver(vel, coeff, target_x, target_h)
success = 0;
MAX_ITER = 100; % 最大迭代次数
PI = atan(1) * 4; % 圆周率
aimed_h = target_h; % 初始化目标高度
angle = 0; % 初始化角度
for i = 1:MAX_ITER
% 计算临时角度
tmp_angle = atan2(aimed_h, target_x);
% 检查角度范围是否在 (-80° 到 80°) 之间
if tmp_angle > 80 * PI / 180 || tmp_angle < -80 * PI / 180
success = 0;
return;
end
% 使用 forward_motion 函数计算高度和时间
[h, t] = forward_motion(vel, coeff, tmp_angle, target_x);
% 检查运动时间是否超过 10s
if t > 10
success = 0;
return;
end
% 计算高度差
dh = target_h - h;
aimed_h = aimed_h + dh;
% 如果高度差小于 0.01,则迭代结束
if abs(dh) < 0.01
angle = tmp_angle;
success = 1;
return;
end
end
end

6. 结论

通过对无空气阻力模型、一次空气阻力模型和二次空气阻力模型的分析,我们最终选择对不同阶段使用不同的模型进行逐段解算,并通过曲线拟合优化了大弹丸的落点预测。这种方法在保证精度的同时,降低了嵌入式设备的计算负担。通过结合实验验证和压力测试,我们证明了该方法在实际应用中的有效性和可靠性。

在未来的研究中,我们计划进一步优化弹道的实时计算方法,探索更加精确且计算量低的弹道解算算法,以适应更复杂的实战环境和更高的性能需求。

参考文献

  1. Ballistics and Projectile Motion
  2. MATLAB Documentation on Iterative Methods: MATLAB Documentation
  3. RoboMaster弹道解算算法:电控实现

Hexo + Github 部署个人网站

1. 环境配置

本人使用的工作流和部署环境是 VSCode + Remote SSH + 阿里云服务器(Ubuntu24.04) + Github Page,以下是一些前置环境:

  • Github账号

  • Ubuntu24.04的环境

    • Node.js

      1
      2
      sudo apt install nodejs #安装 Node.js
      nodejs --version # 查看版本信息 我的是:v18.19.1
    • npm(Node.js的包管理器)

      1
      2
      sudo apt install npm # 安装 npm(Node.js的全局包管理器)
      npm --version # 查看版本信息 我的是:9.2.0
    • git

      1
      2
      3
      4
      sudo apt install git # 安装Git (项目版本管理工具)
      git --version $ 查看版本信息 我的是:git version 2.43.0
      git config --global user.name "Javen"
      git config --global user.email "2452731211@qq.com"
    • Hexo

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      # npm install : 用来安装npm包
      # hexo-cli : Hexo的命令行工具,提供一系列命令来管理和操作博客项目
      # -g : 表示全局安装,在任何地方都可以使用Hexo指令
      npm install hexo-cli -g
      # hexo init : 用于初始化一个新的Hexo项目
      # blog : 用于初始化的目录名,这里会将新的Hexo博客项目创建到执行这条命令的文件夹中的blog文件夹里。
      hexo init blog
      # 进入文件夹
      cd blog
      # npm install : 安装Hexo项目用到的所有包
      # 国内安装慢或者没有魔法的可以使用镜像网站下载,下面是镜像安装命令
      # npm install --registry=https://registry.npmmirror.com
      npm install
      # 启动本地预览,使用这条指令后Hexo会默认在本地的4000端口开启服务,下面是访问链接
      # http://localhost:4000
      hexo server # 简写:hexo s

2. Github Page 配置

首先,我们需要访问Github的官网,登录我们的账号:
image
之后,我们需要创建一个用来访问的仓库,用来部署我们的网站
image2
创建好之后,需要在Github账户中添加公钥,用于我们将本地的项目上传到Github上
image1
本地获取公钥的命令是:

1
2
3
4
5
6
7
8
9
10
11
12
# ssh-keygen : 用于创建公钥的命令
# -t rsa:指定使用 RSA 加密算法(也可以用 ed25519,更快且更安全)。
# -C "your_email@example.com":为 SSH 密钥添加注释(通常为邮箱地址)。
ssh-keygen -t rsa -C "your_email@example.com"

# 系统会提示你选择密钥保存路径(默认路径为 ~/.ssh/id_rsa)。
# 查看公钥
cat ~/.ssh/id_rsa.pub

# 终端会显示以下内容
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7...your-key...== your_email@example.com
# 复制以上公钥内容

之后将获取到的公钥保存到Github上
image3
image4
没有问题之后就可以上传项目了,再次打开VSCode的远程终端或者其他的远程连接终端,进入blog文件夹下,执行一下操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ./blog 下执行
# 首先,找到这个文件夹下的_config.yml配置文件,打开并且下拉到最后,添加以下内容,repo后边跟Github仓库的地址加.git,main表示使用这个分支
deploy:
type: git
repo: https://github.com/username/username.github.io.git
branch: main
# 之后需要安装一个git部署工具 hexo-deployer-git
npm install hexo-deployer-git --save

# 之后执行以下指令 :
hexo clean # 清除之前生成的东西
hexo g # hexo generate 生成静态文章
hexo d # hexo deploy 部署文章
# 如果是在离线端即 localhost:4000端测试你的博客,则只需要 hexo g + hexo s 即可,无需 hexo d

如果看到以下内容,就证明已经配置成功了
image5
之后就可以访问以下网站直接访问博客页面了
username.github.io # https://username.github.io

3. 数学公式渲染

首先,对于我来说,因为很多笔记中要使用到数学公式,所以需要先安装一个可以渲染LaTex公式的引擎,使用以下命令安装

1
2
3
# 首先需要卸载掉Hexo自带的MarkDown库,使用一个对LaTex支持比较完善的库来渲染数学公式
npm uninstall hexo-renderer-marked --save # 卸载hexo-renderer-marked库
npm install hexo-renderer-kramed --save # 安装hexo-renderer-kramed库

之后,需改更改一些配置文件来实现对数学公式的渲染
1
2
3
4
5
6
7
8
9
10
11
# 首先是站点配置文件,位于博客的根目录下的.\_config.yml文件,在其中加入以下内容,位置自定
math:
engine: 'mathjax'
mathjax:
src: custom_mathjax_source
# 之后是主题配置文件,我这里使用的是next主题,配置文件位于对应主题的文件夹下,相对根目录位置为.\themes\next\_config.yml,管理是是对应主题的相关设置
# 如果其中有以下关键词,直接修改即可,如果没有,可在任意位置加上以下内容
mathjax:
enable: true
cdn: https://cdn.jsdelivr.net/npm/mathjax@2.7.8/MathJax.js?config=TeX-AMS-MML_HTMLorMML
# 最后,需要在

到这一步如果都没有问题,那么对于数学公式的渲染配置就结束了

4. 工作流

对于日常需要记录的博客内容,使用以下命令创建一个博客

1
2
# 创建一个新的文章
hexo new <文章名称>

之后,会在博客根目录的.\source\_posts文件夹下生成对应的文章的md文件,打开文件,其中会显示文章的配置内容,类似于以下格式:
1
2
3
4
5
6
7
8
---
title: Hexo-Github-搭建个人博客 # 文章标题
date: 2024-10-21 03:50:49 # 文章日期
tags: # 文章标签类型
- 部署
- 网站
mathjax: true # 是否开始数学公式的渲染
---

配置内容还有更多其他的设置,可以参考官方文档,之后就可以在下边写具体的博客内容了

5. 部署

使用以下指令将博客内容更新并上传到Github Page上

1
2
3
hexo clean # 清除缓存文件,如果没有更换主题或其他比较大的改动,可以不执行这一句
hexo g # hexo generate 生成对应的静态文件
hexo d # heso deploy 部署到配置文件中的指定地址

好了,以上就是从零开始使用Hexo + Github Page搭建个人博客的全流程.

参考文献和内容

  1. Hexo渲染数学公式:配置方法与原理浅释

电机参数识别算法个人心得 —— 递归最小二乘法(RLS)

1. 为什么要做参数辨识

最近在项目里需要搞电机的参数估计,说白了就是要实时获取电机的关键参数,比如定子电阻 、定子电感 还有磁链。之前一直觉得参数测量这种事是硬件组的活儿,没想到我也要弄。于是就开始研究递归最小二乘法(RLS),发现它不仅能搞定这些参数,还能实时更新,在参数整定方面还是很实用的。所以,这篇笔记就是我在搞清楚这套算法之后的心得,边学边写,顺便记个脑子。

2. 电机的 d-q 轴模型

先从基础说起。电机的 d-q 轴模型其实不复杂,就是把三相电机的电压和电流转换成一个固定的参考系。可以这么理解:通过数学变换,把三相电流、电压搞成两个直轴上的量,这样计算起来方便很多,尤其是在控制上。

方程如下:

我们可以把电压 ,电流 ,以及电角速度 看作已知的测量值。通过这两个方程,我们可以推导出 和磁链 的表达式。没错,目标就是把这些参数“猜”出来。

然后再做个假设:磁链 跟电流 是线性关系(这是合理的物理假设):

3. 离散化是个啥?

在电机控制里,信号是离散的(因为都是采样来的数据)。所以,我们得把连续的公式转换成离散形式。最简单的办法就是用有限差分公式,比如:

这意思就是我们用电流的差值除以采样周期 来近似电流的导数。用这个方式,我们可以把之前的电机方程转换成离散形式:

公式虽然有点长,但不用慌,核心就是把电压、电流、速度这些量联系起来,然后推导出

4. 递归最小二乘法(RLS)

现在,重点来了——RLS。说简单点,RLS 是个在线学习算法,它通过历史数据和新数据结合起来,不断优化你要估计的参数。RLS 的公式看起来也没那么复杂,就是矩阵乘法+求逆:

  1. 更新数据矩阵

    其中 是遗忘因子(你可以理解成新数据和旧数据的权重比例,值越接近 1,旧数据占的比重越大)。

  2. 求逆
    如果增广矩阵 的条件数过低(就是说矩阵的逆不好求),就加个小扰动(防止算不出逆)。

  3. 更新参数

    这个公式就是通过反馈误差,不断优化参数的过程。

5. 代码解析

写了半天理论,终于到代码部分了!下面是这个算法的代码实现:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function [Rs,Ls,Flux] = param_identify(ud, uq, id, iq, we)
% 参数初始化
persistent A_star x iq_last id_last I_unit lamda;

if isempty(A_star)
A_star = single(eye(3)); % 初始化协方差矩阵
x = single(zeros(3, 1)); % 参数向量 [Rs, Ls, Psi]
I_unit = single(eye(3)); % 单位矩阵
iq_last = single(0);
id_last = single(0);
lamda = single(1); % 遗忘因子

% 初始估计值
x(1)=0.45; % Rs 初始值
x(2)=0.0085; % Ls 初始值
x(3)=0.171; % Psi 初始值
end

Tpwm = 10000; % PWM 采样周期

% 构造 alpha_k 矩阵
alpha_k = single([iq, we * id+(iq - iq_last) * Tpwm, we;
id, (id - id_last) * Tpwm - we * iq, 0]);
beta_k = single([uq; ud]);

% 更新上次的电流值
iq_last = single(iq);
id_last = single(id);

% 更新 A_star 矩阵
A_star = single(lamda * A_star + alpha_k' * alpha_k);

% 判断 A_star 是否可逆
if rcond(A_star) < eps
% 如果不可逆,可以考虑加入扰动项,但这里注释掉了
%A_star_inv = single((A_star + k * I_unit) \ I_unit);
else
A_star_inv = single(A_star \ I_unit);
% 参数更新
x = x + single(A_star_inv * alpha_k' * (beta_k - alpha_k * x));
end

% 输出参数估计值
Rs = x(1);
Ls = x(2);
Flux = x(3);
end

核心部分:

  • 初始化:用 persistent 来保存历史数据,保持每次调用函数时的上下文。
  • 矩阵更新:用当前时刻的输入输出数据构造矩阵
  • 参数更新:判断 的逆是否存在,若存在则更新参数向量
  • 输出结果:返回当前估计的

6. 最后总结

递归最小二乘法真的是个强大工具,尤其是做这种在线参数估计的时候,它能在数据变化的情况下自适应调整参数。这段代码的实现核心思想很简单:通过历史数据和新数据的结合,不断优化你想要的参数。当然了,实际用的时候,调参也很重要,尤其是遗忘因子 这东西,得根据具体情况调到合适的值。

好了,学完 RLS,电机参数识别这部分算是搞定了,接下来就可以尝试在实际系统中跑一跑,看效果了。