一些实验的数据如下:
[700pixel*500pixel/14000mmx10000mm]实验室标准长度; 中等线速度为0.5m/s,最大线速度为1M/S,最小可以 为0,当在最小测距信息为49pixel~24.5pixel时可以0.5m/s~1m/s
之间变化,机器人身宽半径为0.39m;K
=700pixel/14000mm=0.05f;// proportion gene比例因子;
线速度为0.5m/s,机器人身宽为0.39m,角速度80degree/s;为什么要设置为1pixel/40ms,因为步长越小,
离目标的精度越高,所以,velocity = 1;以20mm为单位,则实验室标准长度为700[20mm]*500[20mm],速度为25[20mm]/s每步长要小于等于1pixel的话, sleep时间为1000ms/25=40ms,这样一个步长为1[20mm]=1pixel,这样精度正好为1pixel.在移动机器人仿真软件制作过 程中需要用到一些数学知识,比如三角函数,坐标平移,坐标旋转,点到点距离公式,点到直线的距离,两直线间夹角公式.甚至有可能还要涉及到旋转矩阵和尖点 (连续而不可导的点)的概念,如果要对采集的181个数据先进行信号处理的话,还要用到插值法,这要看你的具体算法了,我一开始测距用的算法是遍历各个像 素点,用了一下,发现计算量很大,如果不用旋转矩阵的概念,在700*500像素里,遍历一遍就要350000次,而且当机器人接近障碍物的时候,采集的 数据竟然是错误的,原因是每个pixel被遍历到的机会只有一次,而实际上当机器人接近障碍物的时候许多角度的值是落在同一个像素点上;但如果用旋转矩阵
的概念,也就是分片技术clip检测的概念,并没有消除前一个方法的缺点,计算量还是很大,并且当机器人接近障碍物的时候还是会出现信号的错误反馈.最后 我用了径向搜索的方法,简单说就是在某个角度以一定的步长n,从机器人这点开始搜索一直到碰到障碍物,搜索停止,计算两点之间的距离,搜索下一角度的距离
信息,如果在某个方向上直到搜索m个步长还是没搜索到,则认为在这个调度在检测范围内没障碍,这样做优点是计算量明显减少,本来要遍历350000个,计 算量随着障碍点的增加而增加,而以每个角度以步长为1搜索最近点,并且每个角度最长只有500,后者计算最多也只有500*181=90500次,为原来 的1/4的计算量。并且越接近障碍物扫描一次的时间越少,也就是说避障更加敏感;而且它测得的距离数据已经是很符合实际了,也就是当机器人接近障碍物的时 候会让许多角度的值是落在同一个像素点上,这其实是由方法本身决定的.因为它的出发点是角度,而不是各个像素点.
还有就是要用到图象的双缓冲技术,简要的说就是如何解决子屏幕(offscreen)和主屏幕(drawscreen)之间的关系;还有就是free space 和obstacle
space 的定义,可以根据像素的RGB或者鼠标事件来用0或1来标注各个像素点;最好学一些游戏编程方面的书,那里的技术很有启发性.甚至是地图创建和以后要做的 3D仿真都有涉及.
在读取map信息的时候要把图象信息读取进来后,Y轴数据要反向,用于map的数据处理,但在画图的时候只需要读取进来的数据就可以了.还有就是画图的时
候一定要把Y轴数据反过来,比如拿我的数据来说,就要把坐标轴的Y轴数据都要进行(500-1-Y轴数据)的变换,因为画图的坐标不是我们平常用的直角坐 标系.
最后就是程序员的问题了,线程的同步与协作,生产者和消费者的问题。
以下是用java时用到的坐标变换、旋转公式等一些公式知识点以及图象处理的知识点补充。
_______________________________
RGB图象是24位的图象,uint8逻辑数据存储图象数据,对图象数据反像,只要取逆就可以了;图像的大小(宽度×高度×每像素的位数),当前地图的大小为2852×2014×8,宽度为2852像素,高度为2014像素,每像素为8位
____________________________________
local view /gobal view
无论什么角度,都可计算坐标(把矩形当成一个多边形),非要用矩形的话,用AffineTransform(仿射变换)类,可以提供平移,旋转,缩放。
下面是一个例子:
import javax.swing.JFrame;
public class Test extends JFrame{
public
Test(){
super( "Tset ");
setSize(300,300);
}
//重写paint
public
void paint(java.awt.Graphics g){
super.paint(g);
java.awt.Graphics2D g2=(java.awt.Graphics2D)g;
//获取一个旋转45度,平移150点的变换对象
java.awt.geom.AffineTransform af=java.awt.geom.AffineTransform.getRotateInstance(45d,150d,150d);
//构造一个矩形
java.awt.Rectangle rc=new
java.awt.Rectangle(100,100,100,100);
//原样绘制
g2.draw(rc);
//变换后绘制
g2.setTransform(af);
g2.draw(rc);
g2.dispose();
}
public
static void main(String[] args){
new Test().setVisible(true);
}
}
_______________________________
java Alpha 透明度 渐变
GradientPaint gp=new GradientPaint(180,190,Color.yellow,220,210,Color.red,true);
g2.setPaint(gp);//设置渐变填充色
graphics2d.setPaint(new GradientPaint(i, j, outerC, (float)i * 0.65F, (float)j * 0.65F, innerC));
Linear(直线性的)、Radial(放射状的)、Conical(圆锥形的)
消除锯齿:
图形
文本:
// See e575 The Quintessential Drawing Program
public void paint(Graphics g) {
// Retrieve the graphics context;
this object is used to paint shapes
Graphics2D g2d = (Graphics2D)g;
// Determine if antialiasing is
enabled
RenderingHints rhints =
g2d.getRenderingHints();
boolean antialiasOn =
rhints.containsValue(RenderingHints.VALUE_ANTIALIAS_ON);
// Enable antialiasing for shapes
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Disable antialiasing for shapes
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
// Draw shapes...; see e586 Drawing
Simple Shapes
// Enable antialiasing for text
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// Draw text...; see e591 Drawing
Simple Text
// Disable antialiasing for text
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
}
_______________________________
用于建立那种一开始不知道到底有多少元素的向量.这里是画出轨迹点,因为一开始轨迹点的个数总数是不知道的。
Vector oldX=new Vector();
Vector oldY=new Vector();
oldX.addElement(new Double(currentX));
oldY.addElement(new Double(currentY));
// 绘制轨迹点
for (int i = 0; i < oldX.capacity(); i++) {
oldx = (Double) oldX.elementAt(i);
oldy = (Double) oldY.elementAt(i);
g2d.setColor(Color.BLUE);
g2d.drawOval((int) (-map.getRobotStatus().getRadius() +
oldx.doubleValue()), reverseY(map.getRobotStatus().getRadius
()+ oldy.doubleValue()), (int) (map.getRobotStatus().getRadius() * 2),
(int) (map.getRobotStatus().getRadius() * 2));
g2d.setColor(Color.BLACK.brighter().brighter());
g2d.fillOval((int) (-1.5 + oldx.doubleValue()), reverseY(1.5 +
oldy.doubleValue()), 3, 3);
}
__________________________________
x=X*cosθ-Y*sinθ
y=X*sinθ+Y*cosθ(x,y是变换后的坐标,X,Y是变换前坐标,θ是旋转角度,旋转中心为(0,0))
设旋转中心(X0,Y0),点(X1,Y1)旋转后为(X2,Y2)
旋转公式
X2-X0 = (X1-X0)Cosa-(Y1-Y0)Sina
Y2-Y0 =(X1-X0)Sina+(Y1-Y0)Cosa
(X2,Y2是变换后的坐标,X1,Y1是变换前坐标,a是旋转角度,逆时针方向为正)
旋转之后的坐标往往不能和原图坐标吻合,需要用内插法来求旋转后坐标的画素.
___________________________________
把一个坐标点从一个坐标系转移到另一个坐标系公式
首先将激光测距仪数据点由机器人局部坐标系转换成为全局地图的坐标系,设机器
人的当前全局位姿为
为机器人局部坐标系中的数据点,有:
X,Y即为数据点的全局坐标。
___________________________________
所谓线性内插法,其实就是一种二元一次直线方程解法。比如求P3=0.15相对应的Z3值,假设你只能查到P1=0.12和P2=0.17的Z1和Z2值(抱歉,手上没资料,随便举的例子)
这时你就可以设一个方程:y=bx+a,用P1,P2;Z1,Z2算出a,b。然后把P3代入方程,即求得所谓“内插法”所得的值。(至于公式可以自己推导,我这里就不写了)