Reading serial and responding with Python - python

Everyone, hello!
I'm currently using trying to communicate with my Arduino (whom is hooked up my Raspberry Pi through Serial) and using the information in my Python script on my Raspberry Pi.
That said, my Python script has to wait for the Arduino to report back it's data before I want the script to continue, although, I'm not entirely sure on how to do that.
This is what I've got so far:
#!/usr/bin/env python
import time
import serial
import RPi.GPIO as GPIO
ser = serial.Serial('/dev/ttyACM0', 9600)
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(20, GPIO.OUT) #green LED
GPIO.setup(16, GPIO.IN, GPIO.PUD_UP) #green button
GPIO.output(20, True) #green ON
start = time.time()
while True:
if (GPIO.input(16) == False):
print "green button pressed"
time.sleep(0.25)
start = time.time()
while (GPIO.input(16) == False):
time.sleep(0.01)
if (GPIO.input(16) == True):
print "released!"
end = time.time()
elapsed = end - start
print elapsed
if elapsed >= 5:
print "longer than 5s"
else:
print "shorter than 5s"
ser.write("0")
while True:
print ser.readline().rstrip()
if ser.readline().rstrip() == "a":
print "ready"
continue
if ser.readline().rstrip() == "b":
print "timeout"
break
if ser.readline().rstrip()[0] == "c":
print "validated: " + ser.readline().rstrip()[2]
break
As you can see, I'm sending the number 0 to my Arduino, and wait for it to respond with a, which means it's ready. After which, when it has the data, it sends out the message "c", as a result, I need to wait for 2 different seperate messages.
I've tried to do this by having a loop and breaking it when I have what I need, but this doesn't work.
It currently does go into the loop, and it prints out the "a" message, but doesn't come back with the second message.
Any idea how to properly tie this loop?
Thank you!

use functions
def wait_for(ser,targetChar):
resp = ""
while True:
tmp=ser.read(1)
resp = resp + tmp
if not tmp or tmp == targetChar:
return resp
first_resp = wait_for(ser,'a')
second_resp = wait_for(ser,'c')
while not second_resp.endswith('c'):
print "RETRY"
second_resp = wait_for(ser,'c')

This worked out well for me to keep my while, and escape the block until I get what i want:
loop = 1
while loop == 1:
message = ser.readline().rstrip()
if message == "a":
print "ready"
continue
if message == "b":
print "Timeout"
loop = 0
if message[0] == "c":
print "Validated: " + message[2]
loop = 0
if message == "d":
print "error, try again"
loop = 0

Related

Stop speech recognition on keypress

Can I stop listening for audio on keyboard press?
I tried altering the record function (in init.py) like this:
def record(self, source, duration=None, offset=None):
"""
Records up to ``duration`` seconds of audio from ``source`` (an ``AudioSource`` instance) starting at ``offset`` (or at the beginning if not specified) into an ``AudioData`` instance, which it returns.
If ``duration`` is not specified, then it will record until there is no more audio input.
"""
assert isinstance(source, AudioSource), "Source must be an audio source"
assert source.stream is not None, "Audio source must be entered before recording, see documentation for ``AudioSource``; are you using ``source`` outside of a ``with`` statement?"
frames = io.BytesIO()
seconds_per_buffer = (source.CHUNK + 0.0) / source.SAMPLE_RATE
elapsed_time = 0
offset_time = 0
offset_reached = False
while True: # loop for the total number of chunks needed
if offset and not offset_reached:
offset_time += seconds_per_buffer
if offset_time > offset:
offset_reached = True
buffer = source.stream.read(source.CHUNK)
if len(buffer) == 0: break
if offset_reached or not offset:
elapsed_time += seconds_per_buffer
if keyboard.read_key() == "p":
print("\nYou pressed p")
break
frames.write(buffer)
frame_data = frames.getvalue()
frames.close()
return AudioData(frame_data, source.SAMPLE_RATE, source.SAMPLE_WIDTH)
And calling it from my main script like this:
def Main():
r = sr.Recognizer()
try:
with sr.Microphone() as source:
print("Listening....")
audio = r.record(source)
print("Recognizing....")
r.adjust_for_ambient_noise(source)
text = r.recognize_google(audio)
print(text.lower())
if "lock computer" in text.lower():
ctypes.windll.user32.LockWorkStation()
elif "joke" in text.lower():
joke = pyjokes.get_joke()
speak(joke)
except Exception as e:
print(e)
Main()
This listen to the audio and stops listening when I press p but does not recognize it
I figured it out, I saved the input file and saw that there was no audio in it so google could not reognize it.
The error was in this block:
if keyboard.read_key() == "p":
print("\nYou pressed p")
break
I changed this to:
if keyboard.read_key() == "p":
print("\nYou pressed p")
pressed = True
break
And copied the listen function and dublicated it, changed its name to listen1
And now when I press P it stops listening and recognizing is also working.

Python / PySerial / Arduino Reading serial data and later writing this exact serial data to the txt file

I am making a new post regarding this case because I was misunderstood in the first one...
I have a code that reads the serial data from the Arduino and when some specific digits are pressed on the keyboard it writes these digits to the Arduino. This exact code works perfectly when I run it, it reads the serial data and I am able to write data to the Arduino. I use threading and PySerial library to achieve this.
from pynput import keyboard
import threading
import serial
import sys
ser = None
class SerialReaderThread(threading.Thread):
def run(self):
global ser
ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)
while True:
print(ser.readline().decode('utf-8'))
class KeyboardThread(threading.Thread):
def run(self):
def on_press(key):
try:
format(key.char)
if key.char == "1":
ser.write(b'1\r\n') #serial write - 1
elif key.char == "2":
ser.write(b'2\r\n') #serial write - 2
elif key.char == "3":
ser.write(b'3\r\n') #serial write - 3
elif key.char == "4":
ser.write(b'4\r\n') #serial write - 4
elif key.char == "5":
ser.write(b'5\r\n') #serial write - 5
elif key.char == "6":
ser.write(b'6\r\n') #serial write - 6
elif key.char == "0":
ser.write(b'0\r\n') #serial write - 0
except AttributeError:
format(key)
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
listener = keyboard.Listener(on_press=on_press)
listener.start()
serial_thread = SerialReaderThread()
keyboard_thread = KeyboardThread()
serial_thread.start()
keyboard_thread.start()
serial_thread.join()
keyboard_thread.join()
After this I got an idea that I could also write this serial data exactly what I was printing to the .txt file on windows. So I made a new thread called FileWriting and decided to just write ser.readline().decode('utf-8') to it, however it doesn't work anymore... This is the newly modified code which I wrote to write to the .txt file.
from pynput import keyboard
import threading
import serial
import sys
import io
ser = None
class SerialReaderThread(threading.Thread):
def run(self):
global ser
ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)
while True:
print(ser.readline().decode('utf-8'))
class FileWriting(threading.Thread):
def run(self):
while True:
with io.open("output.txt", "a", encoding="utf-8") as f:
f.write(ser.readline().decode('utf-8'))
class KeyboardThread(threading.Thread):
def run(self):
def on_press(key):
try:
format(key.char)
if key.char == "1":
ser.write(b'1\r\n') #serial write - 1
elif key.char == "2":
ser.write(b'2\r\n') #serial write - 2
elif key.char == "3":
ser.write(b'3\r\n') #serial write - 3
elif key.char == "4":
ser.write(b'4\r\n') #serial write - 4
elif key.char == "5":
ser.write(b'5\r\n') #serial write - 5
elif key.char == "6":
ser.write(b'6\r\n') #serial write - 6
elif key.char == "0":
ser.write(b'0\r\n') #serial write - 0
except AttributeError:
format(key)
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
listener = keyboard.Listener(on_press=on_press)
listener.start()
serial_thread = SerialReaderThread()
keyboard_thread = KeyboardThread()
file_thread = FileWriting()
serial_thread.start()
keyboard_thread.start()
file_thread.start()
serial_thread.join()
keyboard_thread.join()
file_thread.join()
As it's clear I only added a new thread called file_thread, now as I run the code printing of the serial data works fine as well as the writing data to the Arduino, however, the code doesn't write anything to the .txt file and gives me an error:
Exception in thread Thread-3:
Traceback (most recent call last):
File "C:\Python\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "C:\Users\ultra\Desktop\work\menucode.py", line 32, in run
f.write(ser.readline().decode('utf-8'))
AttributeError: 'NoneType' object has no attribute 'readline'
If anybody had similar problems with Arduino while reading the serial data and writing to the text file, or if anybody knows how to fix this please let me know I am quite desperate at this point and everything is appreciated.
At the top of your file, you declare ser = None. The error message you get indicate that the ser object has not yet been set to a Serial object before the FileWriting thread tries to access it.
A quick way to fix this issue is by doing
ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)
before you start any of the threads.
However, that would probably make the program behave strangely, as you have two competing ser.readline() calls in different threads. This would probably result in roughly half of the Arduino's output data being captured by each of the threads (depending on how pyserial handles multiple requests for the same resource). To avoid this issue, I would recommend letting a single thread interface with the ser object, and having that thread pass data to other threads using a queue.
A simple example of how this data exchange could go:
import queue
import serial
q = queue.Queue()
ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)
class SerialReaderThread(threading.Thread):
def run(self):
while True:
# Read output from ser
output = ser.readline().decode('utf-8')
print(output)
# Add output to queue
q.put(output)
class FileWriting(threading.Thread):
def run(self):
while True:
output = q.get() # This will wait until an item is available in the queue
with open("output.txt", "a+") as f:
f.write(output)
f.write("\n") # If you want outputs separated by newlines

How to kill old thread and start new thread?

I'm just start learning about python and I have problem with my project to blink LED. when I get new message and start new thread. The old thread is still running.
I want to kill old thread and start new thread. How to solve my problem?
(Sorry if I'm not good in english but I'm trying)
def led_action(topic,message):
print topic+" "+message
if message == 'OFF':
#state = False
print ("Stoping...")
while message == 'OFF':
GPIO.output(8,GPIO.LOW)
elif message == 'ON':
#state = True
print ("Opening...")
while message == 'ON':
GPIO.output(8,GPIO.HIGH) #Set LED pin 8 to HIGH
time.sleep(1) #Delay 1 second
GPIO.output(8,GPIO.LOW) #Set LED pin 8 to LOW
time.sleep(1)
# Get message form NETPIE and Do something
def subscription(topic,message):
set = thread.start_new_thread(led_action, (topic,message))
def connection():
print "Now I am connected with netpie"
def disconnect():
print "disconnect is work"
microgear.setalias("test")
microgear.on_connect = connection
microgear.on_message = subscription
microgear.on_disconnect = disconnect
microgear.subscribe("/mails")
microgear.connect(True)
To terminate a python thread you need to exit your function. You can do this by removing your while message == 'ON'/'OFF' checks. As message doesn't change anyways (it is passed to the function led_action) those checks are unnecessary.

How to completely restart a python program

For a project, i used a Raspberry Pi (running dexter industries modified raspbian) and Brick Pi to run lego motors. I wroted a program with python and it works great and all, but i need the entire program to run repeatedly if the pressure sensor was not pressed. I tried calling the function sensorValue() (which detects whether the pressure sensor was being pushed) under while True:. But once i did that stuff became weird. It would just continue to repeat indefinitely and even if i pushed the sensor, the recurring 0 would turn to 1 but it wouldn't call the next function i need it to run.
Please help, this is my first time actually using python to write anything and i am a massive beginner so any help is GREATLY APPRECIATED.
Thanks Again
from BrickPi import *
BrickPiSetup()
BrickPi.MotorEnable[PORT_A] = 1
BrickPi.SensorType[PORT_4] = TYPE_SENSOR_TOUCH
BrickPiSetupSensors()
def sensorValue():
result = BrickPiUpdateValues()
if not result :
print BrickPi.Sensor[PORT_4]
time.sleep(.01)
if BrickPi.Sensor[PORT_4] == 0:
def programBody():
print ("program rest/pause")
BrickPi.MotorSpeed[PORT_A] = 0
BrickPiUpdateValues()
time.sleep(3)
print ("reminder/alarm = 200 value")
BrickPi.MotorSpeed[PORT_A] = 200
ot = time.time()
while(time.time() - ot <3):
BrickPiUpdateValues()
time.sleep(.01)
print ("reminder/alarm = 125 value")
BrickPi.MotorSpeed[PORT_A] = 125
ot = time.time()
while(time.time() - ot <3):
BrickPiUpdateValues()
time.sleep(.01)
sensorValue() #I would put while True: here but...
if BrickPi.Sensor[PORT_4]:
print "program successfully initiatied"
programBody()
try this
import BrickPi,time
BrickPiSetup()
BrickPi.MotorEnable[PORT_A] = 1
BrickPi.SensorType[PORT_4] = TYPE_SENSOR_TOUCH
BrickPiSetupSensors()
z = 0
def mainprogram():
print ("running")
while x == 1:
z = z + 1
print ("the plate has been pressed for %s seconds" % z)
time.sleep(1)
while True:
time.sleep(.1)
if BrickPi.Sensor[PORT_4]:
print "program successfully initiatied"
mainprogram()

python multithreaded sniffer- exit from thread

I have created a packet sniffer in python using scapy but kind of stuck in the multithreaded stuff..
def sniffer(ip):
filter_str = "icmp and host " + ip
packets=sniff(filter=filter_str,count=20)
status= False
for p in packets:
packet_load=str(p['Raw'].load)
if packet_load.find("##")!= -1:
status=True
log_thread = Thread(target=logger,args=(packets,))
log_thread.start()
log_thread.join()
break
if status==True:
print "Suspicious Packets sniffed!!"
user_ip = raw_input("Do you want to continue sniffing???(y/n)")
while 1:
if user_ip=="y" or user_ip=="Y":
new_thread = Thread(target=sniffer, args=(ip,))
new_thread.start()
new_thread.join()
else:
#need somthing to quit the program
return
Here, my sniffer sniffs 20 packets at a time and waits for user input for further sniffing.
However if the user enters 'n' as input, then the program hangs. Ideally I would want the program to quit if the user enters 'n'. Can I know what I'm doing wrong here??
while 1 is rarely a good choice when writing a finite loop. Try using flags instead:
leaving = False
while not leaving:
user_ip = raw_input("Do you want to continue sniffing???(y/n)")
if user_ip.lower() == 'y':
new_thread = Thread(target=sniffer, args=(ip,))
new_thread.start()
new_thread.join()
elif user_ip.lower() == 'n':
print "Leaving sniffer"
leaving = True
return

Categories