简单的研究了一下运动控制中的两条直线之间的圆弧过渡的情况,在运动控制中,按照两条成角度的直线走插补,一般的控制卡在没有开启速度前瞻之时,会在拐角处减速至0,以减小因为速度方向的改变所造成的冲击。如果发生冲击不仅会对运动的精度造成影响,同时也会损伤电机或者机械传动部分,这种影响在精度要求比较高的机床系统更为明显,因为高精度的机床系统对所处环境中的震动十分敏感。
在没有开启速度前瞻的情况下,存在直线转角衔接点时,其速度曲线大概如下:
图一:运动轨迹
图二:未开启速度前瞻时的速度与加速
(注:以上两图取自博文:基于S型曲线的连续多段曲线插补平滑过渡的规划算法(Matlab))
由上图可见这种冲击还是比较明显的。所以必须予以消除,也就是要开启速度前瞻功能,在两条线段相交的拐角处使用曲线或者圆弧来过渡。
具体示例:
设定两条线段,第一条线段起点(0,0),终点(100,100).
第二条线段起点(100,100),终点(110,90)。
这两条线段之间的夹角为90度。
以这两条线段为运动轨迹,明显的会在点(100,100)处形成速度的冲击点。所以可以使用一个圆弧在两条直线之间进行过渡。为了叙述方便,相关的公式不一一描述,只给一个参考的网址:https://blog.csdn.net/qq_26565435/article/details/98789361?ops_request_misc=%7B%22request%5Fid%22%3A%22158311037219195162559136%22%2C%22scm%22%3A%2220140713.130056874…%22%7D&request_id=158311037219195162559136&biz_id=0&utm_source=distribute.pc_search_result.none-task
上文中有对相关公式的简单描述,也并不麻烦。
我使用的是一个半径为0.5*√2的圆弧,其C++的求的圆弧的过程如下。
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <Windows.h>
using namespace std;
double x[100];
double y[100]; //100个点用来缓存数据
double specx;
double specy;
double endx=100;
double endy=100;
double startx;
double starty;
double interval=0.005; //插补的间隔
double tempRadius=0.5*sqrt(float(2)); //圆弧半径
double tempspecx;
double Plan(double radiu) //开始处理点
{
double temp;
temp=endx-radiu/(interval*sqrt(float(2)))*interval; //开始启动的地方
return temp; //节点X值
}
void Analyze()
{
ofstream out(".\\test.txt",ios_base::ate);
double F;
double FF;
startx=0;
starty=0;
int timesec=0;
int timefir=0;
int timethr;
F=(specx-100)*(specx-100)+(specy-(100-sqrt(float(2))))*(specy-(100-sqrt(float(2))))-0.5;
FF=specy-specx; //注意此处不能用准确的数值
while(TRUE)
{
while(TRUE)
{
if(specx<=endx)
{
if(specy-specx>=0) //直线插补实现过程
{
specx=specx+interval;
}
else
{
specy=specy+interval;
}
tempspecx=specx+50*interval;
if(tempspecx>=Plan(0.5*sqrt(float(2)))) //进行50段的前瞻
{
tempspecx=Plan(0.5*sqrt(float(2)));
}
if(specx>=(tempspecx-0.1))
{
goto others;
}
else
{
}
}
out<<specx<<" "<<specy<<"\n";
cout<<specx<<" "<<specy<<"\n";
timefir++;
}
//圆弧部分规划
others:
{
timesec=timefir;
for(int ii=0.5/interval;ii<99;ii++)
{
x[ii]=0;
y[ii]=0; //存储位置清零
}
while(TRUE)
{
F=(specx-100)*(specx-100)+(specy-99)*(specy-99)-0.5;
if(specx<=100+0.5) //在圆弧范围内
{
if(specx<=100)
{
if(F>=0) //在圆弧以内处理函数
{
specx=specx+interval;
}
else if(F<0) //在圆弧以外
{
specy=specy+interval;
}
}
else if(specx>100)
{
if(F>=0) //在圆弧以内处理函数
{
specy=specy-interval;
}
else if(F<0) //在圆弧以外
{
specx=specx+interval;
}
}
}
if(specx>=100.5)
{
goto ThirdLine;
}
out<<specx<<" "<<specy<<"\n";
cout<<specx<<" "<<specy<<"\n";
timesec++;
}
///直线部分规划/
ThirdLine:
{
int timethi=0;
startx=specx;
starty=specy; //设定起始点
double Fs;
while(TRUE)
{
Fs=(specy-starty)+(specx-startx);
if(specx<=110)
{
if (Fs>=0)
{
specy=specy-interval;
}
else
{
specx=specx+interval;
}
x[99]=specx;
y[99]=specy; //新增数据
timethi++;
cout<<specx<<" "<<specy<<"\n";
out<<specx<<" "<<specy<<"\n";
}
}
}
}
out.close();
}
int _tmain(int argc, _TCHAR* argv[])
{
AllocConsole();
Analyze();
system("pause");
return 0;
}
生成的轨迹会被存储在相关的文档之后,然后使用matlab来进行绘图。
得到的图形如下:
图一:时间
图二: 位置
图三:圆弧拐角
下一步的将会具体的演示,在这种路径下的速度与位置的关系。