上位机要想和库卡机器人通讯,首先要给机器人安装“ETHERNETKRL”这个软件,对,是给机器人安装。具体软件的安装以及初步通讯测试就不多做介绍了。
因为本文不是介绍该软件的安装,所以就不多做解释,下面的内容默认已经能用自带的测试软件获取库卡机器人发送过来的数据。在此基础上,我来说一下c#利用tcp/ip是如何跟库卡机器人进行通讯的.
首先当然是TCP/IP的基础部分,服务器和客户端。这里将库卡机器人作为客户端,上位机作为服务器进行通讯。
privatevoidbutton1_Click(object sender, EventArgs e) { OpenTCP(); }///<summary>/// TCP放在后台线程///</summary>privatevoidOpenTCP() {//新建一个委托线程 ThreadStart myThreadDelegate = new ThreadStart(Listen);//实例化新线程 myThread = new Thread(myThreadDelegate); myThread.Start(); }///<summary>/// 创建TCP服务端并监听///</summary>publicvoidListen()//创建tcp服务端 { //设置端口 setPort = 59152;//初始化SOCKET实例 newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//允许SOCKET被绑定在已使用的地址上。 newsock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);//初始化终结点实例 localEP = new IPEndPoint(IPAddress.Parse("172.31.1.250"), setPort);try { _sessionTable = new Hashtable(53);//绑定 newsock.Bind(localEP);//监听 newsock.Listen(10);//开始接受连接,异步。= newsock.BeginAccept(new AsyncCallback(OnConnectRequest), newsock); }catch (Exception ex) { } }///<summary>/// 客户端连接///</summary>///<param name="ar"></param>publicvoidOnConnectRequest(IAsyncResult ar) {//初始化一个SOCKET,用于其它客户端的连接 server1 = (Socket)ar.AsyncState; Client[theIndex] = server1.EndAccept(ar); DateTimeOffset now = DateTimeOffset.Now; Byte[] byteDateLine = new Byte[65534]; remote = Client[theIndex].RemoteEndPoint;//把连接成功的客户端的SOCKET实例放入哈希表 _sessionTable.Add(Client[theIndex].RemoteEndPoint, null);//等待新的客户端连接 theListClient[theIndex, 0] = Client[theIndex].RemoteEndPoint.ToString(); theListClient[theIndex, 1] = "1"; server1.BeginAccept(new AsyncCallback(OnConnectRequest), server1); theIndex++;int myIndex = theIndex - 1;while (true) {try {if (theListClient[myIndex, 1] == "0") return; Thread.Sleep(150);int recv = Client[myIndex].Receive(byteDateLine);string stringdata = Encoding.UTF8.GetString(byteDateLine, 0, recv);string ip = Client[myIndex].RemoteEndPoint.ToString();//接受到客户端消息if (stringdata != "") { MessageBox.Show(stringdata); }//显示客户端发送过来的信息 }catch (Exception ex) {//从列表中移除通讯失败的客户端string ip = Client[myIndex].RemoteEndPoint.ToString(); _sessionTable.Remove(Client[myIndex].RemoteEndPoint);for (int i = 0; i < 256; i++) {if (Client[myIndex].RemoteEndPoint.ToString() == theListClient[i, 0]) theListClient[i, 1] = "0"; }break; } } }
通过按钮事件,创建后台线程用于TCP服务端,创建服务端并开启监听后,就可以等待机器人客户端发来的消息了。
库卡机器人TCP通讯存在三种数据发送格式:固定长度字节,任意长度字节,和xml格式。个人感觉xml格式比较好用,这里介绍xml的通讯。
xml的通讯,其实可以分解为几个步骤:
机器人发送到上位机:机器人程序将变量或者数值写入xml的元素中→机器人将xml发送通过服务端发送到上位机的服务端→服务端接受到数据,按照xml的格式解析其中元素
RET=EKI_Init("XmlCallBack")//初始化xml文件RET=EKI_Open("XmlCallBack")//打开(相当于客户端请求连接)//将变量或值写入到xml文件的元素中;FOLD Write data to connection ; Write frame to <LastPos X="" Y="" Z="" A="" B="" C="" /> RET=EKI_SetFrame("XmlCallBack","Robot/Data/LastPos", TOOL_DATA[1]) ; Write real to <ActPos X="" /> RET=EKI_SetReal("XmlCallBack","Robot/Data/ActPos/@X", 1000.12) ; Write int to <Status></Status> RET=EKI_SetInt("XmlCallBack","Robot/Status", 12345678) ; Write string to <Mode></Mode> RET=EKI_SetString("XmlCallBack","Robot/Mode","ConnectSensor") ; Write bool to <LightOn></LightOn> RET=EKI_SetBool("XmlCallBack","Robot/RobotLamp/GrenLamp/LightOn",true);ENDFOLD (Write data to connection)//发送xml到服务端RET = EKI_Send("XmlCallBack","Robot")
上位机服务端获取到的数据是:
<Robot><Data><LastPos X="483.980011" Y="7.210000" Z="239.869995" A="0.000000" B="0.000000" C="0.000000"></LastPos><ActPos X="1000.119995"></ActPos></Data><Status>12345678</Status><Mode>ConnectSensor</Mode><RobotLamp><GrenLamp><LightOn>1</LightOn></GrenLamp></RobotLamp></Robot>
<Robot><Data><LastPosX="483.980011"Y="7.210000"Z="239.869995"A="0.000000"B="0.000000"C="0.000000"></LastPos><ActPosX="1000.119995"></ActPos></Data><Status>12345678</Status><Mode>ConnectSensor</Mode><RobotLamp><GrenLamp><LightOn>1</LightOn></GrenLamp></RobotLamp></Robot>
然后对数据进行逐个元素的解析就可以了。要增加变量,只要对应在mxl文件,机器人程序和上位机解析过程中添加就可以了。
上位机发送到机器人:上位机将变量写成xml格式,利用客户端发送到机器人中的xml文件→机器人读取xml文件中的元素值到程序中的变量
写成xml格式:
sendstr = sendstr + "<Sensor><Status><IsActive>FALSE</IsActive></Status></Sensor>";
sendstr = sendstr + "<Sensor><Read><xyzabc X='10.0' Y='20.0' Z='30.0' A='40.0' B='50.0' C='60.0'></xyzabc></Read</Sensor>";
sendstr = sendstr + "<Sensor><Status><IsActive>FALSE</IsActive></Status></Sensor>";sendstr = sendstr + "<Sensor><Read><xyzabc X='10.0' Y='20.0' Z='30.0' A='40.0' B='50.0' C='60.0'></xyzabc></Read</Sensor>";
然后是tcp发送
///<summary>/// 将字符串发送给机器人///</summary>///<param name="str"></param>privatevoidsendToRobot(string str) {string sendstr; str = str.Replace(" ", "");string[] fields = str.Split(',');string header = "<Sensor>", tail = "</Sensor>";//变量xml文件中的父元素 sendstr = header;//设置xml文件中变量的值,格式:<变量名>变量值</变量名>foreach (string item in fields) {string[] arr = item.Split('='); sendstr += "<" + arr[0] + ">" + arr[1] + "</" + arr[0] + ">"; } sendstr += tail;//这些变量的某些中间父元素与前面的不同,所以另外写 sendstr = sendstr + "<Sensor><Status><IsActive>FALSE</IsActive></Status></Sensor>"; sendstr = sendstr + "<Sensor><Read><xyzabc X='10.0' Y='20.0' Z='30.0' A='40.0' B='50.0' C='60.0'></xyzabc></Read></Sensor>";string strDataLine = sendstr;try { Byte[] sendData = Encoding.UTF8.GetBytes(strDataLine);foreach (DictionaryEntry de in _sessionTable) { EndPoint temp = (EndPoint)de.Key; {for (int i = 0; i < theIndex; i++) {if (theListClient[i, 1] == "1") {if (temp.ToString() == theListClient[i, 0]) {try { Client.SendTo(sendData, temp); }catch (Exception ex) { } } } } } } }catch { } }
等发送完成之后,机器人再读取
机器人从xml元素中读取值或者属性并赋予创建的变量
RET=EKI_GetString("XmlCallBack","Sensor/Message",valueChar[])
RET=EKI_GetInt("XmlCallBack","Sensor/Nmb",valueInt)
RET=EKI_GetBool("XmlCallBack","Sensor/Status/IsActive" ,valueBOOL)
RET=EKI_GetFrame("XmlCallBack","Sensor/Read/xyzabc",valueFrame)
RET=EKI_GetString("XmlCallBack","Sensor/Message",valueChar[]) RET=EKI_GetInt("XmlCallBack","Sensor/Nmb",valueInt) RET=EKI_GetBool("XmlCallBack","Sensor/Status/IsActive" ,valueBOOL) RET=EKI_GetFrame("XmlCallBack","Sensor/Read/xyzabc",valueFrame)
然后就可以在机器人程序中使用,或者通过查看变量值检测是否正确。
|