Hello folks again,
after setting and getting to know EKI a little bit, i'm having some follow up questions and problems.
Problem description:
The code found below, should start an EKI server, which listens on port 54601.
After successfull connection the server should execute PTP motions with an advance run of 5 as the data packets come in (as soon as possible).
The tests with this code were executed while beeing in T1 mode.
What works:
Connecting to the server from a PC application. Also sending data packets to the robot and receiving its status with a frequency of 50 hz.
What doesnt work:
The robot does receive and also execute its joint space trajectory, and i can see the the EKI buffer variable filling up, but with a severe delay.
The PC program evaluates the UDP messages with the same frequency as it is sending new packets to the robot. Since the robots message contains the current EKI buffer lenght, im cheking for overflow. The problem is, this variable updates only after several seconds. This results in over 100 packets beeing sent to the robot, before getting an update.
Even if i ignore the problem above. The execution of PTP motions and the frequency of in which i can see the buffer beeing emptied is closer to 2-5hz. Therefore the behavior is as follows, assuming a trajectory of >100 data points.
1. PC Program streams >100 joint space poses to the robot and waits for their execution, since only after 2 to 3 seconds the EKI buffer variable is beeing set and the program can stop streaming.
2. PC waits until the EKI buffer has less than 5 elements.
3. In this time the robot does "something", while i can see on the PC program that the buffer is beeing emptied slowly.
4. After a while the robot moves a part of the streamed trajectory.
5. The cycle repeats.
I've checked the timer and i would assume it is working correctly since im getting data to the PC, although i dont know how to measure the frequency of timers.
I've also checked the "package monitor", which doesnt indicate any problems: the execution time of EKI is substantially less than 1ms.
So the question is: What's happening here? And to some lesser degree, why is EKI behaving as slow as it does?
Below is the full code, comments removed not to exceed the character limit.
&ACCESS RVO
def kuka_eki_hw_interface()
; Declarations
DECL E6AXIS joint_pos_tgt
DECL INT elements_read
; INI
BAS(#initmov, 0) ; Basic initializasion of axes
; Utilized system resources:
; Flags:
; $FLAG[1]: Indicates active client connection
; $TIMER_flag[1]: Used to trigger periodic send of robot state
; Interrupts:
; 15: Calls EKI_hw_iface_reset() on falling edge of $FLAG[1]
; 16: Calls EKI_hw_iface_send() on rising edge of $TIMER_flag[6]
eki_hw_iface_init()
; BCO (Block COincidence) run to current position
; (requied for below loop continue before first incoming command)
joint_pos_tgt = $AXIS_ACT
PTP joint_pos_tgt
; Loop forever
$ADVANCE = 5
loop
elements_read = EKI_hw_iface_get(joint_pos_tgt) ; Get new command from buffer if present
PTP joint_pos_tgt C_PTP ; PTP to most recent commanded position
endloop
; Note: EKI channels delete on reset or deselect of this program
; See <ENVIRONMENT>Program</ENVIRONMENT> EKI config element
end
def eki_hw_iface_init()
DECL EKI_status EKI_ret
; Setup interrupts
; Interrupt 15 - Connection cleanup on client disconnect
global interrupt decl 15 when $FLAG[1]==false do eki_hw_iface_reset()
interrupt on 15
; Interrupt 16 - Timer interrupt for periodic state transmission
global interrupt decl 16 when $TIMER_FLAG[6]==true do eki_hw_iface_send()
interrupt on 16
wait sec 0.012 ; Wait for next interpolation cycle
$TIMER[6] = -200 ; Time in [ms] before first interrupt call
$TIMER_STOP[6] = false ; Start timer 1
; Create and open EKI interface
EKI_ret = EKI_Init("EkiHwInterface")
EKI_ret = EKI_Open("EkiHwInterface")
end
def eki_hw_iface_send()
DECL EKI_STATUS eki_ret
if $FLAG[1] then ; If connection alive
; Load state values into xml structure
; position
eki_ret = EKI_SetReal("EkiHwInterface", "RobotState/Pos/@A1", $AXIS_ACT_MEAS.A1)
eki_ret = EKI_SetReal("EkiHwInterface", "RobotState/Pos/@A2", $AXIS_ACT_MEAS.A2)
eki_ret = EKI_SetReal("EkiHwInterface", "RobotState/Pos/@A3", $AXIS_ACT_MEAS.A3)
eki_ret = EKI_SetReal("EkiHwInterface", "RobotState/Pos/@A4", $AXIS_ACT_MEAS.A4)
eki_ret = EKI_SetReal("EkiHwInterface", "RobotState/Pos/@A5", $AXIS_ACT_MEAS.A5)
eki_ret = EKI_SetReal("EkiHwInterface", "RobotState/Pos/@A6", $AXIS_ACT_MEAS.A6)
eki_ret = EKI_SetReal("EkiHwInterface", "RobotState/Pos/@E1", $AXIS_ACT_MEAS.E1)
; interface state
eki_ret = EKI_checkbuffer("EkiHwInterface", "RobotCommand/Pos/@A1")
eki_ret = EKI_SetInt("EkiHwInterface", "RobotState/RobotCommand/@Size", eki_ret.buff)
; Send xml structure
if $FLAG[1] then ; Make sure connection hasn't died while updating xml structure
eki_ret = EKI_Send("EkiHwInterface", "RobotState")
endif
endif
; Set timer for next interrupt [ms]
$TIMER[6] = -10 ; ~10 ms for above send + 10 ms interrupt timer -> ~50 Hz state transmission
end
deffct int eki_hw_iface_available()
DECL EKI_STATUS eki_ret
if not $FLAG[1] then
return 0
endif
eki_ret = EKI_CheckBuffer("EkiHwInterface", "RobotCommand/Pos/@A1")
return eki_ret.buff
endfct
; EKI_hw_iface_get
; Tries to read most recent elemnt from buffer. q left unchanged if empty.
; Returns number of elements read.
deffct int eki_hw_iface_get(joint_pos_cmd :out)
DECL EKI_STATUS eki_ret
DECL E6AXIS joint_pos_cmd
if not $FLAG[1] then
return 0
endif
eki_ret = EKI_CheckBuffer("EkiHwInterface", "RobotCommand/Pos/@A1")
if eki_ret.buff <= 0 then
return 0
endif
eki_ret = EKI_GetReal("EkiHwInterface", "RobotCommand/Pos/@A1", joint_pos_cmd.a1)
eki_ret = EKI_GetReal("EkiHwInterface", "RobotCommand/Pos/@A2", joint_pos_cmd.a2)
eki_ret = EKI_GetReal("EkiHwInterface", "RobotCommand/Pos/@A3", joint_pos_cmd.a3)
eki_ret = EKI_GetReal("EkiHwInterface", "RobotCommand/Pos/@A4", joint_pos_cmd.a4)
eki_ret = EKI_GetReal("EkiHwInterface", "RobotCommand/Pos/@A5", joint_pos_cmd.a5)
eki_ret = EKI_GetReal("EkiHwInterface", "RobotCommand/Pos/@A6", joint_pos_cmd.a6)
eki_ret = EKI_GetReal("EkiHwInterface", "RobotCommand/Pos/@E1", joint_pos_cmd.e1)
return 1
endfct
def EKI_hw_iface_reset()
DECL EKI_STATUS eki_ret
eki_ret = EKI_Clear("EkiHwInterface")
eki_ret = EKI_Init("EkiHwInterface")
eki_ret = EKI_Open("EkiHwInterface")
end
Display More
<ETHERNETKRL>
<CONFIGURATION>
<EXTERNAL>
<TYPE>Client</TYPE> <!-- Users connect as clients -->
</EXTERNAL>
<INTERNAL>
<ENVIRONMENT>Program</ENVIRONMENT> <!-- Server run via robot interpreter -->
<BUFFERING Limit="512" /> <!-- Allow buffering of up to 512 messages (system max) -->
<ALIVE Set_Flag="1" /> <!-- Use $flag[1] to indicate alive/good connection status -->
<IP>10.100.10.17</IP> <!-- IP address for EKI interface on robot controller (KRC) -->
<PORT>54601</PORT> <!-- Port of EKI interface on robot controller (in [54600, 54615]) -->
<PROTOCOL>UDP</PROTOCOL> <!-- Use UDP protocol -->
</INTERNAL>
</CONFIGURATION>
<!-- Configured XML structure for data reception (external client to robot)
<RobotCommand>
<Pos A1="..." A2="..." A3="..." A4="..." A5="..." A6="..." E1="...">
</Pos>
</RobotCommand>
-->
<RECEIVE>
<XML>
<!-- Joint position command -->
<ELEMENT Tag="RobotCommand/Pos/@A1" Type="REAL" />
<ELEMENT Tag="RobotCommand/Pos/@A2" Type="REAL" />
<ELEMENT Tag="RobotCommand/Pos/@A3" Type="REAL" />
<ELEMENT Tag="RobotCommand/Pos/@A4" Type="REAL" />
<ELEMENT Tag="RobotCommand/Pos/@A5" Type="REAL" />
<ELEMENT Tag="RobotCommand/Pos/@A6" Type="REAL" />
<ELEMENT Tag="RobotCommand/Pos/@E1" Type="REAL" />
</XML>
</RECEIVE>
<!-- Configured XML structure for data transmission (robot to external client)
<RobotState>
<Pos A1="..." A2="..." A3="..." A4="..." A5="..." A6="..." E1="...">
</Pos>
<Vel A1="..." A2="..." A3="..." A4="..." A5="..." A6="..." E1="...">
</Vel>
<Eff A1="..." A2="..." A3="..." A4="..." A5="..." A6="..." E1="...">
</Eff>
</RobotState>
-->
<SEND>
<XML>
<!-- Joint state positions -->
<ELEMENT Tag="RobotState/Pos/@A1"/>
<ELEMENT Tag="RobotState/Pos/@A2"/>
<ELEMENT Tag="RobotState/Pos/@A3"/>
<ELEMENT Tag="RobotState/Pos/@A4"/>
<ELEMENT Tag="RobotState/Pos/@A5"/>
<ELEMENT Tag="RobotState/Pos/@A6"/>
<ELEMENT Tag="RobotState/Pos/@E1"/>
<!-- Interface state -->
<ELEMENT Tag="RobotState/RobotCommand/@Size"/> <!-- Number of elements currently in command buffer -->
</XML>
</SEND>
</ETHERNETKRL>
Display More