在简单地形上小车运动轨迹的数学表达(一)

图形学课上的小小总结

前提:

假设地形函数为f(x)为f(x)=sin(x)[*]。

小车由四个轮子组成。

实现基于OpenGL。

[*] 实际效果图的f(x) = 0.5 * sin(x)

问题一:如何画一个轮子?

具体的问题描述应该是"如何在已知坐标x的情况下画出一个轮子?"

该轮子拥有的唯一特点是:与其所依附的地形应该是相切的。

下面是当"x0 = π/4"地形函数(图-1):

假设在地形上的一点(x0,y0),由它所唯一对应的轮子圆心为(x1,y1)。

不失一般性,(x1,y1)的计算过程如下:

这里有几个需要注意的地方:

k0为0的情况,即在x=x0处地形斜率与x轴相切的情况下:

x1 = x0

y1 = y0 + R

关于x1的±:

if k0 > 0

x1 = x0 + R * cosβ

else

x1 = x0 - R * cosβ

综合以上可得最终实现如下:

void get_wheel_center(float _x0, float _y0, float _r, float &_x1, float &_y1){

float k0, k1, cos_beta, sin_beta;

k0 = derived_f(_x0);

// 考虑c++的浮点计算会丢失精度,此等价于if (k0 == 0) ...

if (k0 < 0.00001f){

_x1 = _x0;

_y1 = _y0 + _r;

return;

}

k1 = -1 / k0;

cos_beta = sqrt(1 / ((k1 * k1) + 1));

sin_beta = sqrt((k1 * k1) / (1 + k1*k1));

_y1 = _y0 + _r * sin_beta;

if (k0 > 0)

_x1 = _x0 - _r * cos_beta;

else

_x1 = _x0 + _r * cos_beta;

}

实现效果图(图-2):

问题1需要注意的地方:

根据上面所讲的画轮子的方法可以看出,若需要在x=x0处画一个轮子,所实际画出的轮子有可能与x=x0这条轴是有偏差的,这里的偏差是指实际画出的轮子的圆心并不在x=x0上,而是在偏移了±R*cosβ的位置上。

根据以上的公式推到是可以算出来一个精确解的,即轮子所在的坐标,但这也是在保证了计算精度的前提下的,不过就实际效果来看还是十分满意的。

问题2:如何画两个轮子?

这里的两个轮子有两层意思:

画出车子不同侧的另一个轮子。

画出车子同侧的另一个轮子。

对于第一层意思:

在获得到第一个轮子的坐标(x0,y0,z0)后,只需要将此点沿z轴平移±w个单位得到(x0,y0,z0±w),这里的w应该是车宽。再根据这个坐标再画出一个轮子,这样实际中的前轮(后轮)就画出来了,这个问题就得到了解决,实际效果可以见图-2。

而第二层意思是一个完全不一样的问题:

对于这个问题,有几点前提与假设:

前轮或后轮已经画好,现在要画剩下的那一边[*]的轮子。这里假设问题一已经解决,即已经画好了后轮,现在就剩下前轮没画了。

前轮的圆心要保证与后轮圆心距离为L(车长)。

前轮也需要与所在地形相切。

[*] “边”的意思是指前边或后边,其含义有别于“侧”。

若视角在车子的顶部,能看到:(=:轮子,-:车子的边缘)

1 2

=----=

=----=

3 4

1和2称为同侧,1和3成为同边。在此文中1和3称为后轮,2和4称为前轮。当出现比较前轮与后轮距离时,所指的是同侧的两轮圆心距离。

因此,问题简化为,如何在已知后轮数据和车长数据的前提下画出前轮?

根据车长L为定长可得,前轮的圆心O1一定在以O0为圆心,L为半径的圆弧上,大意图如下(图-3)

设O0为(x0,y0),O1为(x1,y2)

则一定在(x0,+∞)中存在一点x,由此x做的相切于地形的轮子的圆心O' (x',y'),满足:

|O' - O0| = L 即 ((x'-x0)2 +((y'-y0)2)1/2 = L

因此可以从x0开区间沿着x轴正方向出发一个一个试探性的画圆,判断是否有满足以上条件的,换句话说也就是说不断的做圆,直到满足两圆圆心距离为L。

如此一来这个问题也解决了,但是有一个效率问题,这个效率太慢了,如果在计算机上实现的话也不是特别容易准确实现,主要有这么几个难点:

由于计算机实现是离散的变量,故向前搜索的时候需要设置一个合适的增量,若设置太大,则搜索间隔太大,漏掉准确解的概率较大,但是搜索所消耗时间比较少;若设置太小,则搜索间隔太小,导致搜索次数太多,漏掉准确解的概率相比前者要小得多,但是搜索所消耗时间会变得太大。

无效的搜索过多,几乎前面的搜索就是临近O0的搜索可能都是无效点,而这些点都要进行画圆的计算。

于是针对以上几个问题,有如下的解决方案:

针对搜素精确度的问题:由于计算机计算浮点会有误差,故当计算结果满足一定误差范围内就可以认为找到了精确解了;

针对搜索次数导致效率底下的问题,可以采取二分法进行搜索。

由解决方案2中的二分法进而引发了一个问题:二分法的边界?

由于需要在(x0,+∞)中进行二分法,故需要首先确定这个+∞能否有一个确切的值?有的话是多少?

由问题一中末尾的“注意”可以得到,这个最大值+∞可以是L+R,不妨考虑一种极端情况,即两边的圆所在的地形都是垂直的,在这种情况中最大的搜索值就是b,而b=L+R。(图-4)

因此,二分法的最大范围定下来了,就是(x0,x0+L+R)。

具体的二分法流程如下(图-5):

使用c++实现如下:

void get_righ_wheel_center(float _x0, float _y0, float _L, float &_x1, float &_y1) {

float

beg = _x0,

end = _x0 + _L + _R;

float mid = 0.0f,dis = 0.0f,x1 = 0.0f,y1 = 0.0f;

while (true) {

mid = (beg + end) / 2;

get_wheel_center(mid, f(mid), _R, x1, y1);

dis = dis_between_points(x1, y1, _x0, _y0);

if (abs(beg - end) < 0.00001 || abs(dis - L) < 0.0001){

_x1 = x1;

_y1 = y1;

return;

}

if (dis > _L){

end = mid;

}

else{

beg = mid;

}

}

}

如此一来,只要确定了后轮,前轮就可以由二分法计算得出了,可以比较一下计算效率,若从计算次数比较的话,使用二分法大约只需要12[*]次就可以得到十分精确的结果,而使用之前的方法,在保证同样精度的情况下次数是显然要比12要大得多的。

[*] 这是实际中的值。

实现效果(图-6):

总结

问题1和问题2,将车子的前轮与后轮的位置做出了较为精确的计算,其计算步骤大致如下:

首先已知条件是:后轮当前横坐标X,轮子半径R,车长L。

根据后轮坐标可计算出后轮的圆心坐标。

根据后轮圆心与车长L可计算出同侧前轮的圆心坐标。

将同侧后轮与前轮做Z轴平移,即可得到另一边轮子。

如此,在已知地形上四个车轮的位置就可以计算出来了。

但是一辆小车想要在地形上行走,只是确定了轮子的位置恐怕不是唯一要解决的问题。

还得解决:

车体的运动要随着轮胎的运动而上下起伏与前进。

车体在不规则地形上的前进不是简单的通过x正方向的增量来决定的,而要考虑在地形所经过的的路程,而非位移。但是需要通过位移进行轮子的绘制,故需要位移与地形上路程的转换。

关于这两个问题的解决,可以参见后续的文章。

Thanks

3/30/2017 9:47:02 PM

车轮轨迹原理_在简单地形上小车运动轨迹的数学表达(一)相关推荐

  1. 车轮轨迹原理_方向盘与车轮轨迹图解,方向盘和车轮的动态图

    在车辆前进的时候,如果要往左拐弯那么方向盘就要往左打:如果要往右拐弯那么就应该往右打方向.那如果问你倒车的时候往左往右该如何打方向,你又知道吗?很多新手就是因为没有搞懂这一点才会在倒车时发生刮碰,所以 ...

  2. java断点续传原理_很简单的Java断点续传实现原理

    原理解析 在开发当中,"断点续传"这种功能很实用和常见,听上去也是比较有"逼格"的感觉.所以通常我们都有兴趣去研究研究这种功能是如何实现的? 以Java来说,网 ...

  3. 峰值检波电路的作用和原理_最简单的峰值检波电路

    描述 在改善曾经做过的一个项目时,为了提升微控制器ADC采集的效果,就引用了峰值检波电路.由于ADC的采集电压是处于一个范围内(一般是0-5v或3.3v),当你采集的信号很微弱的时候,你必须要将信号放 ...

  4. java响应式导航栏原理_一个简单的响应式导航栏

    背景 导航对于一个网站重要性,不言而喻.网站上导航一般都置于网站的顶端,每一个导航项都直接详细的列出来,但如果需要去适配移动端的话这样简单粗暴的方法就不大可行了,因为受移动端屏幕宽度所限,在电脑端完美 ...

  5. 卷积神经网络原理_人脸识别背后,卷积神经网络的数学原理原来是这样的

    在自动驾驶.医疗以及零售这些领域,计算机视觉让我们完成了一些直到最近都被认为是不可能的事情.卷积神经网络可能是这一巨大成功背后的关键组成模块.这次,我们将要使用卷积神经网络的思想来拓宽我们对神经网络工 ...

  6. 卡尔曼滤波与组合导航原理_图解卡尔曼滤波器,无需深厚的数学知识也易懂(第五部分:多维卡尔曼滤波器)...

    译者前言:因第1-4部分(基础)已经学习完毕,接下来需要学习多维卡尔曼滤波器与扩展的卡尔曼滤波器(EKF),但是1-4部分的作者对接下来要学习的内容还没有更新,因此我们将从华盛顿大学教授的教材开始学习 ...

  7. 感性电路电流计算_最简单的交流220V降压电路-电阻电容降压原理

    阻容降压原理 电容电阻降压的原理其实比较简单.它的工作原理是电容在交流信号的情况下,产生容抗来限制最大的工作电流.说白了就是电容使用它自己的通交流阻直流的性能,在交流信号输入时电容产生容抗.我们通过他 ...

  8. python卡方检验筛选特征原理_基于Python的遥感特征筛选—递归特征消除(RFE)与极限树(Extra-Trees)...

    引言 基于前几篇文章关于筛选方法的介绍,本篇同样给大家介绍两种python封装的经典特征降维方法,递归特征消除(RFE)与极限树(Extra-Trees, ET).其中,RFE整合了两种不同的超参数, ...

  9. 万能充电器工作原理_百度知道

    万能充电器工作原理_百度知道 万能充电器工作原理_百度知道 万能充电器工作原理     2008-08-29 21:27 457070320 | 分类:社会民生 | 浏览4372次 | 该问题已经合并 ...

最新文章

  1. rabbitmq 同步策略_RabbitMQ(三):消息持久化策略
  2. iframe的src怎么携带参数_Java 爬虫遇到需要登录的网站,该怎么办?
  3. Linux中shell的介绍
  4. java代码删除文件夹_删除文件夹的java类
  5. ajax请求后台报没有body_前端常见面试 - 请求篇
  6. Boost::context模块callcc的jump_void测试程序
  7. android 全屏动画,Android开发之全屏与非全屏的切换设置方法小结
  8. 【搜索引擎基础知识1】搜索引擎的技术架构
  9. Jython调用不包含第三方库的python脚本
  10. 遇见王沥川的人生感悟_23岁酱油泡饭默默无闻,31岁逆袭人生,王彦霖有何魅力?...
  11. wpf 点击按钮弹出选择框_WPF-PopupWindow wpf右下角弹出框,通过按钮调用,类似QQ CSharp C#编程 238万源代码下载- www.pudn.com...
  12. 《linux核心应用命令速查》连载七:bg:后台运行命令
  13. Security+ 学习笔记41 安全网络技术
  14. UDP传输 TCP传输
  15. 在EnableQ创建一张问卷
  16. Python的Method理解
  17. linux shell 统计词频,shell之词频统计
  18. 【系统运维-raid5】HW5885V3下挂4块2T硬盘如何做RAID5
  19. JS与C语言的数据类型转换
  20. 测绘资质升级申请条件有哪些要求?

热门文章

  1. 【正点原子Linux连载】第三十七章 Linux内核移植 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0
  2. Java基础习题(四)
  3. 解决C语言编译undefined reference to ‘pow’问题
  4. Lambda表达式到底是什么?——简单了解Lambda表达式
  5. 用Web标准进行开发
  6. git 使用meld 进行文本对比
  7. 每天一本书 [2014/06/10-2014/07/10 ]
  8. 液晶显示器偏光膜的基本原理
  9. 用java解一元二次方程组
  10. 将 Debian APT 引入 iPhone