I'm trying to send some packages from an MSP to a Raspberry Pi 3 through 2 Xbee S1 modules.
Xbee are configured as DigiMesh 2.4 with escaped frames, one as router and other as coordinator. At the raspberry the connection is made with USB dongle.
My code, at MSP, sends a package at every 10 us with CTS flow control. When the coordinator is plugged into my PC running windows, I can see, through XCTU, all packages arriving, everything just fine!!!
But, when the dongle is at raspberry, running Raspbian and the following code, some packages can not arrive.
As everything works properly with XCTU, the problem resides in the code, probably handling serial port or anything similar to that.
So, any help would be much appreciate!!!
start.py:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# copyright: Thiago Cruz <thiagoalberto#gmail.com>
import sys
import os
from PyQt4 import QtGui
from middleware.QueueMiddleware import QueueMiddleware
from jobs.ScheduleJob import ScheduleJob
def startQueue():
queue = QueueMiddleware()
queue.start()
def assyncSchedule():
schedule = ScheduleJob()
schedule.run()
def runApp():
startQueue()
app = QtGui.QApplication(sys.argv)
sys.exit(app.exec_())
if __name__ == '__main__':
runApp()
QueueMiddleware.py:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# copyright: Thiago Cruz <thiagoalberto#gmail.com>
import threading
import time
import serial
import Queue
from middleware.DataProcessorGear import DataProcessorGear
from xbee import ZigBee
minutes = 0
class QueueMiddleware(threading.Thread):
__instance = None
PORT = '/dev/ttyUSB0'
BAUD_RATE = 9600
# The XBee addresses I'm dealing with
BROADCAST = '\x00\x00\x00\x00\x00\x00\xFF\xFF'
UNKNOWN = '\xFF\xFE' # This is the 'I don't know' 16 bit address
def __new__(cls):
if QueueMiddleware.__instance is None:
QueueMiddleware.__instance = super(QueueMiddleware, cls).__new__(cls)
return QueueMiddleware.__instance
def __init__(self):
QueueMiddleware.__instance = self
threading.Thread.__init__(self)
self.dataPacketsQueue = Queue.Queue()
# Create API object, which spawns a new thread
self.ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
self.xbeeApi = ZigBee(self.ser, callback=self.message_received, escaped=True)
print 'start queue'
def __del__(self):
# halt() must be called before closing the serial
# port in order to ensure proper thread shutdown
self.xbeeApi.halt()
self.ser.close()
self.processor = None
def run(self):
# Do other stuff in the main thread
while True:
try:
time.sleep(1)
#if self.dataPacketsQueue.qsize() > 0:
# lock = threading.Lock()
# processor = DataProcessorGear(self.dataPacketsQueue, lock)
# processor.start()
except KeyboardInterrupt:
break
def message_received(self, data):
global minutes
minutes += 1
print minutes
self.dataPacketsQueue.put(data, block=True, timeout=None)
I already tried to change the values of time.sleep() and have suppressed the execution of the subsequent threads to "isolate" the problem.
My console displays values from ~120 to ~170. MSP only sends 200 data packages!!
So... any guesses ??
Thanks in advance.
Enable hardware flow control and change the baudrate from 9600 to 115200. You'll have to update your XBee module configuration for the new baudrate, but you'll stand a chance of getting your packets through.
I assume you meant to write that you're sending packets every 10ms instead of every 10us. At 10ms/packet, you're at 100 packets/second. 9600 baud is only about 960 characters per second, and your packets are surely larger than 9 characters with the API overhead.
Kind of a solution.....
After trying different approaches in my code, even tried the script below...
#!/usr/bin/python
import serial
serialport = serial.Serial("/dev/ttyUSB0", 115200, timeout=None,rtscts=True,dsrdtr=True)
while True:
serialport.flush()
command = serialport.readline()
print str(command).encode('hex')
I was able to get a desired behavior by changing the XBee MR parameter (Mesh unicast retries - The maximum number of network packet delivery attempts) to the maximum (0x7), none of my packages are lost, even for a delay of 0s (zero) between the transmission of each package.
Probably, as said by tomlogic, if I run my code on a faster PC, I believe, I'll get my packages.
When I do this test, i'll post the results here.
Thanks.
Related
I'm not sure what I'm really doing here and need a little guidance to point me in the right direction with regards to CANBUS sniffing.
I am currently using a PiCAN2 (with gps and gyro) with a raspberry pi 4 to sniff the CANBUS output from a mobileye detection unit. I have the CAN output protocol of the mobileye, the raspberry pi is set up with all the libraries installed and everything seems to be working correctly except the capture of CAN data (the logger captures GPS and all the kinematic data perfectly).
I've been going around in circles because I can't seem to find why I get very intermittent CAN data from the mobileye unit.
I am trying to get send a request to the unit and waiting for any output but am not getting anything.
I even just try to run:
candump can0 or cansniffer can0 and dont get anything.
I've tried to tie directly to the vehicle CAN as well and get intermittent CAN as well.
I've soldered on a jumper to bridge JP2 to use the 120 ohm resistor but that makes the can0 interface disappear. Confirmed this using ifconfig and so I leave the jumper open.
I also sometimes get an sm.smBUS error message that bus.recv() does not exist?
My code is as follows:
from gps import *
import datetime
import sys
import smbus
import math
import time, inspect
import signal
import serial
import RPi.GPIO as GPIO
import can
import os
import binascii
import bitstring
from bitstring import BitArray
import threading
from threading import Thread
from can import Message
try:
import queue
except ImportError:
import Queue as queue
#### Bring up can0 interface at 500kbps
os.system("sudo /sbin/ip link set can0 up type can bitrate 500000")
time.sleep(0.1)
print('Ready')
#### define global variables
PICANGPS_PORT = "/dev/serial0"
led = 22
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(led,GPIO.OUT)
GPIO.output(led,True)
mbdata = ''
PID_REQUEST= 0x7DF
###### ive left out some bits relating to GPS and the file name definitions
#### Communicate with CAN interface
try:
bus = can.interface.Bus(channel='can0', bustype='socketcan_native')
except OSError:
print('Cannot find PiCAN board.')
GPIO.output(led,False)
exit()
#### CAN Receive thread
def can_rx_task(): # Receive thread
while True:
print ('Receiving Message')
msg = bus.recv()
if msg.arbitration_id == MB_DISPLAY:
q.put(msg) # Put message into queue
print ('Received Message!')
if msg.arbitration_id == CAR_SIGNALS:
q.put(msg) # Put message into queue
print ('Received Message!')
#### CAN Transmit thread
def can_tx_task(): # Transmit thread
while True:
GPIO.output(led,True)
# Sent a Engine coolant temperature request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],extended_id=False)
bus.send(msg)
time.sleep(0.05)
GPIO.output(led,False)
time.sleep(0.05)
q = queue.Queue()
rx = threading.Thread(target = can_rx_task)
rx.start()
tx = threading.Thread(target = can_tx_task)
tx.start()
#### main loop
try:
while True:
# create log file - timestamped
f=open(path+fname+".csv",'a')
# get current timestamp
now = datetime.datetime.now()
picantimestamp = now.strftime("%Y/%m/%d %H:%M:%S.%f")
#### mobileye CAN sniff loop
for i in range(4):
# CAN sniff for CAN data frame
if q.empty() != True: # Check if there is a message in queue
mbdata = q.get()
c = '{0:f} {1:d} {2:x} '.format(mbdata.timestamp,count, mbdata.arbitration_id, mbdata.dlc)
s = ''
print ('Received CAN Message')
for j in range(mbdata.dlc):
s += '{0:x} '.format(mbdata.data[j])
Does anyone have any suggestions on what I should try to troubleshoot this?
Happy to discuss it further, I'm just a little confused and would gladly take any input.
I'm trying to understand why I'm not able to open multiple times the same serial port with Digi-Xbee (import digi.xbee) API for python while with Xbee (import xbee) API for python I can.
When I run the code bellow the exception digi.xbee.exception.InvalidOperatingModeException: Could not determine operating mode is raised.
from digi.xbee.devices import *
import time
import codecs
class start(object):
while True:
xbeeApi2 = DigiMeshDevice(port='/dev/ttyUSB0', baud_rate=9600)
xbeeApi2.open()
time.sleep(0.5)
message = xbeeApi2.read_data(timeout=None)
if message is not None:
print(codecs.decode(message.data, 'utf-8'))
time.sleep(1)
XBee module is a S2C (XB24C) set as Digimesh 2.4 TH, firmware 9002 (newest) with a USB Dongle.
Python is 3.7 & my host hardware is a Raspberry Pi 3 B+ running Debian.
Any help would be appreciated.
EDIT 1
Exception is raised when, for the second time, {xbeeApi2.open()} is executed.
In fact, my original code has multiple threads that import the class where the port is opened, many times before the previous thread had the chance to close it.
The 'original' piece of code, that runs fine is bellow:
from xbee import ZigBee
import serial
import time
class start(object):
while True:
ser = serial.Serial('/dev/ttyUSB0', 9600)
xbeeApi2 = ZigBee(ser, escaped=True) # S2 e S2C
time.sleep(0.5)
message = ''
try:
message = xbeeApi2.wait_read_frame(timeout=0.5)
except:
pass #timeout exception
if message is not None:
print(message)
time.sleep(1)
Well, you aren't closing it. Why not create the device and open it before your while True loop?
And you could configure it to just sleep for 0.1 seconds when message is None to reduce processor load. You'll be able to keep up with the message queue that way -- if there was a message, you want to immediately check for another queued message before doing any sleeping.
from digi.xbee.devices import *
import time
import codecs
class start(object):
xbeeApi2 = DigiMeshDevice(port='/dev/ttyUSB0', baud_rate=9600)
xbeeApi2.open()
while True:
message = xbeeApi2.read_data(timeout=None)
if message is not None:
print(codecs.decode(message.data, 'utf-8'))
else:
time.sleep(0.1)
I am developing an application in raspberry pi to use it as a location tracker. I am using neo-6m GPS via USB interface to get the position data in raspberry pi. For this I am setting up GPSD to point to the USB-Serial device. (See instructions)
The following python script polls the GPSD daemon and sends the location data to the parent process via a Unix Domain Socket:
#!/usr/bin/python
import os
from gps import *
from time import *
import time
import threading
import socket
import math
t1, t2 = socket.socketpair()
gpsd = None #seting the global variable
host = "localhost"
port = 8888
class GpsPoller(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
global gpsd #bring it in scope
gpsd = gps(mode=WATCH_ENABLE,host=host,port=port) #starting the stream of info
self.current_value = None
self.running = True #setting the thread running to true
def run(self):
print("%%%%%%%GPS RUN")
global gpsd
while self.running:
gpsd.next() #this will continue to loop and grab EACH set of gpsd info to clear the buffer
time.sleep(3)
def poll_gps(socket):
print('GPS POLL')
gpsp = GpsPoller() # create the thread
gpsp.start()
try:
while True:
#It may take a second or two to get good data
#print gpsd.fix.latitude,', ',gpsd.fix.longitude,' Time: ',gpsd.utc
#print 'latitude ' , gpsd.fix.latitude
#print 'longitude ' , gpsd.fix.longitude
if gpsd.fix.latitude is not None and gpsd.fix.longitude is not None and not math.isnan(gpsd.fix.longitude ) and not math.isnan(gpsd.fix.latitude ) and gpsd.fix.latitude != 0.0 and gpsd.fix.longitude != 0.0 :
gps_str='{0:.8f},{1:.8f}'.format(gpsd.fix.latitude, gpsd.fix.longitude)
dict_str="{'type' : 'gps', 'value' : '"+gps_str+"'}"
dict_str_new="{'type' : 'gps', 'value' : '"+str(gpsd.fix.latitude)+","+str(gpsd.fix.longitude)+"'}"
print("GPS123_OLD" +dict_str)
print("GPS123_NEW" +dict_str_new)
if socket == None:
print("GOT GPS VALUE")
sys.exit(0)
socket.sendall(dict_str+'\n')
else:
print('%%%%%%%%%%%%%%%%%%GPS reading returnd None!')
time.sleep(3) #set to whatever
except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
print "\nKilling Thread..."
gpsp.running = False
gpsp.join() # wait for the thread to finish what it's doing
print "Done.\nExiting."
if __name__ == '__main__':
poll_gps(None)
When I run this code and move the raspberry pi setup to 1 Kilometre away, I can see new distinct lat-long values printed in console. But when I plot these values, I see that all these locations are at the starting point. ie all values are bunched around the same starting point. I am not able to see a clear path to the point 1 km away.
To check if the problem is with my code or not, I installed "navit" software in raspberry pi and pointed it to the GPSD daemon. When I used navit to plot my path, it showed my progress correctly in the map. So I concluded that the problem is with my code.
Can someone take a look and let me know if there is any issue with my code
I figured out the issue. In the "run" method of the "GpsPoller" class, I am invoking a sleep call. It seems this delay make the python client lag behind the GPSD demon in retrieving the location data queued by the GPSD daemon. I just removed the sleep and I started getting the correct locations in time.
def run(self):
print("%%%%%%%GPS RUN")
global gpsd
while self.running:
gpsd.next() #this will continue to loop and grab EACH set of gpsd info to clear the buffer
#time.sleep(3) REMOVE/COMMENT THIS LINE TO GET CORRECT GPS VALUES
I've a target board which sends me CPU load for every 1sec which communicates through serial port. I want to write a python code which reads data from serial port for every 1sec second and writes to a file and also it should check for user input i.e. if user enters command it should pass that command to target board.
You can create two threads, one listening for user input, the other polling the serial port every second. Check out threading for information on multithreading in python and pyserial for information on reading from serial ports. The threading package provides your desired repetition functionality: https://docs.python.org/2/library/threading.html#timer-objects
[EDIT]
Sample code, obviously replace /dev/ttyS1 with the desired port and do something useful with the user input:
import serial
import threading
def read_from_serial():
# port = "/dev/ttyS1"
# ser = serial.Serial(port, 19200, timeout = 1)
# print ser.readline()
# ser.close()
print "read"
threading.Timer(1, read_from_serial).start()
if __name__ == "__main__":
serial_thread = threading.Thread(target = read_from_serial())
serial_thread.start()
while True:
print raw_input("User input: ")
I have two Xbee Pro 900's, each attached to a Raspberry Pi. Both are updated to version 1061 and are set to API Enable with escapes. They also have the same Modem VID of 7FFF. Both Pi's have PySerial and the python-xbee library installed.
Xbee 1(Receiver) has a serial number of 0013A200409A1BB8
Xbee 2(Sender) has a serial number of 0013A200709A1BE9
I've included my code below, which is just sample code I've found online. My issue is that I'm not receiving anything on the appropriate Xbee. I have absolutely no idea what is wrong, I've triple checked the destination address, and both of the Xbee's configuration settings.
Xbee 2 Code(Sender):
#! /usr/bin/python
import time
from xbee import XBee
import serial
PORT = '/dev/ttyUSB0'
BAUD_RATE = 9600
# Open serial port
ser = serial.Serial(PORT, BAUD_RATE)
# Create API object
xbee = XBee(ser,escaped=True)
import pprint
pprint.pprint(xbee.api_commands)
DEST_ADDR_LONG = "\x00\x13\xA2\x00\x40\x9A\x1B\xB8"
# Continuously read and print packets
while True:
try:
print "send data"
xbee.tx_long_addr(frame='0x1', dest_addr=DEST_ADDR_LONG, data='AB')
time.sleep(1)
except KeyboardInterrupt:
break
ser.close()
Xbee 1 Code(Receiver):
#! /usr/bin/python
from xbee import XBee
import serial
PORT = '/dev/ttyUSB0'
BAUD_RATE = 9600
# Open serial port
ser = serial.Serial(PORT, BAUD_RATE)
# Create API object
xbee = XBee(ser,escaped=True)
# Continuously read and print packets
while True:
try:
print "waiting"
response = xbee.wait_read_frame()
print response
except KeyboardInterrupt:
break
ser.close()
When both programs are running, the Tx light on the sending Xbee blinks, but I receive nothing on the receiving Xbee. Is there something I'm missing? Thanks for your time!
Are you using XBee or XBeePro? I had the same problem and this post helped me a lot.
Try to modify the Receiver Code the following way:
import config
import serial
import time
from xbee import ZigBee
def toHex(s):
lst = []
for ch in s:
hv = hex(ord(ch)).replace('0x', '')
if len(hv) == 1:
hv = '0'+hv
hv = '0x' + hv
lst.append(hv)
def decodeReceivedFrame(data):
source_addr_long = toHex(data['source_addr_long'])
source_addr = toHex(data['source_addr'])
id = data['id']
samples = data['samples']
options = toHex(data['options'])
return [source_addr_long, source_addr, id, samples]
PORT = '/dev/ttyUSB0'
BAUD_RATE = 9600
# Open serial port
ser = serial.Serial(PORT, BAUD_RATE)
zb = ZigBee(ser, escaped = True)
while True:
try:
data = zb.wait_read_frame()
decodedData = decodeReceivedFrame(data)
print decodedData
except KeyboardInterrupt:
break
In my case the code above outputs the following:
[['0x00', '0x13', '0xa2', '0x00', '0x40', '0x9b', '0xaf', '0x4e'], ['0x68', '0x3f'], 'rx_io_data_long_addr', [{'adc-0': 524}]]
Here I shared configuration settings for Controller Node (compatible with X-CTU)
Are you sure the XBee modules are in escaped API mode (ATAP=2)? And 9600 baud?
Can you enable a mode in python-xbee to dump all characters in and out?
Have you confirmed the serial wiring is correct? (I see you're using USB, so that's not an issue.)
If you don't have hardware flow control hooked up, make sure the XBee modules have ATD6=0 and ATD7=0 set (disable RTS and CTS) and that python-xbee isn't expecting handshaking.
If you do have hardware flow control configured on the XBee, make sure you've told python-xbee to use it.
Can you use minicom or another serial terminal on the RaspPi to confirm that serial is working? Use minicom on the receiving end to see if you're getting anything at all?
Can you try sending and receiving with the radios connected to a PC instead of the Pi? Sending from the PC to the Pi, or vice-versa?