如何使用 Tc3_IoTBase 在 TwinCAT 中处理大量 MQTT 订阅主题
How to handle a lot of MQTT subscription topics in TwinCAT using Tc3_IoTBase
我可以使用 this 代码阅读多个订阅主题。但是,我订阅了很多不同的主题,而长 if 语句正在减慢我的代码速度。我已经不得不在 PlcTask 中将循环滴答的数量增加到 20(这可能有点过分,但 10 是不够的)。我正在寻找一种更智能的解决方案,该解决方案将以更少的周期滴答运行。在下面显示的代码中,很清楚这个 IF 语句得到了多长时间,这甚至不是整个 if 语句(仅针对主题 machine 和 motion1)。
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
IF fbMessage.CompareTopic(sTopic:='machine/on') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOnPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='machine/off') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOffPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/position') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Postion := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/velocity') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Velocity := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/acceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Acceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/deceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Deceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/execute') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Execute := STRING_TO_LREAL(sPayloadRcv);
// same for motion2 and motion3
END_IF
END_IF
END_IF
我的主题像 'motion1/position' 'motion1/acceleration' 'motion2/acceleration' 等等(我希望你明白)。所以我已经可以通过订阅 'motion1/#' 来订阅所有 motion1 主题了。所以我尝试使用 fb.Message.CompareTopic(sTopic:='motion1/#') 来查找属于 motion1 的主题,而不是使用识别主题 'motion1/somethingsomething' 的 if 语句。但是 fb.Message.CompareTopic(sTopic:='motion1/#') 无法识别 motion1 主题。
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
IF fbMessage.CompareTopic(sTopic:='machine/on') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOnPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='machine/off') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOffPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/#') THEN
IF fbMessage.CompareTopic(sTopic:='motion1/position') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Postion := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/velocity') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Velocity := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/acceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Acceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/deceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Deceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/execute') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Execute := STRING_TO_LREAL(sPayloadRcv);
END_IF
// same for motion2 and motion3
END_IF
END_IF
END_IF
因此,我展示的第一个代码确实从 MQTT 读取了我需要的所有消息,这非常好。然而,应该有一种更有效的方法来做到这一点。我尝试了第二个代码中显示的方法,但是没有用。
我的问题解决了!这是我的代码:
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
fbMessage.GetTopic(pTopic:=ADR(sTopicRcv), nTopicSize := SIZEOF(sTopicRcv));
IF fbMessage.CompareTopic(sTopic:='machine/on') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOnPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='machine/off') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOffPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF INT_TO_BOOL(FIND(sTopicRcv,'motion1')) THEN
IF fbMessage.CompareTopic(sTopic:='motion1/position') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Postion := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/velocity') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Velocity := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/acceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Acceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/deceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Deceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/execute') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Execute := STRING_TO_LREAL(sPayloadRcv);
END_IF
// same for motion2 and motion3
END_IF
END_IF
END_IF
好的,还有很多需要改进的地方。首先让我们创建 SPLIT
函数,将主题转换为数组
FUNCTION SPLIT : ARRAY[0..255] OF STRING(250)
VAR_INPUT
STR: STRING(250);
CHAR: STRING(1);
END_VAR
VAR
iPos: INT;
sTest: STRING(250);
iIndex: INT;
xFinish: BOOL;
END_VAR
sTest := STR;
REPEAT
iPos := FIND(sTest, CHAR);
IF iPos = 0 THEN
SPLIT[iIndex] := sTest;
xFinish := TRUE;
ELSE
SPLIT[iIndex] := LEFT(sTest, iPos - 1);
sTest := RIGHT(sTest, LEN(sTest) - iPos);
END_IF;
iIndex := iIndex + 1;
UNTIL (xFinish = TRUE)
END_REPEAT;
END_FUNCTION
现在如何查找当前主题是否 'motion1' 相关
VAR
arsTopic: ARRAY[0..255] OF STRING(250);
END_VAR
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
fbMessage.GetTopic(pTopic:=ADR(sTopicRcv), nTopicSize := SIZEOF(sTopicRcv));
arsTopic := SPLIT(sTopicRcv, '/');
IF (arsTopic[0] = 'motion1') THEN
// do your staff
END_IF
END_IF
END_IF
但是由于您随后将不同的有效负载加载到不同的变量,因此我会创建一个地图。我不知道你所有的程序,但据我所知,我会从:
TYPE SR_MOTION:
STRUCT
lrPostion: LREAL;
lrVelocity: LREAL;
lrAcceleration: LREAL;
lrDeceleration: LREAL;
lrExecute: LREAL;
END_STRUCT
END_TYPE
SR 表示 Sergey Romanov,您可以使用任何前缀
现在让我们创建您拥有的动作数组。假设您有 3 个。这样我们就可以将运动数分离到单独的变量中。请注意,为了让您的代码顺利运行而不会产生太多垃圾代码,您的主题必须不是 motion1/velocity
,而是 motion/1/velosity
.
VAR
astMotions: ARRAY[1..3] OF SR_MOTION;
arsTopic: ARRAY[0..255] OF STRING(250);
i: INT;
END_VAR
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
fbMessage.GetTopic(pTopic:=ADR(sTopicRcv), nTopicSize := SIZEOF(sTopicRcv));
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
arsTopic := SPLIT(sTopicRcv, '/');
IF arsTopic[0] = 'machine' THEN
IF arsTopic[1] = 'on' THEN
Machine.bOnPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF arsTopic[1] = 'off' THEN
Machine.bOffPB := STRING_TO_BOOL(sPayloadRcv);
END_IF
ELSIF arsTopic[0] = 'motion' THEN
i := STRING_TO_INT(arsTopic[1]); // arsTopic[1] has motion number in `motion/1/velosity`
IF arsTopic[2] = 'position' THEN
astMotions[i].lrPosition := STRING_TO_LREAL(sPayloadRcv);
ELSIF arsTopic[2] = 'velosity' THEN
astMotions[i].lrVelosity := STRING_TO_LREAL(sPayloadRcv);
ELSIF arsTopic[2] = 'acceleration' THEN
astMotions[i].lrAcceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF arsTopic[2] = 'Deceleration' THEN
astMotions[i].lrDeceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF arsTopic[2] = 'execute' THEN
astMotions[i].lrExecute := STRING_TO_LREAL(sPayloadRcv);
END_IF
END_IF
END_IF
END_IF
这是所有 3 个动作的所有代码。
编辑:添加从主题中提取的数字
如果您不想将主题更改为 motion/1/velosity
,那么您可以使用此函数提取最后一个字符并转换为 int
FUNCTION TOPIC_TO_INT: INT
VAR_INPUT
str: STRING;
END_VAR
VAR
ps: POINTER TO ARRAY[0..200] OF BYTE;
END_VAR
ps := ADR(str);
TOPIC_TO_INT := BYTE_TO_INT(ps^[LEN(str) - 1]) - 48;
END_FUNCTION
然后在代码中而不是 i := STRING_TO_INT(arsTopic[1]);
你可以 i := TOPIC_TO_INT(arsTopic[0])
和代码的其余部分稍微改变。
所以如果你使用 TOPIC_TO_INT(STRING#'message2')
这个函数将 return INT#2
我可以使用 this 代码阅读多个订阅主题。但是,我订阅了很多不同的主题,而长 if 语句正在减慢我的代码速度。我已经不得不在 PlcTask 中将循环滴答的数量增加到 20(这可能有点过分,但 10 是不够的)。我正在寻找一种更智能的解决方案,该解决方案将以更少的周期滴答运行。在下面显示的代码中,很清楚这个 IF 语句得到了多长时间,这甚至不是整个 if 语句(仅针对主题 machine 和 motion1)。
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
IF fbMessage.CompareTopic(sTopic:='machine/on') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOnPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='machine/off') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOffPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/position') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Postion := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/velocity') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Velocity := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/acceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Acceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/deceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Deceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/execute') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Execute := STRING_TO_LREAL(sPayloadRcv);
// same for motion2 and motion3
END_IF
END_IF
END_IF
我的主题像 'motion1/position' 'motion1/acceleration' 'motion2/acceleration' 等等(我希望你明白)。所以我已经可以通过订阅 'motion1/#' 来订阅所有 motion1 主题了。所以我尝试使用 fb.Message.CompareTopic(sTopic:='motion1/#') 来查找属于 motion1 的主题,而不是使用识别主题 'motion1/somethingsomething' 的 if 语句。但是 fb.Message.CompareTopic(sTopic:='motion1/#') 无法识别 motion1 主题。
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
IF fbMessage.CompareTopic(sTopic:='machine/on') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOnPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='machine/off') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOffPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/#') THEN
IF fbMessage.CompareTopic(sTopic:='motion1/position') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Postion := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/velocity') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Velocity := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/acceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Acceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/deceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Deceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/execute') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Execute := STRING_TO_LREAL(sPayloadRcv);
END_IF
// same for motion2 and motion3
END_IF
END_IF
END_IF
因此,我展示的第一个代码确实从 MQTT 读取了我需要的所有消息,这非常好。然而,应该有一种更有效的方法来做到这一点。我尝试了第二个代码中显示的方法,但是没有用。
我的问题解决了!这是我的代码:
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
fbMessage.GetTopic(pTopic:=ADR(sTopicRcv), nTopicSize := SIZEOF(sTopicRcv));
IF fbMessage.CompareTopic(sTopic:='machine/on') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOnPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='machine/off') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Machine.bOffPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF INT_TO_BOOL(FIND(sTopicRcv,'motion1')) THEN
IF fbMessage.CompareTopic(sTopic:='motion1/position') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Postion := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/velocity') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Velocity := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/acceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Acceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/deceleration') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Deceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF fbMessage.CompareTopic(sTopic:='motion1/execute') THEN
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
Motion.nMotion1Execute := STRING_TO_LREAL(sPayloadRcv);
END_IF
// same for motion2 and motion3
END_IF
END_IF
END_IF
好的,还有很多需要改进的地方。首先让我们创建 SPLIT
函数,将主题转换为数组
FUNCTION SPLIT : ARRAY[0..255] OF STRING(250)
VAR_INPUT
STR: STRING(250);
CHAR: STRING(1);
END_VAR
VAR
iPos: INT;
sTest: STRING(250);
iIndex: INT;
xFinish: BOOL;
END_VAR
sTest := STR;
REPEAT
iPos := FIND(sTest, CHAR);
IF iPos = 0 THEN
SPLIT[iIndex] := sTest;
xFinish := TRUE;
ELSE
SPLIT[iIndex] := LEFT(sTest, iPos - 1);
sTest := RIGHT(sTest, LEN(sTest) - iPos);
END_IF;
iIndex := iIndex + 1;
UNTIL (xFinish = TRUE)
END_REPEAT;
END_FUNCTION
现在如何查找当前主题是否 'motion1' 相关
VAR
arsTopic: ARRAY[0..255] OF STRING(250);
END_VAR
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
fbMessage.GetTopic(pTopic:=ADR(sTopicRcv), nTopicSize := SIZEOF(sTopicRcv));
arsTopic := SPLIT(sTopicRcv, '/');
IF (arsTopic[0] = 'motion1') THEN
// do your staff
END_IF
END_IF
END_IF
但是由于您随后将不同的有效负载加载到不同的变量,因此我会创建一个地图。我不知道你所有的程序,但据我所知,我会从:
TYPE SR_MOTION:
STRUCT
lrPostion: LREAL;
lrVelocity: LREAL;
lrAcceleration: LREAL;
lrDeceleration: LREAL;
lrExecute: LREAL;
END_STRUCT
END_TYPE
SR 表示 Sergey Romanov,您可以使用任何前缀
现在让我们创建您拥有的动作数组。假设您有 3 个。这样我们就可以将运动数分离到单独的变量中。请注意,为了让您的代码顺利运行而不会产生太多垃圾代码,您的主题必须不是 motion1/velocity
,而是 motion/1/velosity
.
VAR
astMotions: ARRAY[1..3] OF SR_MOTION;
arsTopic: ARRAY[0..255] OF STRING(250);
i: INT;
END_VAR
IF fbMessageQueue.nQueuedMessages > 0 THEN
IF fbMessageQueue.Dequeue(fbMessage:=fbMessage) THEN
fbMessage.GetTopic(pTopic:=ADR(sTopicRcv), nTopicSize := SIZEOF(sTopicRcv));
fbMessage.GetPayload(pPayload:=ADR(sPayloadRcv), nPayloadSize:=SIZEOF(sPayloadRcv), bSetNullTermination:=TRUE);
arsTopic := SPLIT(sTopicRcv, '/');
IF arsTopic[0] = 'machine' THEN
IF arsTopic[1] = 'on' THEN
Machine.bOnPB := STRING_TO_BOOL(sPayloadRcv);
ELSIF arsTopic[1] = 'off' THEN
Machine.bOffPB := STRING_TO_BOOL(sPayloadRcv);
END_IF
ELSIF arsTopic[0] = 'motion' THEN
i := STRING_TO_INT(arsTopic[1]); // arsTopic[1] has motion number in `motion/1/velosity`
IF arsTopic[2] = 'position' THEN
astMotions[i].lrPosition := STRING_TO_LREAL(sPayloadRcv);
ELSIF arsTopic[2] = 'velosity' THEN
astMotions[i].lrVelosity := STRING_TO_LREAL(sPayloadRcv);
ELSIF arsTopic[2] = 'acceleration' THEN
astMotions[i].lrAcceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF arsTopic[2] = 'Deceleration' THEN
astMotions[i].lrDeceleration := STRING_TO_LREAL(sPayloadRcv);
ELSIF arsTopic[2] = 'execute' THEN
astMotions[i].lrExecute := STRING_TO_LREAL(sPayloadRcv);
END_IF
END_IF
END_IF
END_IF
这是所有 3 个动作的所有代码。
编辑:添加从主题中提取的数字
如果您不想将主题更改为 motion/1/velosity
,那么您可以使用此函数提取最后一个字符并转换为 int
FUNCTION TOPIC_TO_INT: INT
VAR_INPUT
str: STRING;
END_VAR
VAR
ps: POINTER TO ARRAY[0..200] OF BYTE;
END_VAR
ps := ADR(str);
TOPIC_TO_INT := BYTE_TO_INT(ps^[LEN(str) - 1]) - 48;
END_FUNCTION
然后在代码中而不是 i := STRING_TO_INT(arsTopic[1]);
你可以 i := TOPIC_TO_INT(arsTopic[0])
和代码的其余部分稍微改变。
所以如果你使用 TOPIC_TO_INT(STRING#'message2')
这个函数将 return INT#2