在数控加工等应用中,要求数控系统对机床进行平滑的控制,以防止较大的冲击影响零件的加工质量。 运动控制器的前瞻预处理功能可以根据用户的运动路径计算出平滑的速度规划,减少机床的冲击,从而提高加工精度。 下面用一个实例来说明前瞻预处理的机制优势。假设机床要加工一个长方形的零件,刀具所走的轨迹 如图 7-17 (a)
所示。假设
m
点到
n
点距离
3000
个单位长度,有
30
段规划。
n
点到
p
点距离
2000
个单位长 度,有 20
段规划。每段规划
100
个单位长度。
如果按照图
7-17 (b)
所示的速度规划,即在拐角处不减速,则加工精度一定会较低,而且可能在拐弯 时对刀具和零件造成较大冲击。如果按照图 7-17 (c)
所示的速度规划,即在拐角处减速为
0
,可以最大限度 保证加工精度,但加工速度就会慢下来。如果按照图 7-17(d)
所示的速度规划,在拐角处将速度减到一个合 理值,既可以满足加工精度又能提高加工速度,就是一个好的速度规划。 为了实现类似图 7-17 (d)
所示的好的速度规划,前瞻预处理模块不仅要知道当前运动的位置参数,还
要提前知道后面若干段运动的位置参数,这就是所谓的前瞻。例如在对图
7-17 (a)
中的轨迹做前瞻预处理 时,我们设定控制器预先读取 50
段运动轨迹到缓存区中,则它会自动分析出在第
30
段将会出现拐点,并依据用户设定的拐弯时间计算在拐弯处的终点速度。前瞻预处理模块也会依照用户设定的最大加速度值计 算速度规划,使任何加减速过程都不会超过这个值,防止对机械部分产生破坏性冲击力。 从下图 7-18
可以直观地了解,使用前瞻预处理功能模块来规划速度,在小线段加工过程中的对速度的 显著提升。前瞻预处理流程图如图 7-19
所示
(1)
用户在应用程序中定义一个结构体
TCrdData
的数组作为前瞻缓存区,数组大小用户自己设定,比如 数组大小为 200
,那么前瞻缓存区长度
N=200
段;然后调用指令
GTN_InitLookAhead
作初始化前瞻。
(2)
用户调用如
GTN_LnXY
等直线插补指令和圆弧插补指令将数据段输入缓存区。这时,插补数据先流 入开辟的前瞻缓存区,当流入前瞻缓存区的数据段数大于了 N
之后,才能逐段流入运动缓存区。运动缓存区是控制器内部资源,大小 4096
段,每一段可以存放一条指令。控制器只能执行压入运动缓存 区中的数据,所以用户一定要确保前瞻缓存区的数据进入运动缓存区。分不同情况分析:
1)
假设用户数据只有
190
段,则当用户调用完后,数据会一直停留在前瞻缓存区,因此,用户需要 调用
GTN_CrdData
(1, NULL, 0)
来将前瞻缓存区数据压入运动缓存区。
2)
假设用户数据只有
300
段,则当用户调用完后,有
100
段数据已经流入运动缓存区,但还有
200 段留在前瞻缓存区,同样,用户需要调用
GTN_CrdData
(1, NULL, 0)
来将前瞻缓存区数据压入运 动缓存区。
3)
假设用户有数据
5000
段,则在用户调用插补指令过程中,会出现前瞻缓存区和运动缓存区都被
压满的情况,因此,需要注意,若一直压数据,没有启动插补运动,当压入第
4297
段时(前瞻 缓存区和运动缓存区一共 4296
段大小),由于两缓存区都满了,所以调用指令会返回1。此时 需要调用
GTN_CrdSpace
查询运动缓存区的空间,只有当查询到当前运动缓存区有空间时,才能 继续调用插补指令压入剩下的数据。同样,最后用户需要调用
GTN_CrdData
(1, NULL, 0)
来将前 瞻缓存区数据压入运动缓存区。
private void motionDO1_Click(object sender, EventArgs e)
{
// TCrdPrm结构体变量,该结构体定义了坐标系
GTN.mc.TCrdPrm crdprm;
short sRtn = GTN.mc.GTN_GetCrdPrm(1, 1, out crdprm);
crdprm.dimension = 2; // 坐标系为二维坐标系
crdprm.synVelMax = 800; // 最大合成速度:500pulse/ms
crdprm.synAccMax = 8; // 最大加速度:1pulse/ms^2
crdprm.evenTime = 50; // 最小匀速时间:50ms
crdprm.profile1 = 1; // 规划器1对应到X轴
crdprm.profile2 = 2; // 规划器2对应到Y轴
crdprm.setOriginFlag = 1; // 需要指定坐标系的原点坐标的规划位置
crdprm.originPos1 = 0; // 坐标系的原点坐标的规划位置为(100, 100)
crdprm.originPos2 = 0;
sRtn = GTN.mc.GTN_SetCrdPrm(1, 1, ref crdprm);
Task.Run(LookAheadTest);
}
private static void LookAheadTest()
{
short sRtn;
int space;
GTN.mc.TCrdData[] crdData = new GTN.mc.TCrdData[200]; //前瞻缓冲区
int[] posTest = new int[2];
// 初始化坐标系1的FIFO0的前瞻模块
sRtn = GTN.mc.GTN_InitLookAhead(
1, //core
1, //crd
0, //fifo
5, //T //拐弯时间
7, //accMax
200, //n
ref crdData[0]); // 定义前瞻缓存区内存区
//压插补数据:小线段加工
posTest[0] = 0;
posTest[1] = 0;
{
sRtn = mc.GTN_LnXY( //向前瞻缓冲区冲写入数据共300段
1, //core
1, //crd
0 + posTest[0], //x
0 + posTest[1], //y
800, //vel
6, //acc
0, //velend
0); //fifo
if (0 != sRtn)
{
do
{
// 查询运动缓存区空间,直至空间不为0
sRtn = GTN.mc.GTN_CrdSpace(1, 1, out space, 0);
} while (0 == space);
// 重新调用上次失败的插补指令
sRtn = GTN.mc.GTN_LnXY(1, 1, 0 + posTest[0], 0 + posTest[1], 800, 6, 0, 0);
}
posTest[0] = 3000000;
posTest[1] = 0;
sRtn = mc.GTN_LnXY( //向前瞻缓冲区冲写入数据第2段
1, //core
1, //crd
0 + posTest[0], //x
0 + posTest[1], //y
800, //vel
6, //acc
0, //velend
0); //fifo
if (0 != sRtn)
{
do
{
// 查询运动缓存区空间,直至空间不为0
sRtn = GTN.mc.GTN_CrdSpace(1, 1, out space, 0);
} while (0 == space);
// 重新调用上次失败的插补指令
sRtn = GTN.mc.GTN_LnXY(1, 1, 0 + posTest[0], 0 + posTest[1], 800, 6, 0, 0);
}
posTest[0] = 3000000;
posTest[1] = 3000000;
sRtn = mc.GTN_LnXY( //向前瞻缓冲区冲写入数据第3段
1, //core
1, //crd
0 + posTest[0], //x
0 + posTest[1], //y
800, //vel
6, //acc
0, //velend
0); //fifo
if (0 != sRtn)
{
do
{
// 查询运动缓存区空间,直至空间不为0
sRtn = GTN.mc.GTN_CrdSpace(1, 1, out space, 0);
} while (0 == space);
// 重新调用上次失败的插补指令
sRtn = GTN.mc.GTN_LnXY(1, 1, 0 + posTest[0], 0 + posTest[1], 800, 6, 0, 0);
}
posTest[0] = 0;
posTest[1] = 3000000;
sRtn = mc.GTN_LnXY( //向前瞻缓冲区冲写入数据第4段
1, //core
1, //crd
0 + posTest[0], //x
0 + posTest[1], //y
800, //vel
6, //acc
0, //velend
0); //fifo
if (0 != sRtn)
{
do
{
// 查询运动缓存区空间,直至空间不为0
sRtn = GTN.mc.GTN_CrdSpace(1, 1, out space, 0);
} while (0 == space);
// 重新调用上次失败的插补指令
sRtn = GTN.mc.GTN_LnXY(1, 1, 0 + posTest[0], 0 + posTest[1], 800, 6, 0, 0);
}
posTest[0] = 0;
posTest[1] = 0;
sRtn = mc.GTN_LnXY( //向前瞻缓冲区冲写入数据第5段
1, //core
1, //crd
0 + posTest[0], //x
0 + posTest[1], //y
600, //vel
5, //acc
0, //velend
0); //fifo
if (0 != sRtn)
{
do
{
// 查询运动缓存区空间,直至空间不为0
sRtn = GTN.mc.GTN_CrdSpace(1, 1, out space, 0);
} while (0 == space);
// 重新调用上次失败的插补指令
sRtn = GTN.mc.GTN_LnXY(1, 1, 0 + posTest[0], 0 + posTest[1], 800, 6, 0, 0);
}
}
// 将前瞻缓存区中的数据压入控制器
IntPtr crdDataNULL = new IntPtr();
sRtn = GTN.mc.GTN_CrdData(1, 1, crdDataNULL, 0);
// 启动运动
sRtn = GTN.mc.GTN_CrdStart(1, 1, 0); //mask bit0 对应坐标系 1,bit1 对应坐标系 2,0:不启动该坐标系,1:启动该坐标系。
}
拐弯时间
(T)
:
GTN_InitLookAhead
指令的第三个参数,单位:
ms
。
T
的经验范围是:
1ms~10ms
, T 越大,计算出来的终点速度越大,但却降低了加工精度;反之,提高了加工的精度,但计算出 的终点速度偏低。因此要合理选择 T
值。
最大加速度
(accMax)
:
GTN_InitLookAhead
指令的第四个参数,单位:
pulse/ms2
。系统能承受的 最大加速度,根据不同的机械系统和电机驱动器取值不同。
前瞻缓存区
(pLookAheadBuf)
:
前瞻缓存区是用户在应用程序中自己定义的,用于存放描述运动轨 迹的数组。用户应根据自己的需要以及计算机的条件定义合适的缓存区大小,并且要在
GTN_InitLookAhead
指令的第五个参数中说明数组的大小
运动缓存区:插补缓存区是运动控制器内部专门用于插补运动的缓存区资源,大小
4096
段,每
一段可以放一条指令。 当前瞻缓存区的段数不为 0
时,用户调用缓存区指令传递的插补数据先进入前瞻缓存区,当前瞻 缓存区放满之后,如果再有新的数据传入,最先进入前瞻缓存区的数据,则会进入插补缓存区。 如果用户所有的插补数据已经输入完毕,前瞻缓存区中还有数据没有进入插补缓存区,这时,需 要调用
GTN_CrdData
(1, NULL, 0)
,运动控制器会将前瞻缓存区的数据依次传递给插补缓存区, 直到前瞻缓存区被清空为止。 在数据量比较大的时候,用户需要配合
GTN_CrdSpace
指令查询插补缓存区的剩余空间,在有空 间的时候再调用缓存区指令传递数据,如果插补缓存区已满,调用缓存区指令将会返回错误,说 明该段插补数据没有输入成功,需要再次输入该段插补数据。