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
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 using one XBee S2 as coordinator (API mode), 3 XBee S2 as routers (AT mode). The routers are connected to Naze32 board (using MSP).
On the computer side, I have a GUI using wxpython to send out command to request data.
The GUI will send out command to XBee (Coordinator) to request data from the routers every second.
I am using python-xbee library to do the send and receive frame job on computer side. Once new data received, it will notify the GUI to update some labels with the new data.
Currently I am able to send and receive frames outside a thread, but once I move the send and receive functions to a thread, it will never be able to read a frame any more. As I don't want to let the serial stop the GUI or make it not responding. Another thing is if I close the thread, then start new thread with xbee again, it will not work any more.
The communication is controlled by a button on the GUI; once "Turn on" clicked, the "self._serialOn" will set to True, then create new thread; once "Turn off" clicked, "self._serialOn" will set to False and thread is stopped.
How can I fix this problem?
Thanks in advance.
class DataExchange(object):
def __init__(self):
self._observers = []
self._addressList = [['\x00\x13\xA2\x00\x40\xC1\x43\x0F', '\xFF\xFE'],[],[]]
self._serialPort = ''
self._serialOn = False
self.workerSerial = None
# serial switch
def get_serialOn(self):
return self._serialOn
def set_serialOn(self, value):
self._serialOn = value
print(self._serialOn)
if self.serialOn == True:
EVT_ID_VALUE = wx.NewId()
self.workerSerial = WorkerSerialThread(self, EVT_ID_VALUE, self.serialPort, self.addressList)
self.workerSerial.daemon = True
self.workerSerial.start()
elif self.serialOn == False:
self.workerSerial.stop()
del(self.workerSerial)
self.workerSerial = None
serialOn = property(get_serialOn, set_serialOn)
class WorkerSerialThread(threading.Thread):
def __init__(self, notify_window, id, port, addresslist):
threading.Thread.__init__(self)
self.id = id
self.serialPort = port
self.addressList = addresslist
self.counter = 0
self._notify_window = notify_window
self.abort = False
self.sch = SerialCommunication(self.serialPort, self.addressList)
try:
self.sch.PreLoadInfo()
except:
print('failed')
def run(self):
while not self.abort:
self.counter += 1
print('Serial Working on '+str(self.id))
self.sch.RegularLoadInfo()
#wx.PostEvent(self._notify_window, DataEvent(self.counter, self.id))
time.sleep(1)
def stop(self):
self.sch.board.stop()
self.abort = True
This question was finally solved with multiprocessing rather than threading of python.
In the manual of python-xbee, it mentioned that "... Make sure that updates to external state are thread-safe...". Also in the source code, threading was used.
So I guess in this case threading will cause problem.
Anyway, using multiprocessing it finally works.
I'm attempting to find a way to easily and cleanly close my code from an external os input. I have a python tcp server running on a beaglebone black or BBB awaiting a tcp/ip communication telling it to turn on and off a relay via gpio output and it works great, I wrote a windows program to control it remotely. My question is python related and not BBB related. I have this script running for the tcp/ip server interface and when i update the linux environmental variable "pyserv" the script doesn't get the update, it only knows the value of pyserv when the program starts. The trouble code is directly below.
while True:
pyserv = os.environ.get('pyserv')
if pyserv == "1":
server.socket.close()
break
However, before I start the script I can change the environmental variable to 0 and it will run. Alternatively, I can set it as 1 and it immediately closes. If i start the script and then change the environmental variable it doesn't get the update. I've also tried inserting this code into vardata.py and importing the value of vardata.py. I have the same result. Below I have my complete code in context. the problem code is at the very bottom.
#!/usr/bin/env python
import sys
import threading
import SocketServer
import os
import Adafruit_BBIO.GPIO as GPIO
GPIO.setup("P8_14", GPIO.OUT)
s1 = 0
class ThreadedEchoRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
global s1
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
cur_thread = threading.currentThread()
print self.data
if self.data == "1":
if s1 == 0:
GPIO.output("P8_14", GPIO.HIGH)
s1 = 1
elif s1 == 1:
GPIO.output("P8_14", GPIO.LOW)
s1 = 0
response = '%s: %s' % (cur_thread.getName(), self.data)
self.request.send(response)
return
class ThreadedEchoServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
if __name__ == '__main__':
import socket
import threading
HOST, PORT = "", 9999
# Create the server, binding to localhost on port 9999
server = SocketServer.TCPServer((HOST, PORT), ThreadedEchoRequestHandler)
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
t = threading.Thread(target=server.serve_forever)
t.setDaemon(True) # don't hang on exit
t.start()
print 'Server loop running in thread:', t.getName()
### This Is Where The Code That Is Giving Me Issue's lies. ###
while True:
pyserv = os.environ.get('pyserv')
if pyserv == "1":
server.socket.close()
break
### This Is Where The Code That Is Giving Me Issue's lies. ###
Just use a plain text file to store your pyserv data.
First create the pyserv data file. Eg,
echo 1 > vardata
Now run this:
test1.py
#! /usr/bin/env python
import time
def get_data(fname):
with open(fname, 'r') as f:
return int(f.read())
while True:
time.sleep(1)
pyserv = get_data('vardata')
print pyserv
Hit Ctrl+C to abort the script.
If you change the contents of vardata it will be reflected in the script output.
This is simpler (and safer) than storing your parameter in an executable Python file. But if you really do want to use a Python file for your parameters then you need the script to reload the imported data to make any changes visible.
vardata.py
pyserv = 1
test2.py
#! /usr/bin/env python
import time
import vardata
while True:
time.sleep(1)
reload(vardata)
print vardata.pyserv
Note that you have to do import vardata; if you do from vardata import pyserv the reload() call will fail.
I have a passive infrared sensor and I wanted to turn off and on my display based on motion. E.g. if there is no motion for 5 minutes, then the display should turn off to save power. However if there is motion don't turn off the display, or turn it back on. (Don't ask why isn't a screensaver good for this. The device I'm making won't have any keyboard or mouse. It only will be a standalone display.)
My idea was to create two threads, a producer, and a consumer. The producer thread (the PIR sensor) puts a message into a queue, which the consumer (which controls the display) reads. This way I can send signals from one to another.
I have a fully functional code below (with some explanation), which completes the previously described. My question is that is there some way to achieve this in a more elegant way? What do you think of my approach, is it okay, is it hackish?
#!/usr/bin/env python
import Queue
from threading import Thread
import RPi.GPIO as gpio
import time
import os
import sys
class PIRSensor:
# PIR sensor's states
current_state = 0
previous_state = 0
def __init__(self, pir_pin, timeout):
# PIR GPIO pin
self.pir_pin = pir_pin
# Timeout between motion detections
self.timeout = timeout
def setup(self):
gpio.setmode(gpio.BCM)
gpio.setup(self.pir_pin, gpio.IN)
# Wait for the PIR sensor to settle
# (loop until PIR output is 0)
while gpio.input(self.pir_pin) == 1:
self.current_state = 0
def report_motion(self, queue):
try:
self.setup()
while True:
self.current_state = gpio.input(self.pir_pin)
if self.current_state == 1 and self.previous_state == 0:
# PIR sensor is triggered
queue.put(True)
# Record previous state
self.previous_state = 1
elif self.current_state == 1 and self.previous_state == 1:
# Feed the queue since there is still motion
queue.put(True)
elif self.current_state == 0 and self.previous_state == 1:
# PIR sensor has returned to ready state
self.previous_state = 0
time.sleep(self.timeout)
except KeyboardInterrupt:
raise
class DisplayControl:
# Display's status
display_on = True
def __init__(self, timeout):
self.timeout = timeout
def turn_off(self):
# Turn off the display
if self.display_on:
os.system("/opt/vc/bin/tvservice -o > /dev/null 2>&1")
self.display_on = False
def turn_on(self):
# Turn on the display
if not self.display_on:
os.system("{ /opt/vc/bin/tvservice -p && chvt 9 && chvt 7 ; } > /dev/null 2>&1")
self.display_on = True
def check_motion(self, queue):
try:
while True:
try:
motion = queue.get(True, self.timeout)
if motion:
self.turn_on()
except Queue.Empty:
self.turn_off()
except KeyboardInterrupt:
raise
if __name__ == "__main__":
try:
pir_sensor = PIRSensor(7, 0.25)
display_control = DisplayControl(300)
queue = Queue.Queue()
producer = Thread(target=pir_sensor.report_motion, args=(queue,))
consumer = Thread(target=display_control.check_motion, args=(queue,))
producer.daemon = True
consumer.daemon = True
producer.start()
consumer.start()
while True:
time.sleep(0.1)
except KeyboardInterrupt:
display_control.turn_on()
# Reset GPIO settings
gpio.cleanup()
sys.exit(0)
The producer thread runs a function (report_motion) of a PIRSensor class instance. The PIRSensor class reads the state of a passive infrared sensor four times per second, and whenever it senses motion puts a message into a queue.
The consumer thread runs a function of (check_motion) of a DisplayControl class instance. It reads the previously mentioned queue in blocking mode with a given timeout. The following can happen:
If the display is on and there is no message in the queue for a given
time, aka the timeout expires, the consumer thread will power off the
display.
If the display is off and a message comes, the thread will
power on the display.
I think the idea is good. The only question I have about your implementation is why have both the consumer and producer in child threads? You could just keep the consumer in the main thread, and then there'd be no need to have this meaningless loop in your main thread.
while True:
time.sleep(0.1)
which is just wasting CPU cycles. Instead you could just call display_motion.check_motion(queue) directly.
I think it is a good solution. The reason being that you have separated the concerns for the different classes. One class handles the PIR sensor. One handles the display. You glue them together by a queue today, that's one approach.
By doing this you can easily test the different classes.
To extend this (read make it extendable) you might introduce a controller. The controller gets events (e.g. from the queue) and acts on the events (e.g. tell the Display Controller to turn off the display). The controller knows about the sensor, and knows about the display. But the sensor should not know about the display or vice versa. (this is very similar to MVC where in this case the data is the model (sensor), the display is the view and the controller sits in between.
This approach makes the design testable, extendable, maintainable. And by that you are not hackish, you are writing real code.