2

I have this digital dial indicator : Helios-Preisser Digimet 1722-502". It comes with a capacity to output its reading over a USB serial cable. The USB cable is a special 4 pin connector on the end that plugs into the calipers and a normal USB on the other end.

Although the device comes with special software, I am trying to write a basic python library to communicate with it. Below is the snippet of the manuel which explains the data communication protocol

I am using the python Serial library and have managed to get some communication going with it. Here's what I have so far

import serial
ser = serial.Serial(port ='/dev/tty.usbserial-MA4LOCLF', baudrate=4800,parity=serial.PARITY_EVEN,  bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_TWO, dsrdtr=True, xonxoff=True)
# press the small red button on the cable. This generates a data entry
In [77]: ser.inWaiting()
Out[77]: 8
In [78]: ser.read(8)
Out[78]: '+000.00\r'

So this works great when using the mode the data is being requested by the pressing of the small red button on the cable plugged into the dial indicator

However, there is another mode where one can request a data entry. This is the mode described in the manual as "data transmission by request of peripheral" where one has to pulse the DataRequest pin low for T1 (100ms<T1<1000ms). I have tried mostly randomly all possible combinations I could think to get this data request working but to no avail. All attempts at using the write function from the serial library have not worked

In [79]: ser.write('0\r')
Out[79]: 2

In [80]: ser.inWaiting()
Out[80]: 0

I am a bit out of ideas. I know this mode works because when you download (in Windows only) the software which comes with the device, you have the ability to send that request. SO there must be a way of emulating this request with the python serial library but I'm stuck and I'm not even sure how to proceed. Any help would be appreciated. Thanks

Denis Barkats
  • 41
  • 1
  • 4

2 Answers2

0

pyserial supports (or it should, but at the end of the day that would depend on the driver and not on pyserial itself) a function to change the state of the port's control lines.

You need to do something like this:

ser.setDTR(False)
time.sleep(0.5)
ser.setDTR(True)

If you read from the port right after you should get the value you are looking for.

To get the timing more or less right you should run your code as a script instead of line by line.

Marcos G.
  • 3,371
  • 2
  • 8
  • 16
  • Hi Marcos G, so you are saying that if I run those lines above, I should see on the USB pin that carries the DTR line (not sure which one it is, but there are only a Transmit, Receive, +Vdd, -Vdd), the voltage should go from +Vdd to -Vdd back to +Vdd. I guess I'll try that and probe the USB output lines with a voltmeter to see if that does what I want. And I'll then try it on the dial indicator and see if that works. – Denis Barkats Mar 17 '21 at 20:37
  • Yes, that's right. You should see the DTR line changing. It actually looks like your port does not have a receive line, but only TX, DTR and RTS. – Marcos G. Mar 18 '21 at 05:10
  • I forgot to mention that you need to check carefully what driver you are using on Linux. It might very well be that the `set.DTR()` function works well on Windows but not on Linux. One thing you can do is try with Python on Windows. – Marcos G. Mar 18 '21 at 07:54
  • Hi Marcos, thanks for alt the tips. I am actually testing these functionalities on my mac osx laptop. I'll test all of this on Monday and provide feedback here. – Denis Barkats Mar 19 '21 at 07:43
  • Ah, I was wondering about the port name, now I see where it is coming from. Anyway, you need to find out what serial chip you are dealing with and where is the Mac driver coming from. It might be that pyserial's control functions work only under Windows. Did you install the driver for the Mac yourself? or maybe it was already in the system? – Marcos G. Mar 19 '21 at 09:44
  • Unfortunately, the small command snippet you suggested above did not work ( on my mac). **However**, setting dtr to false, then back to true as you suggested did change something on the device, because after doing so, it stops producing a reading when pressing on the red button. So something happens. To get it to work via the push button, I have to close it, and re-initialize the device. – Denis Barkats Mar 22 '21 at 09:12
  • Have you run these lines together with the part you read data on a script? You need to get the timing right so you cannot run them one by one from the command line manually – Marcos G. Mar 22 '21 at 11:33
  • Marcos, I have indeed send those lines together as a single script. – Denis Barkats Mar 22 '21 at 15:18
0

Ok, well after much "messing around", I was able to debug this problem and find the solution but it was certainly not a linear process. I should point out that I was placed on the right path thanks to the suggestions by Marcos G. who pointed out that you can indeed control the dtr lines directly with pyserial.

Here's the answer. After some more searching the web, I found this link which provided a suggestion for how to troubleshoot your serial connection on a mac. This Coolterm software was immensely helpful.

I downloaded it and it allows you to monitor the state of the various RTS and DTS (and other) lines while you are communicating in a real time with you device. Super useful!

This showed me that:

  • When "sending" a reading from the device by pressing the red button, the DTR line was True and the RTS line was irrelevant. This is indeed what is shown in the documentation.
  • In order to "request" a reading from the device the DTR line needed to be False and the RTS line needed to be pulsed from False to True back to False with the precise timing. This worked and indeed produced a reading waiting on the USB line.

Here's the code below

import time
import serial

ser = serial.Serial(port ='/dev/tty.usbserial-MA4LOCLF', baudrate=4800,parity=serial.PARITY_EVEN,  bytesize=serial.SEVENBITS,stopbits=serial.STOPBITS_TWO, dsrdtr=True)

ser.dtr=False
ser.rts=False
# request one reading every second
while(1):
    ser.rts=True
    time.sleep(0.1)
    ser.rts=False
    time.sleep(0.1)
    print ser.read(ser.inWaiting())
    time.sleep(1)
Denis Barkats
  • 41
  • 1
  • 4
  • I don't think you understand how SO works. I can see how my answer did not solve your problem right away but writing your own answer based on what I had suggested and not even giving it any credit is not the way to go around here. I'm glad you managed to make it work but don't expect any more help from me. – Marcos G. Mar 22 '21 at 11:48
  • Hi Marcos, I did not mean to discredit the help you provided. Please tell me how to give it proper credit and I will. I agree that I may not understand how SO works and amy happy to correct my error. – Denis Barkats Mar 22 '21 at 15:20
  • sorry I did not mean to be harsh or anything. In my humble opinion, you should have as a minimum mentioned that you got the idea from somebody else's answer or comment. If my answer was what prompted you to find the right way to solve your problem then (again in my opinion) you should have marked it as the solution. Then nothing would prevent you from elaborating with your own answer. See for instance [this Q&A](https://stackoverflow.com/questions/56922031/modbus-error-invalid-message-incomplete-message-received-expected-at-least-2/56923891#56923891). – Marcos G. Mar 22 '21 at 17:58