stlehmann / pyads

Python wrapper for TwinCAT ADS
MIT License
251 stars 92 forks source link

Cannot communicate with TwinCAT 3 PLC (CX9020) on Ubuntu 16.04 #42

Closed sebastianbk closed 6 years ago

sebastianbk commented 6 years ago

Hi,

First of all, thank you so much for sharing this library. It's an amazing effort and it has made my life so much easier... at least on Windows! :wink:

I have a Beckhoff CX9020 running with TwinCAT v3.1 that runs a small program, which controls a servomotor. I have made it so that when I set MAIN.bStart to True, my servomotor rotates 360 degrees and then stops. Using pyads on Windows 10 I was able to successfully set my variable using the write_by_name method in Python. I followed your guide and created a route in the TwinCAT Router UI, which then allowed me to communicate with the PLC in Python. This worked like a charm!

However, when trying the same thing in Ubuntu 16.04.3 LTS (with Python 3.5.2), I am having some issues. It seems as if the connection opens and then immediately closes when I try to connect to the PLC. I really don't understand why, as I believe I have correctly followed the steps provided in the guide and in the examples provided in some other related issues. See here:

sebastian@SB-Ubuntu:~$ ipython3
Python 3.5.2 (default, Sep 14 2017, 22:51:06) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import pyads

In [2]: plc = pyads.Connection('5.38.157.217.1.1', 851, '192.168.1.84')

In [3]: plc.open()
2017-10-23T14:30:18+0200 Info: Connected to 192.168.1.84

2017-10-23T14:30:18+0200 Info: connection closed by remote
In [4]: plc.write_by_name('MAIN.bStart', True, pyads.PLCTYPE_BOOL)
---------------------------------------------------------------------------
ADSError                                  Traceback (most recent call last)
<ipython-input-4-783030c2433f> in <module>()
----> 1 plc.write_by_name('MAIN.bStart', True, pyads.PLCTYPE_BOOL)

/usr/local/lib/python3.5/dist-packages/pyads/ads.py in write_by_name(self, data_name, value, plc_datatype)
    531         if linux:
    532             return adsSyncWriteByNameEx(self._port, self._adr, data_name,
--> 533                                         value, plc_datatype)
    534         else:
    535             return adsSyncWriteByName(self._adr, data_name, value,

/usr/local/lib/python3.5/dist-packages/pyads/pyads_ex.py in adsSyncWriteByNameEx(port, address, data_name, value, data_type)
    495     handle = adsSyncReadWriteReqEx2(
    496         port, address, ADSIGRP_SYM_HNDBYNAME, 0x0,
--> 497         PLCTYPE_UDINT, data_name, PLCTYPE_STRING
    498     )
    499 

/usr/local/lib/python3.5/dist-packages/pyads/pyads_ex.py in adsSyncReadWriteReqEx2(port, address, index_group, index_offset, read_data_type, value, write_data_type)
    365 
    366     if err_code:
--> 367         raise ADSError(err_code)
    368 
    369     # If we're reading a value of predetermined size (anything but a string),

ADSError: ADSError: timeout elapsed (1861)

I have also tried running plc.open_port() before attempting to connect to the PLC. In addition, I have also tried creating the Connection object without the target IP parameter. I am getting the same error every time.

The AMS Net ID of my PLC is 5.38.157.217.1.1 and, on Windows, I can connect to it on port 851. By running arp-scan I can see that my PLC has gotten the IP 192.168.1.84 by router's DHCP server.

sebastian@SB-Ubuntu:~$ sudo arp-scan --interface=wlp5s0 --localnet
[sudo] password for sebastian: 
Interface: wlp5s0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.8.1 with 256 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.1.1 88:a6:c6:e2:42:93   (Unknown)
192.168.1.8 58:00:e3:d6:e1:05   (Unknown)
192.168.1.55    9c:eb:e8:43:af:24   BizLink (Kunshan) Co.,Ltd
192.168.1.84    00:01:05:26:9d:d9   Beckhoff Automation GmbH
192.168.1.90    9c:eb:e8:43:af:24   BizLink (Kunshan) Co.,Ltd
192.168.1.99    34:97:f6:d3:8c:30   (Unknown)
192.168.1.78    9c:b6:d0:df:d6:71   (Unknown)

7 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.8.1: 256 hosts scanned in 1.321 seconds (193.79 hosts/sec). 7 responded

The IP of my Ubuntu laptop is 192.168.1.82. Here are some more details about my own network interface:

wlp5s0    Link encap:Ethernet  HWaddr 58:00:e3:4f:4a:e7  
          inet addr:192.168.1.82  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::63a5:9c67:34b4:3da3/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:12856 errors:0 dropped:0 overruns:0 frame:0
          TX packets:5534 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:13604275 (13.6 MB)  TX bytes:808785 (808.7 KB)

According to some other GitHub issues, it should not be necessary to manually create the route before trying to connect to the PLC. I tried doing so anyway but I still get the message that it connects and then immediately disconnects. Anyway, it shouldn't be necessary to create the route, as I already created it from Windows. Or is there something I am not understanding correctly? I have dual-boot running on my laptop so when I am in Ubuntu my laptop has the same IP as when I am in Windows.

I really hope you can help me resolve this issue, as I would love to use pyads on Linux. Please let me know if you need any additional information.

Thank you very much!

sebastianbk commented 6 years ago

Just to make it clear, when trying to manually create the route, I also get a message that says the connection has been opened and then immediately closed.

sebastian@SB-Ubuntu:~$ ipython3
Python 3.5.2 (default, Sep 14 2017, 22:51:06) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import pyads

In [2]: pyads.open_port()
Out[2]: 30000

In [3]: remote_ip = '192.168.1.84'

In [4]: address = pyads.AmsAddr('5.38.157.217.1.1', 851)

In [5]: pyads.add_route(address, remote_ip)
2017-10-23T14:59:31+0200 Info: Connected to 192.168.1.84

2017-10-23T14:59:31+0200 Info: connection closed by remote

When creating the route on Windows, I am being prompted to enter the credentials for the PLC. My username is Administrator and the password is blank. However, on Linux, I am not being prompted to enter the credentials. Could this have something to do with the issue?

sebastianbk commented 6 years ago

Okay, it turns out that the route from the PLC to my laptop was not created with the proper AMS Net ID. In Ubuntu my local AMS Net ID was 192.168.1.82.1.1 while in Windows it was 169.254.1.1.1.1. I changed my Net ID in Windows to be the same as the one in Ubuntu, created a new route with the TwinCAT Router UI in Windows and then rebooted into Ubuntu. Now it works. :blush:

However, this process is a little cumbersome. Is there any way to create a route from the PLC to my laptop directly from Ubuntu? This would really be an awesome feature!

stlehmann commented 6 years ago

@sebastianbk I'm glad it works for you now. Yes, I agree. It is a bit cumbersome to get the routing of the AMS IDs right. Especially as you need to add the routing on both sides (plc and PC). Unfortunately we do not have any influence on how the routing is done.