在先前的两次文章当中使用了PC SDK的几个功能,在PC SDK中称为域即domain,使用到了Controllers、Discovery和Motion几个域,这次将会来到另一个比较重要的域即Messaging domain,使用消息队列的形式进行机器人的实时控制,这也是笔者所知的为数不多的几种实时控制ABB机器人的方法。
使用上位机对机器人进行实时控制的方法,笔者目前知道两种,其一是修改RAPID代码中的特定点坐标,然后执行点动任务,该任务只包含一个运动指令;其二是使用下述信息队列,直接下发rapiddata格式的目标点,下位机收到信息后会尝试解释信息,并进一步执行。
感谢应用这种方法并给出demo的开发者,完成这部分功能的时候参考了很多项目。
5. PC SDK信息队列
何为信息队列
PC SDK的Messaging域的信息队列可用于在PC SDK应用程序和RAPID任务之间发送和接收数据。RAPID信息队列包括RAPID数据类型和RAPID指令以及用于发送和接收数据的功能。
它使RAPID任务之间或RAPID任务与PC SDK应用程序之间能够通信。需要注意的是,此部分需要PC SDK的版本高于5.11.
官方给出的信息队列原理图为:
一般来说,信息传递是在任务执行时完成,虽然可以在rapid代码停止运行时发送消息,机器人也会正常接收(但不会执行),接收的消息会存储在机器人堆栈中,在执行任务(tasks)时调用。个人不是很推荐这种方式。
所谓的信息队列在系统下应当称为IPC即进程间通信,其定义为:
简单来说,信息队列是一个列表,机器人会逐一实现这些消息,并给出答复。需要注意的是,对于特定场合,机器人同样可以以相同的方式向上位机发送消息。一般来说,主要使用的功能是下发信息给机器人执行,所以此处仅实现下载队列作为示例。
信息队列逻辑顺序
一个信息队列必须同时在下位机和上位机中构造队列,此时只能执行包含队列的下位机任务。
一个信息的产生与执行需要经过如下几个步骤:
- 在上位机中,连接到RAPID任务的队列
- 创建上位机的一条信息
- 下发到机器人中
- 在机器人的下位机任务的RAPID任务程序中,设置一个trap来捕获这条消息,消息接入中断,读取,并执行这个消息。
创建一个信息队列
一个信息队列所包含的参数包含了几种,队列名称,队列单条消息长度,队列包含消息总数,其具体的创建代码为:
static public void QueueConnect(string PCQueueName,string RobQueueName)
{
robotMessageQueue = controller.Ipc.GetQueue(PCQueueName);
if (controller.Ipc.Exists(RobQueueName))
{
pcMessageQueue = controller.Ipc.GetQueue(RobQueueName);
}
else
{
pcMessageQueue = controller.Ipc.CreateQueue(RobQueueName,50,Ipc.IPC_MAXMSGSIZE);
}
}
此处代码调用时间一般是在上位机连接上控制器并启动控制器任务的时候。
代码存在于RobotConnection当中,其中包含控制器类controller, 队列类pcMessageQueue,robotMessageQueue。
创建队列必须在机器人已经连接后,关闭队列必须在机器人断开连接前。
关闭队列后关闭机器人连接的代码附上:
if (controller != null)
{
if (pcMessageQueue != null)
{
controller.Ipc.DeleteQueue(pcMessageQueue.QueueId);
pcMessageQueue = null;
}
controller.Logoff();
controller.Dispose();
}
下位机队列实现
下位机实现信息队列可以参考SDK manual的例程,包含所需的基本功能,下发一个布尔量,机器人收到之后回复,在此贴出这段例程用于参考:
MODULE RAB_COMMUNICATION
VAR bool flag := FALSE;
VAR intnum connectnum;
PROC main()
CONNECT connectnum WITH RABMsgs;
IRMQMessage flag, connectnum;
WHILE flag = FALSE DO
!do something, eg. normal processing...
WaitTime 3;
ENDWHILE
!PC SDK message received - do something...
TPWrite "Message from PC SDK, will now...";
IDelete connectnum;
EXIT;
ENDPROC
TRAP RABMsgs
VAR rmqmessage msg;
VAR rmqheader header;
VAR rmqslot rabclient;
VAR num userdef;
VAR string ack := "Acknowledged";
RMQGetMessage msg;
RMQGetMsgHeader msg \Header:=header
\SenderId:=rabclient\UserDef:=userdef;
!check data type and assign value to flag variable
IF header.datatype = "bool" THEN
RMQGetMsgData msg, flag;
!return receipt to sender
RMQSendMessage rabclient, ack;
ELSE
TPWrite "Unknown data received in RABMsgs...";
ENDIF
ENDTRAP
ENDMODULE
这段代码较为好懂,在此解释如下:
MODULE RAB_COMMUNICATION
VAR bool flag := FALSE;//待修改的量
VAR intnum connectnum;//一个标记位,格式必须是intnum,用于引发中断
PROC main()
CONNECT connectnum WITH RABMsgs;//绑定中断,这个必须有,With之后是中断函数名称,此后,connectnum即表示这个中断
IRMQMessage flag, connectnum;//说明中断绑定于待修改的量
WHILE flag = FALSE DO
!do something, eg. normal processing...
WaitTime 3;
ENDWHILE
!PC SDK message received - do something...
TPWrite "Message from PC SDK, will now...";
IDelete connectnum;//取消中断
EXIT;
ENDPROC
TRAP RABMsgs//中断定义
VAR rmqmessage msg;
VAR rmqheader header;//这个是消息头
VAR rmqslot rabclient;
VAR num userdef;
VAR string ack := "Acknowledged";
RMQGetMessage msg;
RMQGetMsgHeader msg \Header:=header
\SenderId:=rabclient\UserDef:=userdef;
!check data type and assign value to flag variable
IF header.datatype = "bool" THEN
RMQGetMsgData msg, flag;//收到消息"bool;TRUE"则引入中断
!return receipt to sender
RMQSendMessage rabclient, ack;
ELSE
TPWrite "Unknown data received in RABMsgs...";
ENDIF
ENDTRAP
ENDMODULE
以上内容是信息队列MessageQueue的初步构建,这周或者下周更新使用消息队列完成半实时控制的内容