概述
文章目录
- 0. 文章说明
- 1. PVT说明
- 2.PVT 插值模式
- 2.1 三次多项式插值(eCUBIC_POLYNOM)
- 2.2 五次多项式插值(eQUINTIC_ON_CUBIC)
- 2.3 七次样条多项式(eSEPTIC_ON_CUBIC)
- 2.4 正弦插值
- 2.4.1 三角正弦插值(eCYCLOID_VELOCITY_MODIFIED1)
- 2.4.2 梯形正弦插值(eCYCLOID_VELOCITY_MODIFIED2)
- 2.4.3 正弦速度插值(eCYCLOID_POSITION)
- 3. 数据加载
- 4. PVT 运动
- 5.动态模式
- 5.1 初始化列表
- 5.2 加载数据
- 5.3 循环模式(Cyclic Mode)
- 6.PVT在C++中的实现
- 6.1 PVT表初始化函数
- 6.2 PVT数据点加载函数
- 6.3 PVT移动函数
- 7.PVT 使用教程
- 7.1 使用方法
- 7.2 例程
0. 文章说明
请忽略前面的扯淡内容,直接跳至3
1. PVT说明
详情参见API手册P783
通常,PV/PVT运动由一组点定义,如果在当前位置之前提供了多个点,profiler可以构建一个三次多项式来计算下一个要下载到驱动器的位置。该路径是实时计算的,因此所有多项式系数的计算都在实时模块中进行。PV/PVT运动不需要执行完整的数据,只需要最少的点。
与样条相似,输入表存储在共享内存中,但与样条不同的是,只存储坐标,而多项式系数在实时模块中计算。表可以通过文件加载,也可以通过用户提供的N x M数组加载。可以选择将一行或几行附加到表中,但要在合理的约束条件下;例如,不能将数据附加到当前段,分析器正在操作。PV/PVT函数块仅适用于NC循环/插补模式。
用户提供的点多于3个,即可应用PVT插补。
2.PVT 插值模式
对于PVT表的定义,遵循以下格式:
Ti为时间,有两种模式:两点之间的相对时间、各点分别对应的绝对时间。
轴的数量不受三个坐标轴的限制,最多可达16个坐标轴。
2.1 三次多项式插值(eCUBIC_POLYNOM)
三次多项式保证了位置和速度的连续性。它的缺点是在每一个连接点上都有加速度和加加速度(即簇动jerk)造成的不连续。
2.2 五次多项式插值(eQUINTIC_ON_CUBIC)
五次多项式保证了位置、速度和加速度的连续性。它的缺点是在每一个连接点上都有加加速度造成的不连续。
2.3 七次样条多项式(eSEPTIC_ON_CUBIC)
七次多项式保证了连续的位置,速度,加速度和加加速度。它的缺点是振幅变化比我们看到的低次多项式更高。这是在大多数情况下可以推荐的最通用的插值模式。
2.4 正弦插值
2.4.1 三角正弦插值(eCYCLOID_VELOCITY_MODIFIED1)
三角形正弦加速度-修正三角形加速度与AC(t)和DC(t)由正弦增加到某个最大值,然后下降到零。它保证连续的位置,速度,加速度和加加速度。
2.4.2 梯形正弦插值(eCYCLOID_VELOCITY_MODIFIED2)
梯形正弦加速度或修正梯形加速度通常由两部分组成:
- 加速度随正弦曲线从0增加到ACmax,运动与ACmax(抛物线位置,线速度剖面)和加速度下降的正弦为零。
- 由正弦波由零到-ACmax减速运动,由-ACmax减速运动(抛物线位置剖面,线速度剖面),由正弦波减速增加到零。
它保证连续的位置,速度,加速度和加加速度(如果所有的段定义与此插值模式)。
2.4.3 正弦速度插值(eCYCLOID_POSITION)
这种插补方式产生摆线位置和正弦速度插补。正弦速度是这种插值类型的一个优点,但它有两个明显的缺点。首先,它的开始和结束都伴随着最大的jerk。其次,它的应用具有局限性,当Y(i)≠0和Y(i+1)≠0时必须满足开始和结束导数服从条件△Y(i)=0.5(Y(i)+Y(i+1))△X(i)。(此处存疑) 因此,这种插补方式主要用于Y(i)≠0或者Y(i)=0的情况。
3. 数据加载
将每一行输入数据作为表存储在共享内存中,表示时间、位置、速度和向量位置。例如,我们在使用m个轴的情况下,表中第n行按如下格式生成:
用户可以通过以下几种方式提供数据:
- 提供一个包含数据点的表的文件
- 提供一个包含数据点的数组,这些数据点也可以附加到给定索引中的现有路径
当用户决定向现有路径添加点时,他必须知道:
- 表的大小是有限的,应该知道它的最大大小
- 仅对于dynamic Append(动态添加),当点的数量超过表的上限时,这些点将被附加到表的开头。
- 不可能追加到当前段(目前,如果当前索引是X,用户只能从X + 3追加)。
在数据加载期间,从文件中读取这些点。然而,与样条不同的是,它们无需预先计算就可以插入共享内存。
禁止将数据附加到从文件加载的表中。如果T等于循环时间,应该使用一个简单的profiler。
4. PVT 运动
运动是使用一种特殊类型的函数块来执行的。当插入这个函数块类型时,应用一个特殊的轮廓仪来计算多项式系数并沿着计算的轨迹移动。
每一个循环下一段都向前计算。函数块包括指向当前选定路径数据起点的指针,包括所有路径常数数据,即维数、点数等。此外,函数块包含当前工作索引,因此如果用户希望添加点,系统将避免在当前工作索引中添加这些点。当PVT函数块处于运动状态时,只能通过STOP命令(类似于样条行为)以任何缓冲模式插入其他函数块。
5.动态模式
Maestro还支持动态地将数据加载到Maestro,即用户可以基于现有数据启动运动,剩余数据可以稍后添加。这个概念允许用户在考虑软件约束的情况下动态地更改路径。此时,实现了两种附加子模式:自动和手动。
- 在自动模式下,大师将记住添加数据的最后一个索引,并将在下一次添加到该索引中。
- 在手动模式下,用户必须提供索引,并在其中添加他希望添加的点。
实时模块使用计算出的点数来检查路径是否到达终点,即如果分配了2000个点数,而用户只插入了1000个点数,则不应遍历1000个点数的限制。此外,仅在动态模式下,当索引接近路径末尾时,才可以发送潜流事件。
5.1 初始化列表
在向表添加点之前,用户应该初始化它。这可以通过两种方式实现;通过从文件中加载一个表,或调用一个专用函数,该函数将初始化“常量”路径参数,如维度、最大点数等。
此外,用户应该选择附加操作是静态执行还是动态执行。如果选择动态附加,则用户应该选择下溢阀值。
5.2 加载数据
从数组中加载数据有两种模式——静态和动态。静态模式非常类似于从文件模式加载,当表中填充了最大值时,将加载表,并且不允许添加值。动态模式默认为循环模式,当超过潜流阀值时将生成实时事件。每次插入点的数量下降到预定义阈值以下时,就会向用户空间生成一个事件。使用现有的事件机制——用户根据需要处理溢出。
在向表中添加数据时,用户可以控制两个参数;是否附加在自动模式?如果没有,则第二个参数是要追加的索引。基于这两个参数,算法安全插入数据。
如果轴/向量在运动,则使用索引delta来维持计算出的路径(索引delta = 3)。如果当前索引与要追加的起始索引之差小于delta,则禁止插入。
在循环模式下,数据被附加到给定的索引(自动或手动),当数据到达PVT段的末尾时,数据被自动附加到开头。在非循环模式下,当数据到达PVT段的末尾时,返回一个错误。
文件中的数据被识别为double型,则对于m轴一行数据需要((M2 + 1) * size of(double)) bytes,分配的总内存将是(N * (M2 + 1) * size (double))
5.3 循环模式(Cyclic Mode)
为了支持循环模式,对循环缓冲区进行了管理。主要的限制是附加的缓冲区的大小不能超过表的大小,因为这样结束时将运行在开始时。此外,如果附加索引在当前索引之后,用户应该保持一个最小的增量: Abs(current – start) < 3
如果追加的索引在当前索引之前,则应保持以下内容:start + block size < current
6.PVT在C++中的实现
PVT (ECAM和样条,在将来)的基类是继承自CMMCMotionAxis的类CMMCAxis,即它包含所有CMMCAxis成员和方法。类CMMCMotionAxis函数在第8章中详细介绍:位置、速度、时间(PVT)运动。类CMMCMotionAxis保留了本文档中描述的用于C函数块的字段参数属性和值。
应该注意的是,私有和受保护的函数及其操作应该对用户透明,而不是供用户一般应用。
PVT和ECAM的基类CMMCMotionAxis继承自CMMCAxis,即它包含所有CMMCAxis成员和方法。
该方法继承自CMMCAxis类,但在CMMCMotionAxis类中重载,因为该方法不适合CMMCAxis实现的需求。而是使用BindAxis方法,InitAxisData只会抛出一个异常。
PVT包含以下方法:
函数 | 说明 |
---|---|
InitPVTTable | 该方法是MMC_InitTableCmd()命令的包装器。 |
LoadPVTTable | 该方法从文件中加载PVT表 |
AppendPointsToPVTTable | 此方法将点附加到当前PVT表(在自动模式下) |
AppendPointsToPVTTable | 此方法将点附加到当前PVT表(在手动模式下) |
MovePVT | 该方法插入PVT函数块 |
UnloadPVTTable | 卸载PVT表 |
详细请参考《Maestro Administrative and Motion API》手册第8章
6.1 PVT表初始化函数
// 初始化列表函数介绍
//此函数根据维度和点数在共享内存中分配内存段。
//应该注意的是,当使用这个函数时,没有加载任何数据。函数返回hMemHandle,它是唯一的路径ID(类似于样条)。
virtual MC_PATH_REF InitPVTTable(unsigned long ulMaxPoints,
unsigned long ulUnderflowThreshold,
unsigned char ucIsCyclic,
unsigned char ucIsPosAbsolute,
unsigned short usDimension,
MC_COORD_SYSTEM_ENUM eCoordSystem,
NC_MOTION_TABLE_TYPE_ENUM eTableMode = eNC_TABLE_PVT_ARRAY) throw (CMMCException);
/*
* 参数 ulMaxPoints - 表能够包含的最大点数(在非循环模式下),任何+ve值都可以接受。
* 参数 ulUnderflowThreshold - 如果当前索引和结束索引之间的点数低于此值,则将生成一个事件。值不能大于ulMaxPoints值。
* 参数 ucIsCyclic - 这个列表应该是循环的吗?也就是说,当索引到达表的末尾时,它会滚动并从头开始?。布尔值为0或1
* 参数 ucIsDynamic - 是否允许动态追加
* 参数 ucIsPosAbsolute - 是否是绝对位置,1为绝对位置,0为相对位置
* 参数 usDimension - PVT表的维度
* 参数 eSplineMode - 定义样条函数的计算方法 (FT/VT/CV_DWELL)
* 参数 ConstVelocity - 所有的线段都必须有恒定的速度
* 参数 FixedType - 在所有段上强制使用常数时间(ms)
* 参数 eCoordSystem - 支持的坐标系类型
* 参数 eTableMode - 这个枚举用作这些函数的输入,以便区分ECAM和PVT.目前只能应用eNC_TABLE_PVT_FILE和eNC_TABLE_PVT_ARRAY(默认采用三次样条插补)。
* //对于插补这一点,可能不如PMAC。
* return void
*/
6.2 PVT数据点加载函数
//自动添加
void AppendPVTPoints(MC_PATH_REF hMemHandle,
double (&dTable)[NC_PVT_ECAM_MAX_ARRAY_SIZE],
unsigned long ulNumberOfPoints,
unsigned char ucIsTimeAbsolute = 0,
NC_MOTION_TABLE_TYPE_ENUM eTableType = eNC_TABLE_PVT_ARRAY) throw (CMMCException);
/*
* brief 此函数将点追加到现有表
* 参数 hMemHandle - 指向共享内存指针所在的日志项的句柄
* 参数 dTable[NC_PVT_ECAM_MAX_ARRAY_SIZE] - 指向数组值表的指针,数组最大值限制为170。
* 参数 ulNumberOfPoints - 要追加的行中点数,任何+ve值都可以接受。
* 例如:对于三轴,一个轨迹点即一行,有7个参数(T,Px,Vx,Py,Vy,Pz,Vz),要添加n个轨迹点,则数组中共有7n个点,此时ulNumberOfPoints为n
* 参数 ucIsTimeAbsolute - 时间是绝对的吗?
* 0为绝对,每一个“时间”输入都被用作绝对时间,此时当前点将结束运动并到达所需位置。
* 1为相对,每一个“时间”输入都被用作从以前的点移动到当前点结束所花费的时间。
* 参数 NC_MOTION_TABLE_TYPE_ENUM eTableType - 这个枚举用作这些函数的输入,以便区分ECAM和PVT.目前只能应用eNC_TABLE_PVT_FILE和eNC_TABLE_PVT_ARRAY。
* return void
*/
//--------------------------------------------------------------------------------------------
//手动添加
void AppendPVTPoints(MC_PATH_REF hMemHandle,
double (&dTable)[NC_PVT_ECAM_MAX_ARRAY_SIZE],
unsigned long ulNumberOfPoints,
unsigned long ulStartIndex,
unsigned char ucIsTimeAbsolute = 0,
NC_MOTION_TABLE_TYPE_ENUM eTableType = eNC_TABLE_PVT_ARRAY) throw (CMMCException);
6.3 PVT移动函数
//PVT运动
virtual void MovePVT(MC_PATH_REF hMemHandle, MC_COORD_SYSTEM_ENUM eCoordSystem) throw (CMMCException);
/*
* brief 这个函数沿着PT/PVT表移动(在线样条)
* param hMemHandle - 表访问句柄
* param eCoordSystem - 坐标系设置 - 与单轴无关
* return 0 执行成功则返回0,否则执行错误
*/
//PT运动
virtual int MovePT(MC_PATH_REF hMemHandle, MC_COORD_SYSTEM_ENUM eCoordSystem) throw (CMMCException);
7.PVT 使用教程
7.1 使用方法
三步走(数组方式静态加载):
- InitPVTTable()
- AppendPVTPoints() / AppendPointsToPVTTable()
- MovePVT()
7.2 例程
/*
================================================================================
Name: pvt_motor.cpp
Author: Jack Soong
Version: 1.00
Description: 测试数组加载的PVT功能
================================================================================
*/
#include "mmc_definitions.h"
#include "mmcpplib.h"
#include <iostream>
#include <unistd.h>
using namespace std;
int giAxis1Status,giAxis2Status,giAxis3Status,giAxis4Status;
void TableUnderflow(unsigned short usAxisRef);
void Emergency_Received(unsigned short usAxisRef, short sEmcyCode);
int CallbackFunc(unsigned char* recvBuffer, short recvBufferSize,void* lpsock);
void SetData();
//===========================================================================================
int main(int argc, char* argv[])
{
CMMCConnection MyConnectionClass;
unsigned int ui_conn_hndl;
CMMCGroupAxis Group1;
CMMCSingleAxis Axis1,Axis2,Axis3,Axis4;
ui_conn_hndl = MyConnectionClass.ConnectIPCEx(0x7fffffff,(MMC_MB_CLBK)CallbackFunc);
MyConnectionClass.GetVersion();
MyConnectionClass.GetVersion_Ex();
//关联轴
Axis1.InitAxisData("a01",ui_conn_hndl);
Axis2.InitAxisData("a02",ui_conn_hndl);
Axis3.InitAxisData("a03",ui_conn_hndl);
Axis4.InitAxisData("a04",ui_conn_hndl);
//为特定类型回调注册事件回调
MyConnectionClass.RegisterEventCallback(MMCPP_TABLE_UNDERFLOW,(void*)TableUnderflow);
MyConnectionClass.RegisterEventCallback(MMCPP_EMCY, (void*)Emergency_Received);
MMC_MOTIONPARAMS_GROUP stVectorDefault ;
stVectorDefault.fAcceleration = 1000000; //加速度
stVectorDefault.fDeceleration = 1000000; //负加速度
stVectorDefault.fJerk = 20000000; //加加速度
stVectorDefault.fVelocity = 1000000; //速度
stVectorDefault.eBufferMode = MC_BUFFERED_MODE; //定义轴的行为
stVectorDefault.eTransitionMode = MC_TM_NONE_MODE; //转换模式
stVectorDefault.eCoordSystem = MC_ACS_COORD; //定义支持的坐标系统的类型
stVectorDefault.m_uiExecDelayMs = 0; //执行下一个动作的延迟(以秒为单位)。任意+ve整数值
stVectorDefault.ucSuperimposed = 0; //是否操作了叠加选项
stVectorDefault.ucExecute =1; //从上升边缘启动执行命令
// Initialize Vctor names and default parameters.初始化Vctor名称和默认参数。
Group1.InitAxisData("v01",ui_conn_hndl) ; //关联轴组
Group1.SetDefaultParams(stVectorDefault); //更新轴组参数///
giAxis1Status = Axis1.ReadStatus() ;
if(giAxis1Status & NC_AXIS_ERROR_STOP_MASK)
{
Axis1.Reset() ;
giAxis1Status = Axis1.ReadStatus() ;
}
giAxis2Status = Axis2.ReadStatus() ;
if(giAxis2Status & NC_AXIS_ERROR_STOP_MASK)
{
Axis2.Reset() ;
giAxis2Status = Axis2.ReadStatus() ;
}
giAxis3Status = Axis3.ReadStatus() ;
if(giAxis3Status & NC_AXIS_ERROR_STOP_MASK)
{
Axis3.Reset() ;
giAxis3Status = Axis3.ReadStatus() ;
}
giAxis4Status = Axis4.ReadStatus() ;
if(giAxis4Status & NC_AXIS_ERROR_STOP_MASK)
{
Axis4.Reset() ;
giAxis4Status = Axis4.ReadStatus() ;
}
/*----------------------- All axis and group enable ----------------------------*/
Axis1.PowerOn();
while (!(Axis1.ReadStatus() & NC_AXIS_STAND_STILL_MASK));
Axis2.PowerOn();
while (!(Axis2.ReadStatus() & NC_AXIS_STAND_STILL_MASK));
Axis3.PowerOn();
while (!(Axis3.ReadStatus() & NC_AXIS_STAND_STILL_MASK));
Axis4.PowerOn();
while (!(Axis4.ReadStatus() & NC_AXIS_STAND_STILL_MASK));
cout<<"aaa"<<endl;
Group1.GroupEnable();
cout<<"bbb"<<endl;
while (!(Group1.ReadStatus() & NC_GROUP_STANDBY_MASK));
cout<<"ccc"<<endl;
/*----------------------- Go Home ----------------------------*/
/* All axis go back to absolute 0 position */
//所有电机回零
//两种写法,如果不用类,直接指定,则可以直接赋值,具体参考手册 Group移动部分
//轴组回零有问题
double db_pos[4] = {0,0,0,0};
Group1.MoveLinearAbsolute(100000, db_pos); //参数1为最大的速度值,参数2为轴运动目标
while (!(Group1.ReadStatus() & NC_GROUP_STANDBY_MASK));
sleep(0.5);
/*----------------------- Set data table ----------------------------*/
/*----------------------- PVT Table Setting ----------------------------*/
MC_PATH_REF PVTReference;
double dTable[170]={
0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 655360, 1000000, 655360, 1000000, 655360, 1000000, 655360, 1000000,
0.2, 1310720, 1000000, 1310720, 1000000, 1310720, 1000000, 1310720, 1000000,
0.2, 1966080, 1000000, 1966080, 1000000, 1966080, 1000000, 1966080, 1000000,
0.2, 2621440, 1000000, 2621440, 1000000, 2621440, 1000000, 2621440, 1000000,
0.2, 3276800, 1000000, 3276800, 1000000, 3276800, 1000000, 3276800, 1000000,
0.2, 3932160, 1000000, 3932160, 1000000, 3932160, 1000000, 3932160, 1000000,
0.2, 4587520, 1000000, 4587520, 1000000, 4587520, 1000000, 4587520, 1000000,
0.2, 5242880, 1000000, 5242880, 1000000, 5242880, 1000000, 5242880, 1000000,
0.2, 5898240, 1000000, 5898240, 1000000, 5898240, 1000000, 5898240, 1000000,
1, 6553600, 0, 6553600, 0, 6553600, 0, 6553600, 0,
};
//
/*----------------------- PVT Motion ----------------------------*/
PVTReference = Group1.InitPVTTable(300,3,0,1,4,MC_ACS_COORD);
Group1.AppendPVTPoints(PVTReference,dTable,11);//相对时间
Group1.MovePVT(PVTReference,MC_ACS_COORD);
int GroupStatus;
while(!((GroupStatus = Group1.ReadStatus()) & NC_GROUP_STANDBY_MASK))
{
usleep(1000);
cout << "Moving !!!" << endl;
}
/*----------------------- 卸载PVT数据,Disable各轴及轴组 ----------------------------*/
Group1.UnloadPVTTable(PVTReference);
Group1.GroupDisable();
Axis1.PowerOff();
Axis2.PowerOff();
Axis3.PowerOff();
Axis4.PowerOff();
MMC_CloseConnection(ui_conn_hndl);
printf("Program finishedn");
return 0;
}
//===========================================================================================
void TableUnderflow(unsigned short usAxisRef)
{
cout << "usAxisRef = " << usAxisRef << endl;
//bSendpoints = true;
return;
}
void Emergency_Received(unsigned short usAxisRef, short sEmcyCode)
{
printf("Emergency Message Received on Axis %d. Code: %xn",usAxisRef,sEmcyCode) ;
}
int CallbackFunc(unsigned char* recvBuffer, short recvBufferSize,void* lpsock)
{
switch(recvBuffer[1])
{
case EMCY_EVT:
printf("Emergency Event receivedrn") ;
break ;
case MOTIONENDED_EVT:
printf("Motion Ended Event receivedrn") ;
break ;
case HBEAT_EVT:
printf("H Beat Fail Event receivedrn") ;
break ;
case PDORCV_EVT:
printf("PDO Received Event received - Updating Inputsrn") ;
break ;
case DRVERROR_EVT:
printf("Drive Error Received Event receivedrn") ;
break ;
case HOME_ENDED_EVT:
printf("Home Ended Event receivedrn") ;
break ;
case SYSTEMERROR_EVT:
printf("System Error Event receivedrn") ;
break ;
}
return 1 ;
}
最后
以上就是重要大米为你收集整理的Platinum Maestro运动控制器 —— PVT模式笔记0. 文章说明1. PVT说明2.PVT 插值模式3. 数据加载4. PVT 运动5.动态模式6.PVT在C++中的实现7.PVT 使用教程的全部内容,希望文章能够帮你解决Platinum Maestro运动控制器 —— PVT模式笔记0. 文章说明1. PVT说明2.PVT 插值模式3. 数据加载4. PVT 运动5.动态模式6.PVT在C++中的实现7.PVT 使用教程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复