I'm trying to use pyserial for reading out some bluetooth sensor data via rfcomm0.
Setting up the connection using the linux rfcomm command and its rfcomm.conf is working fine. But after a reading attempt using pyserial the device is freezing after a few seconds (until that poing delivering correct data!) and only useable after a complete device reset. Using direct connection with a FTDI level shifter my code is working fine without problems.
rfcomm.conf:
rfcomm0 {
Automatically bind the device at startup
bind no;
device 98:D3:31:70:23:90;
channel 1;
comment "Example Bluetooth device";
}
Command being used for setting up the connection
# rfcomm -i hci0 connect 0
Connected /dev/rfcomm0 to 98:D3:31:70:23:90 on channel 1
Relevant python code snippet (looped heavily with magic algorithms read(1)-ing bytes):
ser = serial.Serial('/dev/rfcomm0')
start_frame = ser.read(1)
(...)
Python trace when when deadlocking:
serialposix.py(443): if not self._isOpen: raise portNotOpenError
serialposix.py(444): read = bytearray()
serialposix.py(445): while len(read) < size:
serialposix.py(446): ready,_,_ = select.select([self.fd],[],[], self._timeout)
Seems as the linux host bluetooth device is stopped delivering data. When I'm attaching a FTDI directly to the bluetooth sensor it' still sending data.
Why is it doing this?! Do I need to flush some magic bluetooth buffers? I even tried two different bluetooth adapters.
On SF i found this article:
https://askubuntu.com/questions/114171/why-is-dev-rfcomm0-giving-pyserial-problems
But using BluetoothSocket and replacing read(1) with recv(1) only 50% of the received data is correct, rest containing garbage (upper solutions gives me 100% data but dying after ~5 seconds).
Any suggestions?
Thank you for helping!
Okay, nailed that beast down:
The whole thing dies when the rfcomm0 buffer on the host side is empty.
read(1)-ing from empty rfcomm0 buffer = deadlock without comeback
Solution:
Fine: Looking if there's some data in the buffer- when yes, read it
Ugly: Use some time.delay() and hope for god that there's some data
Related
I am currently trying to implement simple communication between an I/O module as a CanOpen slave and my computer(Python script). The I/O module is connected to my computer with a PEAK USB-CAN adapter.
My goal would be to read or write the inputs/outputs. Is this even possible with the hardware, since I don't have a real "master" from that point of view?
Unfortunately I don't know what else I have to do to be able to communicate correctly with my I/O module.
import canopen
import time
network = canopen.Network()
network.connect(bustype='pcan', channel='PCAN_USBBUS1', bitrate=500000)
#add node and DCF File
IO_module = network.add_node(1, 'path to my DIO.DCF')
network.add_node(IO_module)
IO_module.nmt.state = 'RESET COMMUNICATION' # 000h 82 01
print(IO_module.nmt.state)
time.sleep(5)
IO_module.nmt.state = 'OPERATIONAL'
print(IO_module.nmt.state)
for node_id in network:
print(network[node_id])
IO_module.load_configuration()
i see some kind of communication in my console with timeout errors
INITIALISING
OPERATIONAL
<canopen.node.remote.RemoteNode object at 0x000002A023493A30>
Transfer aborted by client with code 0x05040000
No SDO response received
Transfer aborted by client with code 0x05040000
No SDO response received
Any advices ?
I can't get any further with the documentation alone
https://canopen.readthedocs.io/en/latest/
thank you
The good news is, you probably have all the required hardware. You are doing the "master" part from Python, that's fine. (The CAN bus isn't really master/slave, just broadcast. CANopen can be master/slave sometimes, but it's still all broadcast messages among equals on the same bus.)
You haven't provided information about your device, but I would start checking at a lower level.
Do you even have the CAN-Bus wired up correctly, and if so, what did you do to verify it? (Most common mistake: CAN-Bus not terminated with two 120ohm resistors. Though you usually can get away with just one instead of two.) And have you verified that you are using the correct baud rate?
The library docu example suggests to wait for the heartbeat with node.nmt.wait_for_heartbeat(). Why are you using a sleep instead? If there is no heartbeat, you don't need to continue. (Unless the device docu says that it doesn't implement NMT heartbeat - would be unusual.)
I certainly wouldn't try to go ahead with SDOs if you cannot confirm a NMT heartbeat. Also, some devices don't implement SDOs but only PDOs.
Try sniffing the CAN bus at a lower level (e.g. not PDOs/SDOs but just print the raw messages received - from Python, or with a separate application - e.g. candump on Linux.) Try getting statistics of the CAN "network" interface (on Linux, e.g. ifconfig). If everything is okay, the adapter should be in state "ERROR-ACTIVE", and you should see the frame counter increase for frames you've sent via Python.
I have a serial Python program, Linux environment (Raspbian / Raspberry Pi), that uses a serial port via a USB-to-serial adapter. I need to handle a situation when the user unplugs the USB adapter and then reinsert it.
The problem is that, on reconnect, the ttyUSB0 becomes ttyUSB1 and so the port is no longer found. However, if I stop the Python program (keyboard interrupt) and again unplug and reinsert the USB adapter, then the port goes back to ttyUSB0 (and so I can start over again). This can happen only when the Python program is stopped.
I tested the program in a flip-flop mode (and it seems to be working) in order to use ttyUSB1 when ttyUSB0 is no longer found and then vice versa, use ttyUSB0 back in case ttyUSB1 is no longer found, etc., but this looks like a weird solution to me.
Is there a better way to force pySerial to "forget" it has ever been connected to ttyUSB0 in case of error and release the current port to the system while the program is still running?
Here is a working flip-flop test program:
import serial
import time
p = "/dev/ttyUSB0"
while True:
error_flag = False
try:
s = serial.Serial(port=p, baudrate=9600, bytesize=8, parity="N", stopbits=1, timeout=None, xonxoff=False, rtscts=False, write_timeout=None, dsrdtr=False, inter_byte_timeout=None)
except Exception as e:
error_flag = True
if "ttyUSB0" in str(e):
p = "/dev/ttyUSB1"
print ("port is now", p)
elif "ttyUSB1" in str(e):
p = "/dev/ttyUSB0"
print ("port is now", p)
else:
print (e) # none of the above
# if not error_flag, do whatever, etc.
time.sleep(1)
You could try creating a udev rule that would create a symbolic link to that USB device and then you would be able to use something like /dev/myUSB that would always stay the same for that specific USB device.
First, you will need to find some identifying information for the USB drive. Typing in lsusb should display some information that looks like:
Bus 001 Device 004: ID 0403:6001 Future Technology Devices International
In this example 0403 is the Vendor Id and 6001 is the Product Id.
Create a file named 99_usbdevice.rules (I don't think the name matters, just the directory):
sudo nano /etc/udev/rules.d/99_usbdevices.rules
Note that the directory above may be specific to Raspbian.
Copy/paste the line below into the file and save it:
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", SYMLINK+="myUSB"
Restart your Raspberry Pi or unplug the USB and reinsert it. There should now be a /dev/myUSB entry that you can use the same way you would the ttyUSB# entry.
If the opened port file is closed when unplugged (or on error handler), then the port name will not change on subsequent connection of the USB device. If left open then it will create a different name each time.
Do not forget to close the file descriptor of /dev/ttyUSB0 as soon as you detect that the user unplugged the USB adapter (read or write with error), and before the reinsertion.
If you properly close the device, the ttyUSB1 device will never appear. On the other hand, you can see in some cases also ttyUSB2, ttyUSB3, and so on, if all the previous ttyUSBx's are blocked because not closed.
I am trying to use a Raspberry Pi 3B (run Ubuntu Mate 16.04 operating system)as a Master to read values from an electric energy meter which supports Modbus-RTU protocol.
I used a RS232/USB adapter and a RS485/RS232 adapter to link the meter and the USB port on the Raspberry Pi. I have tried the modbus_tk 0.5.7 and MinimalModbus to implement the communication under Modbus-RTU protocol.
When I use modbus_tk 0.5.7 and run the following code:
import sys import serial
#add logging capability import logging import modbus_tk import modbus_tk.defines as cst import modbus_tk.modbus_rtu as modbus_rtu
logger = modbus_tk.utils.create_logger("console")
if __name__ == "__main__":
try:
#Connect to the slave
master = modbus_rtu.RtuMaster(serial.Serial(port="/dev/ttyUSB0", baudrate=9600, bytesize=8, parity='N', stopbits=1, xonxoff=0))
master.set_timeout(5.0) #Change the timeout value/Defines a timeout on the MAC layer
master.set_verbose(True) #print some more log prints for debug purpose
logger.info("connected")
logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 49))
except modbus_tk.modbus.ModbusError, e:
logger.error("%s- Code=%d" % (e, e.get_exception_code()))
The parameters such as port, baudrate, bytesize,parity,and stopbits were set correctly, but it always returns this:
2017-08-10 19:24:34,282 INFO modbus_rtu.__init__ MainThread RtuMaster /dev/ttyUSB0 is opened
2017-08-10 19:24:34,283 INFO rtumaster_example.<module> MainThread connected
2017-08-10 19:24:34,284 DEBUG modbus.execute MainThread -> 1-3-0-0-0-49-132-30
2017-08-10 19:24:39,291 DEBUG modbus.execute MainThread <-
Traceback (most recent call last):
File "rtumaster_example.py", line 34, in <module>
logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 49))
File "build/bdist.linux-x86_64/egg/modbus_tk/utils.py", line 39, in new
modbus_tk.exceptions.ModbusInvalidResponseError: Response length is invalid 0
When I use MinimalModbus and run the following code:
#!/usr/bin/env python
import minimalmodbus
instrument.serial.port='/dev/ttyUSB0' # this is the serial port name
instrument.serial.baudrate = 9600 # Baud
instrument.serial.bytesize = 8
instrument.serial.parity = serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout = 0.05 # seconds
#instrument.address # this is the slave address number
instrument.mode = minimalmodbus.MODE_RTU # rtu or ascii mode
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 1) # port name, slave address (in decimal)
energy = instrument.read_register(10, 1) # Registernumber, number of decimals
print energy
It always returns this:
raise IOError('No communication with the instrument (no answer)')
IOError: No communication with the instrument (no answer)
And then I use the same serial transmission line to link the meter and the laptop, and use a debugging tool running on Windows XP, which was developed by the manufacturer of the meter. The debugging tool sends the same Request (1-3-0-0-0-49-132-30) as before, but the debugging tool can get correct Responses. (Maybe it's because it ignored some incorrect Responses and keep on send Requests regularly) And it can represent that the Request message is correct and the connection of serial transmission has no problem.
I also used the CuteCom(a graphical serial terminal) and the RS232/USB adapter to confirm that the USB port can send and receive correctly. It is also useless to add a resistor between two RS485 lines
I have tried many times, but the Raspberry Pi never gets a Response, and always returns the same error information. I also try to run the same code on a Ubuntu virtual machine, it returned the same message as above and never get a Respond.
I am new to Modbus and serial communication, so any help would be appreciated.
I have solved my problem by using a more expensive USBtoRS485 connector.
The problem took me a lot of time to try different library and different code.
It turns out that the adapter "QinHeng Electronics HL-340 usb-serial" that I bought works well on windows but does not work with Linux. It can achieve send and receive message on Linux, but it just can`t support Modbus communication.
So I suggest you buy a more expensive connector, and it may save your a lot of time and energy.
That`s all, thank you!
I was having the same problem. After use mbpoll tool I have realized the parity was wrong. Just updated to parity.EVEN and it is ok now.
Try connecting RS232-end of a cable into PC with serial port (if you have it ofc) to ensure usb/rs232 works
If you have oscilloscope (like fluke), you can observe RS485 line (it is not difficult in fact) to understand where is the issue.
It happened to me to find out that serial parameters (like baud rate) can be configured it 2 places for Windows - when you open the port and in driver configuration.
Try equalize the potential for all devices. I know rs485 is supposed to be immune to it but rs232 not
You have a too short time out on your Pi, try increasing it to 100 ms and it should work.
EDIT: As requested in the comment below I'm giving some more details on my suggestion. Based on the details given on the question and subsequent answers and comments the hardware setup seemed to be correct. I've seen this happen from time to time: when you set a very short timeout on one side the link suddenly stops working (it makes sense too, a timeout error occurs when you have not received an answer within the timespan you determine with the timeout parameter), and it goes back alive as soon as you increase it again. I've also noticed this effect is hardware dependent, some devices are able to answer faster than others
My issue is to make a serial communication between raspberry pi and another hardware. The recommended connection for this hardware is as shown on the manual, I have to connect, RX, TX, GND, RS, and CS.
But on raspberry pi we have only RX, TX so I connected RX and TX and The GNG of Pi to this hardware.
I modified Pi's parameters as shown on the link : here
Then I maked a simple python program that initialize the communication, and send data.
Here is the code :
import serial,os
port=serial.Serial("/dev/ttyAMA0",baudrate=9600)
print ('port is ok')
port.write('Command')
rcv=port.read(10)
print rcv
after running this code on pi, I got ('port is ok'), But the problem is that this hardware don't respond correctly to the command, and as respoce it gave me normally OK, but I got some extra caracter( non readable).
Is that a problem of encoding? Can some one help about this?
You need to check the baud rate on the other hardware
or make sure that the length of the received message = to the printed message.
In a serial communication, there are two important things to be careful :
The two devices have to work with the same baudrate IF the link is bidirectional.
When writing data on serial, you have to flush data just after the write().
refer to here for it.
In a lot of case, flush isn't needed, but when two different devices have to communicate, it could unlock the comm'.
If it's not efficient, try to set up your other device with the same conf (no flow control, etc)
I am attempting to receive data from the qu-bot at http://www.qu-bot.com. The robot has an ATML atmega16 microcontroller. I have written a program that runs on the robot which outputs data to its serial port. The program however stops whenever I connect to the controller. I tested this by adding a beep statement. The robot beeps as long as the program is running. The beeping stops when I connect to the robot. I tried qu-bo support and they suggested disabling the dtr flag on the serial port. I did that but no joy.
Is there anything else I can try?
[start of code running on the qu-bot]
Note:
This is written in some kind of proprietary variant of C which they call quick c.
// This code displays the uart functions.
int main(void)
{
INIT();
UART_INIT(57600);
UART_PRINT("HELLO!!\n");
DELAYS(1);
UART_PRINT("MY NAME IS QU-BOT.\n");
DELAYS(1);
UART_PRINT("HELLO!!\n");
UART_PRINT("YOU ARE USING UART SAMPLE CODES.\n");
while(1)
{
UART_PRINT("test\n");
BEEP();
DELAYS(60);
}
}
now for my python serial port reading program. I have tried this program both on raspbian and on windows 7 64bit. I am pasting the windows version. The raspbian version has a different name for the linux.
import serial
import time
ser=serial.Serial()
ser.port=8
ser.baudrate=57600
ser.setDsrDtr(False)
print 'initialized'
flag = ser.isOpen()
if flag:
print 'port already open.'
pass
else:
ser.open() # opening the port 'ser' that was just created to receive data
time.sleep(0.5)
print 'ready to read'
print ser
ser.write('a')
s=ser.read(4)
print s
ser.close()
Pranav
P.S. I have consulted the following links amongst others.
<https://learn.sparkfun.com/tutorials/terminal-basics/all>
<http://www.plainlystated.com/2013/06/raspberry-pi-serial-console/>
<http://elinux.org/RPi_Serial_Connection>
<https://learn.sparkfun.com/tutorials/terminal-basics/all>
Based on my experience in serial communications with microcontrollers the most likely cause of this problem is that when you connect the serial cable to the robot it causes a phantom byte (due to electrical noise that happens when you make the connection) to look like it's coming from the controller - either this or the controller is sending a legitimate byte to the robot. In either case it is likely that the arrival of a byte at the robot's serial port (even if it was only electrical noise mistaken to be a data byte - this is a very common occurrence) caused the robot's microcontroller to invoke the UART receive interrupt. If you don't have an appropriate UART receive handler (ISR - Interrupt Service Routine) written and linked into the correct interrupt vector then your robot's microcontroller can go off into "deep space" upon the detection of the first incoming serial data byte - and make your robot appear to "hang". If you intend to do "polled" serial communications (your code manually checks for received bytes in its main loop) instead of interrupt-driven (hardware detection of an incoming byte causes your UART Rx ISR to be invoked) then all you have to do is to disable UART interrupts and your problem should go away.