changing update rate with gpsd and python - python

I'm using the adafruit ultimate GPS breakout with my Raspberry Pi 2 using python2.7.9, GPSD, and the python-gps package. I'm successfully getting gps updates at 1Hz over the serial port.
This device is supposedly capable of 10Hz updates, which I would like to enable. According to the datasheet (see snippet below), this can be set by serial command.
My problem is that I can't find sufficient documentation for the python-gps module or GPSD that would tell me how I'm supposed to send commands to the GPS over serial with my python script. Can someone point me in the right direction?

I just picked up a gps from the same family as yours. (MTK) They use $PMTK control strings. Any search for PMTK protocol gives endless resources. The limit is the gps itself.
For a one-off conversion, the standard method is from a root terminal execute echo -e "\$PMTK220,200*2C\r\n" > /dev/ttyAMA0, or wherever the device is attached, for a 5Hz response. The
-e flag allows parsing the backslash(s)
$ The start of the NMEA sentence
P Proprietary message
MTK NMEA Data type
220 Packet type
200 Packet data
* End of data
2C Checksum
\r\n The end of the NMEA sentence
There are scripts and other projects available as well, but all require the gpsd to not be in control of the gps. The gpsd will prevent sending a control string to the gps.
Additionally, if you have the -b flag in /etc/default/gpsd the gpsd will not write to the device when it is attached. It will choose a generic NMEA driver, and will not write any control strings to the gps.
You can slip in behind, and manipulate the rate with control strings from the shell. The gps will spew the data, but the gpsd will not acknowledge the rate.
It appears, gpsd prefers the 1 second timing. Even if the gps is capable of faster cycles, even if you have already use another methods to re/set the rate, and it doing so, the gpsd needs to be told the rate has changed.
This is where gpsctl -c 0.2 (no sudo) comes into play. It is bundled in the gpsd package.
If there is only one device connected to the gpsd, in the example, gpsctl will change that device to 0.2 second timing cycles and convey that to the gpsd. The time is in seconds. Yes, it can be set pretty slow/fast, but there's no faking ability. If it can't do it, it won't do it, nor tell you that it hasn't/can't, unless there is a fatal error.
Port speed is not an issue, as long as there is capacity. Someone who counted once said 4800 baud is sufficient for one reading of data in the one second it takes to send the data. It depends on payload, but it works for a rule of thumb. 10Hz might make the 38400 baud default on many systems. I tried it and nothing broke.
You just want to make sure gpsd hasn't negotiated to 9600 baud before you can ramp up the speed, just in case. gpsctl -s XXXX (to set the baud rate at which the GPS emits packets) returns an error for me.
Even without the -bflag in the gpsd default setting, this new gps of mine doesn't stay latched into the higher frequency updates between powerdowns. I must re-issue the command. It might be a bad battery, operator error, or I don't understand this defect is a feature to not latch the gps out of reach for other systems. (A reason for the -b)
This is how you change the response from a gps that uses the gpsd, or how I did.
In answering your question, however, to change the rate of a gps response through the gpsd with Python
import subprocess
subprocess.call(['gpsctl', '-c', '0.2']) # Digits are the time in seconds.
Try it and see. Using gpsctl -c 0.25 returns quarter second gps readings, etc..
To help are two Python gpsd client demonstration scripts to which I have just added a gpsd device report refresh keystroke, (Hit d to refresh and see the numbers from the new setting.)
They are for a Python 2.7-3.5 gpsd python client, when the function finds a home in the demo scripts it will look something like this:
def hertz(hz):
"""Change or enumerate a Faster/Slower gps refresh rate if device is able"""
from subprocess import call
inverse = str(1 / hz)
call((['gpsctl', '-c', inverse]))

Related

CanOpen communication (Python) 1 Slave and CAN-USB adapter

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.

How to get data directly from XBee iolines

Hi I have XBee RF mode S2C which does not have internal storage to run micropython. So I need to get data from KY-001 sensor connected its iolines. With python library I didnt get anything just get_adc_value(ioline) function which seems doesnt do anything. I need to check sensor in local device for now .After I gonna use same solve to remote devices (I only use Python XBee library). Or exactly can I use Xbee iolines directly to get data from sensor without external MCU?
I don't think you'll be able to interface to this 1-Wire sensor, it's intended for a microprocessor that can handle timing requirements and uses a tristate I/O line (IIRC).
You should be looking at temperature sensors with an analog voltage output (like this TMP36) that you can tie to one of the analog inputs of the XBee, and then read that input with a remote ATIS for a single sample or ATIR for periodic sampling.

Minimum delay to communicate through serial using Python

I have a simple Python script to communicate with a micro-controller (STM32F103C8T6) using the serial port. I'm using pySerial to write a couple of 44-bytes messages at a time.
[...]
serial = serial.Serial(serial.tools.list_ports.comports()[0].device, 115200)
packet0 = bytearray(INSERT_RELEVANT_44-BYTES)
packet1 = bytearray(INSERT_RELEVANT_44-BYTES)
serial.write(packet0)
time.sleep(0.1) # Delay between communications
serial.write(packet1)
[...]
I had to insert a delay between the communications, otherwise it wouldn't work. My reasoning is that for a baud rate of 115200 bps the messages should take 44*8/115200 = ~0,003 seconds to be sent, thus this should be the minimum ideal interval between sending the packets. The code, however, doesn't work for anything smaller than 0,1.
Why? Am I missing something? I suppose there is some delay due to the operating system and the USB, but it shouldn't account for ~0,7 seconds. How can I optimize this to use the minimum possible delay?
Rather then calculating a nominal delay based on the UART link, you could simply poll the serial driver to determine whether the Tx buffer is empty:
serial.write(packet0)
while serial.outWaiting() > 0 :
pass
serial.write(packet1)
This has the advantage of accounting automatically for any latency, software overhead and buffer limitations anywhere in the chain of application code, library, driver, USB-Serial bridge. It will not however solve any problem with the STM32 serial I/O implementation, you should probably address the root problem of why the data cannot be streamed, which is most likely down to poor implementation of the at the STM32 device end.

how do I monitor data from serial port and have certain data act as a flag in Python

I am working on a project for work and I am stuck on a part where I need to monitor a serial line and listen for certain words using python
so the setup is that we have a automated RAM testing machine that tests RAM one module at a time and interacts with software that came with the machine via serial. The software that came with the RAM tester is for monitoring/configuring the testing process, it also displays all of the information from the SPD chip from each module. while the RAM tester was running I ran a serial port monitoring program and I was able to see the same information that it displays in the software. The data I'm interested in is the speed of the RAM and the pass/fail result, both of which I was able to find in the data I monitored coming over the serial line. There are only 5 different speeds of RAM that we test, so I was hoping to have python monitor the serial line and wait for the speed of the RAM and the pass/fail results to come across. once python detects the speed of the RAM, and if it passes, I will have python write to an Arduino, and the Arduino will control a conveyor belt that will sort the ram by speed.
my idea is to have a variable for each of the RAM speeds and set the variables to 0. when python detects the RAM speed from the serial line it will set the corresponding variable to 1. then when the test is over the results, either pass or fail, will come over the serial line. this is where I am going to try to use a if statement. I imagine it would look something like this:
if PC-6400 == 1 and ser.read() == pass
ser.write(PC-6400) #serial write to the arduino
I know the use of the ser.read() == pass is incorrect and that's where I'm stuck. I do not know how to use a ser.read() function to look for certain words. I need it to look for the ram speed (in this case its PC-6400) and the word pass but I have not been successful in getting it to find either. I am currently suck in is getting python to detect the RAM speed so it can change the value of the variable. would it be something close to this?
if ser.read() == PC-6400
PC-6400 = 1
This whole thing is a bit difficult for me to explain and I hope it all makes sense, I thank you in advance if anyone can give me some advice on how to get this going. I am pretty new to python and this is the most adventurous project I have worked on using python so far.
I'm still a bit confused, but here's a very basic example to hopefully get you started.
This will read from a serial port. It will attempt to read 512 bytes (which just means 512 characters from a string). If 512 bytes aren't available then it will wait forever, so make sure you set a timeout when you made the serial connection.
return_str = ser.read(size = 512)
You can also see how many bytes are waiting to be read:
print "num bytes available = ", ser.inWaiting()
Once you have a string, you can check words within the string:
if "PASS" in return_str:
print "the module passed!"
if "PC-6400" in return_str:
print "module type is PC-6400"
To do something similar, but with variables:
# the name pass is reserved
pass_flag = "PASS"
PC6400 = 0
if pass_flag in return_str and "PC-6400" in return_str:
PC6400 = 1
Keep in mind that you it is possible to read part of a line if you are too quick. You can add delays by using timeouts or the time.sleep() function. You might also find you need to wait for a couple of seconds after initiating the connection as the arduino resets when you connect. This will give it time to reset before you try and read/write.

How does PySerial work?

Say I have the following python script to read in serial data from my Arduino:
import serial
ser = serial.Serial("dev/ttyACM1", 9600)
ser.timeout = 2
ser.readlines()
On the other end I've flashed my Arduino with a program that sends 20 voltage readings every 0.5 seconds. The Arduino starts sending those readings from the moment it's hooked up, then after 20 seconds it stops and sends nothing.
Now what I've noticed is that I can read those 20 voltage values using the first script whenever I want. That is, I can hook up the Arduino, wait a couple of minutes then read in the values. This makes me think that the data is getting stored somewhere. I'm inclined to think that it's not being stored on the Arduino but on my laptop somewhere.
I've come up with a few questions that I hope the community could help me with:
Where is PySerial getting the data from (the Arduino or some buffer on my laptop)?
For how long is the data stored in this place?
Is there a way to clear this space before reading in values?
How much storage space is there?
When you set the baud rate in PySerial (second line in script), is this the rate that
PySerial reads data from the storage area (not the Arduino)?
I've noticed that if I set the baud rate in PySerial too high the first few lines of data are fragmented and sometimes completely wrong, why?
Not exactly related but when you set serial.Serial.timeout are the
units in seconds?
I appreciate your time.
Have you tried using a terminal program like TerraTerm (windows) or GTKTerm (linux) to open the same port to the arduino? I think this would be helpful to answer some of your questions.
Some quick answers to your questions that I can dump off the top of my head.
From the port specified, I'm guessing you are asking something deeper than this?
If you do a
x = ser.readlines()
then the data will be in x as long as you'd like.
There is a flush function defined in PySerial
Not sure. You can specify how many characters you would like to read though
example:
x = ser.read(number)
The pyserial documentation states the following
Read size bytes from the serial port. If a timeout is set it may return less characters as requested. With no timeout it will block until the requested number of bytes is read.
http://pyserial.sourceforge.net/pyserial_api.html
This is the clock rate of the port you are opening, ie /dev/ttyACM1, most serial comms are at 9600, if you happen to be using a USB to serial you'll need 115200
Clock rate mismatch. You're computer is sampling data at a rate higher than the arduino is providing it, causing it to be incorrectly displayed.
Seconds, quote from Pyserial documentation : "timeout = x: set timeout to x seconds (float allowed)" Same link as number 4
Hope that helps some!

Categories