Multiple reproducible errors with a Brecknell Scale - python

I'm working on getting a weight from a usb scale using python and PyUSB. Here's my code
import sys
import usb.core
import usb.util
from reports import \
ReportFactory, STATUSES, ZERO_WEIGHT, STABLE_WEIGHT, DATA_REPORT
device = usb.core.find(idVendor=0x67b, idProduct=0x2303)
if device is None:
raise ValueError('Device Not Found')
if device.is_kernel_driver_active(0) is True:
device.detach_kernel_driver(0)
usb.util.claim_interface(device, 0)
device.set_configuration()
collected = 0
attempts = 50
while collected < attempts:
ret = device.read(0x2,0x0040)
sret=''.join([chr(x) for x in ret])
print "Return Raw: ",ret
print "Return : ", sret
print ReportFactory.build(ret)
# release the device
usb.util.release_interface(device, 0)
device.attach_kernel_driver(0)
The first time I run this program I get Resource busy error
The second run I get Operation timed out on the 5th dump.
Subsequent runs after that result in immediate timeouts.
There are several things going on here
Why do I get a resource busy error on first run? I would think the kernel_driver if statement I have should take care of it.
Why do I get data that looks nothing like what a USB scale should produce?
Why the timeout after 4 dumps of data? Everytime!
The device information is thus
Any help would be much appreciated!

Ok, anyone that is struggling to get anything from the GP100 Brecknell scale using PyUSB, switch to PySerial. Since this is one of the cheapest USB scales on the market, I'm guessing this information will help many.
I emailed the manufacturer for documentation and they've sent me some valuable serial protocol information.
If you set the protocol of the scale to 7010 you can use python code that looks like this
import time
import serial
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=2400,
bytesize=8,
parity='N',
stopbits=2
)
while 1:
x = ser.read(100)
print(x)
This will stream 8 bytes of data.
The first byte is status information that can be interpreted thusly
Bits 2-4
Bits 5-8
Bytes 2 & 3 can be safely ignored.
Bytes 4-8 have the weight information, represented by characters 0-9 (e.g. 00023 = 2.3 lbs). This scale is only accurate +- 0.6 lbs and does not work in ounces, perhaps other models using the same serial controller utilize the oz capabilities. The PG100 does not.

Related

Mimic Chint DDSU666 Meter with python

i am looking for some help.
i already figured out how to read the Chint DDSU666 energy meter, these meters are used with modbus RTU to communicate with solar battery inverters. so i would like to mimic this type of meter to adjust charging and discharging power.
my code to read this type of meter is:
import minimalmodbus
import struct
# The minimalmodbus library uses RTU mode for Modbus communication.
# You will need to set up the serial port and baud rate to match your energy meter's settings.
instrument1 = minimalmodbus.Instrument('com4',1)
instrument1.serial.baudrate = 9600
instrument1.close_port_after_each_call = True
# Set the slave address of your energy meter
instrument1.address = 0x01
while True:
try:
##Chint Meter DDSU666
spanning = instrument1.read_float(0x2000, 3, 2)
freq = instrument1.read_float(0x200e, 3, 2)
stroom = instrument1.read_float(0x2002, 3, 2)
vermogen = instrument1.read_float(0x2004, 3, 2)
baurdrate = instrument1.read_register(0x000c, 0)
print(spanning)
print(freq)
print(stroom)
print(vermogen)
print(baurdrate)
except:
print('communication lost')
now i want to write the registers above by my own data.
so i need to setup an modbus RTU slave/server where the inverter can read its data.
i started with pymodbus3.1 but was not able to get anywhere..
now i am trying with modbus_tk library to setup a server.
underneath my code.
import minimalmodbus
import struct
import pymodbus
import asyncio
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
import serial
import time
modbusserver = modbus_rtu.RtuServer(serial.Serial('com4'),baudrate = 9600, bytesize=8,parity = 'N', stopbits=1, xonxoff=0)
print('start')
modbusserver.start()
slave1 = modbusserver.add_slave(1)
slave1.add_block('spanning',cst.HOLDING_REGISTERS,0x2000,250)
slave1.add_block('freq',cst.HOLDING_REGISTERS,0x200e,50)
slave1.add_block('vermogen',cst.HOLDING_REGISTERS,0x2002,3000)
could someone guide me what i need to use or what is the best option to be able to mimic this energymeter?
Thank you in advance.
tried above code to mimic the meter but not working.
Your code has two small problems.
First: you are not giving add_block the right values. According to this those are: name, type, starting address and number of registers so you should be doing something like:
slave1.add_block('spanning',cst.HOLDING_REGISTERS,0x2000,2)
slave1.add_block('freq',cst.HOLDING_REGISTERS,0x200e,2)
slave1.add_block('vermogen',cst.HOLDING_REGISTERS,0x2002,2)
And now that you have defined your blocks you can fill them with data. But be aware that to do that you need to use raw registers. You can't just send a float because the block is expecting raw registers as a list.
To circumvent that problem, the easiest thing to do is, instead of reading floats like so:
spanning = instrument1.read_float(0x2000, 3, 2)
Just read raw registers:
spanning = instrument1.read_registers(0x2000, 3, 2) #better read raw regs
freq = instrument1.read_registers(0x200e, 3, 2)
...
That should result in a list of two registers, so then you can directly do:
slave1.set_values("spanning", 0, spanning) #note that the first time we use quotes
#but not on the second. The fist is the
#name of the block and the second the
#list of values for the regs
...
Now you are ready to start your server with:
modbusserver.start() #start your server AFTER adding blocks and setting values
Finally, it might be a good idea to add a provision to manually stop your server; otherwise, you might end up killing the task resulting in havoc. You can have a look at this answer for inspiration.
Good luck! and veel plezier.

Serial stops reading after about 6 hours

When reading the serial port in python, all works fine until after hours where receiving data stops. This happens both on a laptop running Linux and on a Raspberry PI 2. Sending data still works at that point.
The source is still sending data (now and again). Restarting the python script helps.
The source sends small packages (4 - 12 bytes) and interval times may vary from minutes to over 12 hours.
My code, just only the receiving part, extracted from a bigger part, looks like this:
#!/usr/bin/python3
import tkinter
import os
import serial
class Transceiver():
def __init__(self, main):
self.port = serial.Serial(
port = "/dev/ttyUSB0",
baudrate = 38400,
bytesize = serial.EIGHTBITS,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
timeout = 0
)
self.ReceivedData = bytearray()
self.Time = 0
def Receiver(self):
while (self.port.in_waiting > 0):
# Receiving data
self.Time = 0 # Reset time elapsed to 0
self.ReceivedData += self.port.read(1) # Add data to bytearray
if (self.Time == 20): # Some time elapsed, packet considered complete
print(''.join('{:02x} '.format(x) for x in self.ReceivedData))
self.port.reset_input_buffer()
self.ReceivedData = bytearray()
if (self.Time < 2000): # Just avoid running to 0 again
self.Time += 1 # Increment time elapsed
root.after(5, self.Receiver)
root = tkinter.Tk()
transceiver = Transceiver(root)
transceiver.Receiver()
root.mainloop()
It is just this receiving part that stops working after hours, I am trying to find the root cause.
So the above script is just an extract from a bigger script.
It controls the lights in the house. I want to run it on a raspberry PI, instead of a PC. The R'PI has a little 7" touch screen.
The bigger scripts has some decoding of the received data and updates a very simple GUI, just a bunch of small rectangles with some short name as text in it, indicating which lamps are on and off, and they act as buttons too, to toggle the lamps on and off. All works well, apart from the receiving part, though, in the end it may be possible that some other part disturbs the receiving part.
I have just started running just the above extraction of the script, to see if it keeps working without the GUI updates. I suspect the function Receiver fails to be restarted after some time. I need to have the above script running for a day to see of it keeps receiving though. I will update with the findings.
Update: The above script keeps working. The above is the extraction of a bigger program where only this part stops working after some hours. Receiving stops, but transmitting keeps working, hence I did not include that part.
By now I found the problem. In the receiver function, a decode function is called where above is the print line. Without calling the decode function, there is no problem. The decode function has some conditions, depending on the packet length and some values. Code for one of these conditions contained an error. I always started to run the script again in early evening, and then about 6 hours later a timer (at a fixed time late in the evening) would send the offending packet (a different format) that then caused the problem. The packet was not at fault, but my decoding of that packet.
Strange is that the script kept working, only the reception part stopped. I thought it stopped silently, but I printed quite a lot in this stage, hence I didn't see the error message telling me the problem of the use of an uninitialised variable. It's not in the above code. Hope the above code is useful for other people.

Python hangs when using serial.write() on my Raspberry 2

I use pySerial for communication between RaspberryPi 2 and Arduino but after my first 100 write-calls it starts to become very slowly when writing.
My Code looks like this:
import serial
ser = serial.Serial("/dev/ttyACM0", 2000000, write_timeout=0)
while True:
byteData = getData()
sentBytes = ser.write(byteData)
if sentBytes == 4:
print("All Data was sent successfully!")
Everything is fine for the first second but then it hangs and I only send like 4 bytes each second. I also saw this post here but on my Raspbian machine a /dev/serial0 or /dev/ttyS0 doesn't exist. How I get this rushing like in the first second permanently?
You are using a very high baud rate, a buffer may be running full and cause the hick up after a short while.
Try a very conservative baud rate of 9600 and see if you have the same issue.
Also make sure your getData() actually always returns 4 bytes, otherwise your print statement might not get evaluated in every loop.

Detecting fast-flowing data with serial port

300 items flow from a production band at a minute. Using an optical micrometer, with pyserial and qthread, I am trying to 200 receives per second. But I can not get it right as I expected. There is not a problem when I keep it fixed, but I can not get the correct result when the object is moving. I need to detect width of the item flowing fast with the serial port. How would you recommend a method for this?
Question:. When I decrease the timeout, it occasionally breaks in the data stream.
Try the following, decrease down to 9600:.
Open port at “38400,8,E,1”, non blocking HW handshaking:
>>> ser = serial.Serial('COM3', 38400, timeout=0,
... parity=serial.PARITY_EVEN, rtscts=1)
>>> s = ser.read(100) # read up to one hundred bytes
... # or as much is in the buffer

Performance at serial read python

I am reading string from serial in a loop and realize that the processor is at 100% (RaspberryPI) while waiting for the next serial.read().
I found recommendation to add a few sleeps here and there, but doing this might cause missing serial data. In theorie I am getting a string from serial every 5 seconds, but could be a bit more or less and not in my control.
Is there a way to solve this in python better and with less processor use?
#!/usr/bin/env python
import serial
ser = serial.Serial("/dev/ttyUSB0", 57600, timeout=0)
def sr():
while True:
for line in ser.read():
try:
response = ser.readlines(None)
response = str(response)
print response
except:
print datetime.datetime.now(), " No data from serial connection."
if __name__ == '__main__':
sr
ser.close()
from what i remember (been a while since i used pyserial) i am sure that serial uses buffers, so as long as your message doesn't fill the buffer you shouldn't lose any data.
assuming i'm looking at the docs for the right module the following page:
[Pyserial docs][1]http://pyserial.sourceforge.net/pyserial_api.html
make mention about buffers both on the input and output.
so you should have no problems with putting sleeps into your program as the buffers will collect the data until you read it. (assuming your messages are not big enough to cause an overflow)
James

Categories

Resources