segmentation fault :pyaudio recording in no blocking mode - python

I've been trying to record audio using pyaudio untill silence is met in the input stream .but segmentation fault happens while running it .i don't think anything is wrong with pyaudio/portaudio installed in my raspberry pi because pyaudio works when i tried to run examples in pyaudio docs it works without any issue .i tried to debug it with pdb and
gdb these are the results :
Recording: Setting up
Thread 1 "python" received signal SIGSEGV, Segmentation fault.
0x7652a298 in ?? ()
from /usr/lib/python2.7/dist-packages/_portaudio.arm-linux- gnueabihf.so
(gdb) backtrace
#0 0x7652a298 in ?? ()
from /usr/lib/python2.7/dist-packages/_portaudio.arm-linux- gnueabihf.so
#1 0x764f47b0 in Pa_GetDeviceInfo ()
from /usr/lib/arm-linux-gnueabihf/libportaudio.so.2
#2 0x7effe2c4 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)
pyaudio callback function
def _callback(self, in_data, frame_count, time_info, status): # pylint: disable=unused-argument
debug = logging.getLogger('alexapi').getEffectiveLevel() == logging.DEBUG
if not in_data:
self._queue.put(False)
return None, pyaudio.paAbort
do_VAD = True
if self._callback_data['force_record'] and not self._callback_data['force_record'][1]:
do_VAD = False
# do not count first 10 frames when doing VAD
if do_VAD and (self._callback_data['frames'] < self._callback_data['throwaway_frames']):
self._callback_data['frames'] += 1
# now do VAD
elif (self._callback_data['force_record'] and self._callback_data['force_record'][0]()) \
or (do_VAD and (self._callback_data['thresholdSilenceMet'] is False)
and ((time.time() - self._callback_data['start']) < self.MAX_RECORDING_LENGTH)):
if do_VAD:
if int(len(in_data) / 2) == self.VAD_PERIOD:
isSpeech = self._vad.is_speech(in_data, self.VAD_SAMPLERATE)
if not isSpeech:
self._callback_data['silenceRun'] += 1
else:
self._callback_data['silenceRun'] = 0
self._callback_data['numSilenceRuns'] += 1
# only count silence runs after the first one
# (allow user to speak for total of max recording length if they haven't said anything yet)
if (self._callback_data['numSilenceRuns'] != 0) \
and ((self._callback_data['silenceRun'] * self.VAD_FRAME_MS) > self.VAD_SILENCE_TIMEOUT):
self._callback_data['thresholdSilenceMet'] = True
else:
self._queue.put(False)
return None, pyaudio.paComplete
self._queue.put(in_data)
if debug:
self._callback_data['audio'] += in_data
return None, pyaudio.paContinue
pyaudio
def _callback(self, in_data, frame_count, time_info, status): # pylint: disable=unused-argument
debug = logging.getLogger('alexapi').getEffectiveLevel() == logging.DEBUG
if not in_data:
self._queue.put(False)
return None, pyaudio.paAbort
do_VAD = True
if self._callback_data['force_record'] and not self._callback_data['force_record'][1]:
do_VAD = False
# do not count first 10 frames when doing VAD
if do_VAD and (self._callback_data['frames'] < self._callback_data['throwaway_frames']):
self._callback_data['frames'] += 1
# now do VAD
elif (self._callback_data['force_record'] and self._callback_data['force_record'][0]()) \
or (do_VAD and (self._callback_data['thresholdSilenceMet'] is False)
and ((time.time() - self._callback_data['start']) < self.MAX_RECORDING_LENGTH)):
if do_VAD:
if int(len(in_data) / 2) == self.VAD_PERIOD:
isSpeech = self._vad.is_speech(in_data, self.VAD_SAMPLERATE)
if not isSpeech:
self._callback_data['silenceRun'] += 1
else:
self._callback_data['silenceRun'] = 0
self._callback_data['numSilenceRuns'] += 1
# only count silence runs after the first one
# (allow user to speak for total of max recording length if they haven't said anything yet)
if (self._callback_data['numSilenceRuns'] != 0) \
and ((self._callback_data['silenceRun'] * self.VAD_FRAME_MS) > self.VAD_SILENCE_TIMEOUT):
self._callback_data['thresholdSilenceMet'] = True
else:
self._queue.put(False)
return None, pyaudio.paComplete
self._queue.put(in_data)
if debug:
self._callback_data['audio'] += in_data
return None, pyaudio.paContinue
These are actually adaptation of the code that i found somewhere on the internet.i double checked my device index and sample rate there is nothing wrong with them
can someone help me sort it out ?
complete code is here
pdb result
> /usr/lib/python2.7/dist-packages/pyaudio.py(438)__init__()
-> arguments['stream_callback'] = stream_callback
(Pdb) step
> /usr/lib/python2.7/dist-packages/pyaudio.py(441)__init__()
-> self._stream = pa.open(**arguments)
(Pdb) step
Segmentation fault
root#raspberrypi:/home/pi/Desktop# python -m pdb rp3test.py

Idk may it's just a bug in pyaudio and everylibs that uses pyaudio such as python sounddevice . cause i tried it with sounddevice library . Finally made it work with this code
def silence_listener(throwaway_frames,filename = "recording.wav"):
# Reenable reading microphone raw data
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, alsa_card)
inp.setchannels(1)
inp.setrate(VAD_SAMPLERATE)
inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
inp.setperiodsize(VAD_PERIOD)
audio = ""
# Buffer as long as we haven't heard enough silence or the total size is within max size
thresholdSilenceMet = False
frames = 0
numSilenceRuns = 0
silenceRun = 0
start = time.time()
# do not count first 10 frames when doing VAD
while (frames < throwaway_frames): # VAD_THROWAWAY_FRAMES):
l, data = inp.read()
frames = frames + 1
if l:
audio += data
isSpeech = vad.is_speech(data, VAD_SAMPLERATE)
# now do VAD
while (thresholdSilenceMet == False) and ((time.time() - start) < MAX_RECORDING_LENGTH):
l, data = inp.read()
if l:
audio += data
if (l == VAD_PERIOD):
isSpeech = vad.is_speech(data, VAD_SAMPLERATE)
if (isSpeech == False):
silenceRun = silenceRun + 1
#print "0"
else:
silenceRun = 0
numSilenceRuns = numSilenceRuns + 1
#print "1"
# only count silence runs after the first one
# (allow user to speak for total of max recording length if they haven't said anything yet)
if (numSilenceRuns != 0) and ((silenceRun * VAD_FRAME_MS) > VAD_SILENCE_TIMEOUT):
thresholdSilenceMet = True
if debug: print ("End recording")
rf = open(filename, 'w')
rf.write(audio)
rf.close()
inp.close()
return

Related

Sending and receiving a signal at the same time

I’m working in python on a raspberry pi. I’m trying to send out a signal on a motor controller, and then receive a signal with a sensing hat after it pass through my plant (an RC filter in this case).
The important thing is I want to generate the output and read the input as close to simultaneously as possible. I was hoping to use multiprocessing to have a thread send the signal while the other read the incoming signal. But I keep getting confused on how threads work in python.
In short is it possible to do 2 different tasks with multiprocessing and then repeat those tasks (sending and reading a signal) until a condition is met. (like in a while loop)
(Edited with Code)
from __future__ import print_function
from PyQt5.QtWidgets import QAction
from pyqtgraph.Qt import QtGui, QtCore
from adafruit_motorkit import MotorKit
import pyqtgraph as pg
import sys
from sys import stdout
import numpy as np
from daqhats import mcc118, OptionFlags, HatIDs, HatError
from daqhats_utils import select_hat_device, enum_mask_to_string, \
chan_list_to_mask
from decimal import *
import math
import time
getcontext().prec = 3
total_samples_read = 0
READ_ALL_AVAILABLE = -1
channelData = np.zeros(4, dtype=float)
CURSOR_BACK_2 = '\x1b[2D'
ERASE_TO_END_OF_LINE = '\x1b[0K'
# for plotting data
########################################
scan_rate = 1000 # scan rate in hz
maxtime = 30 # second s to run for
Datatime = np.zeros(maxtime * scan_rate, dtype=float)#List of times when smaples are taken
Data1 = np.zeros(maxtime * scan_rate, dtype=float) #sampels taken
data_index = 0 # Maximum index of data points taken
dt = Decimal(1 / scan_rate) # difference in time between indexes of Datatime
display_index = 0 # maximum index of Data being displayed on plot
#################################
# variables for Data logger
##########################
is_scanning = False
channels = [0]
channel_mask = chan_list_to_mask(channels)
num_channels = len(channels)
samples_per_channel = 0
options = OptionFlags.CONTINUOUS
######################################
startedTime = 0 # time at program start
myTime = 0 # time since program started
try:
address = select_hat_device(HatIDs.MCC_118)
hat = mcc118(address)
except (HatError, ValueError) as err:
print('\n', err)
class MainWindow(pg.GraphicsWindow):
def __init__(self, *args, **kwargs):
super(pg.GraphicsWindow, self).__init__(*args, **kwargs)
self.delay = 30 #ms
self.quit = QAction("Quit", self)
self.quit.triggered.connect(self.clean_close)
self.timer = QtCore.QTimer()
self.timer.setInterval(self.delay)
self.timer.timeout.connect(self.update_plot)
# plots data and runs calibrate between trials
def update_plot(self):
global display_index, Datatime, Data1
kit.motor1.throttle = .4 + .2 * math.cos((time.time()-startedTime)* 2 * np.pi* 1) # 1hz sinusiod out of motor
if data_index < len(Data1):
Collect_Data()
plot.setXRange(0, 20, padding=0)
plot.setXRange(0, 20, padding=0)
curve.setData(Datatime[:display_index], Data1[:display_index])
display_index += 1
app.processEvents()
def clean_close(self):
self.close()
# starts data collection
def Collect_Data():
global is_scanning
"""
This function is executed automatically when the module is run directly.
"""
# Store the channels in a list and convert the list to a channel mask that
# can be passed as a parameter to the MCC 118 functions.
try:
# Select an MCC 118 HAT device to use.
# actual_scan_rate = hat.a_in_scan_actual_rate(num_channels, scan_rate)
# Configure and start the scan.
# Since the continuous option is being used, the samples_per_channel
# parameter is ignored if the value is less than the default internal
# buffer size (10000 * num_channels in this case). If a larger internal
# buffer size is desired, set the value of this parameter accordingly.
if not is_scanning:
hat.a_in_scan_start(channel_mask, samples_per_channel, scan_rate,
options)
is_scanning = True
try:
read_and_display_data(hat, num_channels)
except KeyboardInterrupt:
# Clear the '^C' from the display.
print(CURSOR_BACK_2, ERASE_TO_END_OF_LINE, '\n')
print('Stopping')
hat.a_in_scan_stop()
hat.a_in_scan_cleanup()
except (HatError, ValueError) as err:
print('\n', err)
# reads Data off of Hat and adds to Data1
def read_and_display_data(hat, num_channels):
global channelData, data_index, Datatime, Data1
total_samples_read = 0
read_request_size = READ_ALL_AVAILABLE
# When doing a continuous scan, the timeout value will be ignored in the
# call to a_in_scan_read because we will be requesting that all available
# samples (up to the default buffer size) be returned.
timeout = 5.0
# Read all of the available samples (up to the size of the read_buffer which
# is specified by the user_buffer_size). Since the read_request_size is set
# to -1 (READ_ALL_AVAILABLE), this function returns immediately with
# whatever samples are available (up to user_buffer_size) and the timeout
# parameter is ignored.
trigger = True
while trigger == True:
read_result = hat.a_in_scan_read(read_request_size, timeout)
# Check for an overrun error
if read_result.hardware_overrun:
print('\n\nHardware overrun\n')
break
elif read_result.buffer_overrun:
print('\n\nBuffer overrun\n')
break
samples_read_per_channel = int(len(read_result.data) / num_channels)
total_samples_read += samples_read_per_channel
# adds all data in buffer to data to be plotted.
count = 0
if samples_read_per_channel > 0:
index = samples_read_per_channel * num_channels - num_channels
while count < samples_read_per_channel:
for i in range(num_channels):
channelData[i] = read_result.data[index + i]
if data_index < len(Data1):
Data1[data_index] = channelData[0]
Datatime[data_index] = float(dt * Decimal(data_index))
data_index += 1
count += 1
trigger = False
stdout.flush()
if __name__ == '__main__':
app = QtGui.QApplication([])
win = MainWindow() # display window
plot = win.addPlot(1, 0)
curve = plot.plot()
win.show()
kit = MotorKit() # implements motor driver
kit.motor1.throttle = .4 # values 1 is 5v and 0 is 0 volts
startedTime = time.time()
# u = .2*math.cos(t * 2*np.pi*1)
win.timer.start()
sys.exit(app.exec_())

VIDIOC_QBUF: Invalid argument V4l2 MEMORY USERPTR python implementation

I am trying to work with user-pointer v4l2 driver.
Currently I am working with the v4l2 MMAP and its working fine, but I want to change it to user pointer because of reading performance.
Working example (with mmap):
def init_mmap(self, width=8192, height=256):
req = v4l2_requestbuffers()
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
req.memory = V4L2_MEMORY_MMAP # V4L2_MEMORY_MMAP V4L2_MEMORY_USERPTR
req.count = 1 # number of buffer frames
self.height = max(self.height, 32)
# get device capabilities
cp = v4l2_capability()
fcntl.ioctl(self.vid.fileno(), VIDIOC_QUERYCAP, cp)
# Configure v4l2 format
fmt = v4l2_format()
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
fmt.fmt.pix.width = self.width # 8192
fmt.fmt.pix.height = self.height # 256
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RG12
fmt.fmt.pix.field = V4L2_FIELD_NONE
fmt.fmt.pix.bytesperline = 0
fcntl.ioctl(self.vid.fileno(), VIDIOC_S_FMT, fmt)
# init mmap capture
fcntl.ioctl(self.vid.fileno(), VIDIOC_REQBUFS, req) # tell the driver that we want some buffers
for ind in range(self.req.count):
print(f"allocate MMAP buffer {ind}")
buf = v4l2_buffer()
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
buf.memory = V4L2_MEMORY_MMAP
buf.index = ind
buf.reserved = 0
buf.flags = 0
# queue the buffer for capture
ret = fcntl.ioctl(self.vid.fileno(), VIDIOC_QBUF, buf) # return 0 on success.
if ret != 0:
print("Could not allocate buffers!")
return -1
fcntl.ioctl(self.vid.fileno(), VIDIOC_QUERYBUF, buf)
return 0
What I am trying to achieve (userptr):
def init_userptr(self, width=8192, height=256, buffer=None):
req = v4l2_requestbuffers()
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
req.memory = V4L2_MEMORY_USERPTR # V4L2_MEMORY_MMAP V4L2_MEMORY_USERPTR
req.count = 1 # number of buffer frames
self.height = max(self.height, 32)
# get device capabilities
cp = v4l2_capability()
fcntl.ioctl(self.vid.fileno(), VIDIOC_QUERYCAP, cp)
# Configure v4l2 format
fmt = v4l2_format()
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
fmt.fmt.pix.width = self.width # 8192
fmt.fmt.pix.height = self.height # 256
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RG12
fmt.fmt.pix.field = V4L2_FIELD_NONE
fmt.fmt.pix.bytesperline = 0
fcntl.ioctl(self.vid.fileno(), VIDIOC_S_FMT, fmt)
# init mmap capture
fcntl.ioctl(self.vid.fileno(), VIDIOC_REQBUFS, req) # tell the driver that we want some buffers
for ind in range(self.req.count):
print(f"allocate USERPTR buffer {ind}")
buf = v4l2_buffer()
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
buf.memory = V4L2_MEMORY_USERPTR
buf.index = ind
buf.m.userptr = ctypes.c_ulong(ctypes.addressof(buffer[ind])) # Tried id(buffer) as well and few more similar options
buf.length = len(buffer) # ctypes.c_uint32(len(buffer))
# queue the buffer for capture
ret = fcntl.ioctl(self.vid.fileno(), VIDIOC_QBUF, buf) # ## FAILS HERE ## #
if ret != 0:
print("Could not allocate buffers!")
return -1
fcntl.ioctl(self.vid.fileno(), VIDIOC_QUERYBUF, buf)
return 0
The buffer in the section above was allocated as so:
arr = ctypes.ARRAY(ctypes.ARRAY(ctypes.c_float, 4194304), 3)
buffer = arr()
The code fails at the line ret = fcntl.ioctl(self.vid.fileno(), VIDIOC_QBUF, buf) with the error:
"OSError: [Errno 22] Invalid argument"
After doing some reading I came across this:
"The buffer type is not supported, or the index is out of bounds, or no buffers have been allocated yet, or the userptr or length are invalid."
Which was not so helpful.
I have found some C implementations of user-pointer v4l2 readings, but I could not make it work on my python code.
I have tried to allocate buffers with ctypes, and bytearray, but got the same result every time.
Relevant info:
C Implementation -
https://gist.github.com/maxlapshin/1253534
videodev2.h -
https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L1114
ioctl VIDIOC_QBUF, VIDIOC_DQBUF - https://www.kernel.org/doc/html/v4.15/media/uapi/v4l/vidioc-qbuf.html
EDIT:
Ok so after some more reading I managed to make
ret = fcntl.ioctl(self.vid.fileno(), VIDIOC_QBUF, buf) to work by changing the way I am allocating the buffers.
The buffer allocation:
b_address = ctypes.c_void_p()
buf.length = fmt.fmt.pix.width * fmt.fmt.pix.height * 2
posix_memalign(ctypes.byref(b_address), getpagesize(), buf.length)
buf.m.userptr = b_address.value
buf.type = self.req.type
buf.memory = self.req.memory
ret = fcntl.ioctl(self.vid.fileno(), VIDIOC_QBUF, buf) # this line is now working!
I used this post as reference - user pointer in python
Now I am facing a new issue with select(). It reaches time out and then hangs on VIDIOC_DQBUF when I try to read frame.
Example:
def get_frame(self):
dbuf = v4l2_buffer()
dbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
dbuf.memory = V4L2_MEMORY_USERPTR # V4L2_MEMORY_MMAP
# wait till buffer is ready for reading
t0 = time.time()
max_t = 5
ready_to_read, ready_to_write, in_error = ([], [], [])
while len(ready_to_read) == 0 and time.time() - t0 < max_t:
ready_to_read, ready_to_write, in_error = select.select([self.vid.fileno()], [], [], max_t) # Reaches time out here
# read (de-queue) buffer
ret = fcntl.ioctl(self.vid.fileno(), VIDIOC_DQBUF, dbuf) # Hangs here.
I understand that this issue is related to buffers size or maybe incorrect allocations, but really I cant point my finger on a specific thing.
Any help will be much appreciated!
Thank you all in advance!

Python real time plotting

I have a problem... I've already tried some ways but it didn;t work. I have to do a real time data aquisition and plotting them in an interface... If you can suggest me a way to do that... The program below makes one data aquisition in variable "data"(matrix), but I have to do it continuously and plotting them the same time... Thank you!
# Print library info:
print_library_info()
# Search for devices:
libtiepie.device_list.update()
# Try to open an oscilloscope with block measurement support:
scp = None
for item in libtiepie.device_list:
if item.can_open(libtiepie.DEVICETYPE_OSCILLOSCOPE):
scp = item.open_oscilloscope()
if scp.measure_modes & libtiepie.MM_BLOCK:
break
else:
scp = None
if scp:
try:
fig = plt.figure()
ax = fig.add_subplot(111)
k=0
while k<20:
# Set measure mode:
scp.measure_mode = libtiepie.MM_BLOCK
# Set sample frequency:
scp.sample_frequency = 5e6 # 1 MHz
# Set record length:
scp.record_length = 1000 # 15000 samples
# Set pre sample ratio:
scp.pre_sample_ratio = 0 # 0 %
# For all channels:
for ch in scp.channels:
# Enable channel to measure it:
ch.enabled = True
# Set range:
ch.range = 8 # 8 V
# Set coupling:
ch.coupling = libtiepie.CK_ACV # DC Volt
# Set trigger timeout:
scp.trigger_time_out = 100e-3 # 100 ms
# Disable all channel trigger sources:
for ch in scp.channels:
ch.trigger.enabled = False
# Setup channel trigger:
ch = scp.channels[0] # Ch 1
# Enable trigger source:
ch.trigger.enabled = True
# Kind:
ch.trigger.kind = libtiepie.TK_RISINGEDGE # Rising edge
# Level:
ch.trigger.levels[0] = 0.5 # 50 %
# Hysteresis:
ch.trigger.hystereses[0] = 0.05 # 5 %
# Print oscilloscope info:
#print_device_info(scp)
# Start measurement:
scp.start()
# Wait for measurement to complete:
while not scp.is_data_ready:
time.sleep(0.01) # 10 ms delay, to save CPU time
# Get data:
data = scp.get_data()
except Exception as e:
print('Exception: ' + e.message)
sys.exit(1)
# Close oscilloscope:
del scp
else:
print('No oscilloscope available with block measurement support!')
sys.exit(1)
What about something like this (I assumed you were plotting your data against time):
import joystick as jk
import time
class test(jk.Joystick):
_infinite_loop = jk.deco_infinite_loop()
_callit = jk.deco_callit()
#_callit('before', 'init')
def _init_data(self, *args, **kwargs):
self.t = np.array([])
self.data = np.array([])
# do the hardware initialization here
#.............
self.range = 8
self.record_length = 1000
#_callit('after', 'init')
def _build_frames(self, *args, **kwargs):
self.mygraph = self.add_frame(
Graph(name="Graph", size=(500, 500),
pos=(50, 50), fmt="go-", xnpts=self.record_length,
freq_up=10, bgcol="w", xylim=(0,10,0,self.range)))
#_callit('before', 'start')
def _set_t0(self):
# initialize t0 at start-up
self._t0 = time.time()
#_infinite_loop(wait_time=0.2)
def _get_data(self):
self.t = self.mygraph.add_datapoint(self.t, time.time())
# new data acquisition here
new_data = scp.get_data()
self.data = self.graph.add_datapoint(self.data, new_data)
self.mygraph.set_xydata(self.t-self._t0, self.data)
and to start the reading/plotting:
t = test()
t.start()

Brookstone rover 2.0 Python program to control from computer isn't working

I have a python program that controls a Brookstone Rover 2.0 from a computer through openCV and pygame and I've been working on this for 7 hours now and it has been nothing but errors after errors and this is what it's showing me now
PS C:\users\sessi\desktop> C:\Users\sessi\Desktop\rover\ps3rover20.py
Traceback (most recent call last):
File "C:\Users\sessi\Desktop\rover\ps3rover20.py", line 168, in <module>
rover = PS3Rover()
File "C:\Users\sessi\Desktop\rover\ps3rover20.py", line 58, in __init__
Rover20.__init__(self)
File "C:\Program Files\Python 3.5\lib\site-packages\roverpylot-0.1-py3.5.egg\rover\__init__.py", line 182, in __init__
Rover.__init__(self)
File "C:\Program Files\Python 3.5\lib\site-packages\roverpylot-0.1-py3.5.egg\rover\__init__.py", line 47, in __init__
self._sendCommandIntRequest(0, [0, 0, 0, 0])
File "C:\Program Files\Python 3.5\lib\site-packages\roverpylot-0.1-py3.5.egg\rover\__init__.py", line 149, in _sendCommandIntRequest
bytevals.append(ord(c))
TypeError: ord() expected string of length 1, but int found
These are the two files that it's getting errors from
ps3rover20.py
#!/usr/bin/env python
'''
ps3rover20.py Drive the Brookstone Rover 2.0 via the P3 Controller, displaying
the streaming video using OpenCV.
Copyright (C) 2014 Simon D. Levy
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
'''
# You may want to adjust these buttons for your own controller
BUTTON_LIGHTS = 3 # Square button toggles lights
BUTTON_STEALTH = 1 # Circle button toggles stealth mode
BUTTON_CAMERA_UP = 0 # Triangle button raises camera
BUTTON_CAMERA_DOWN = 2 # X button lowers camera
# Avoid button bounce by enforcing lag between button events
MIN_BUTTON_LAG_SEC = 0.5
# Avoid close-to-zero values on axis
MIN_AXIS_ABSVAL = 0.01
from rover import Rover20
import time
import pygame
import sys
import signal
# Supports CTRL-C to override threads
def _signal_handler(signal, frame):
frame.f_locals['rover'].close()
sys.exit(0)
# Try to start OpenCV for video
try:
import cv
except:
cv = None
# Rover subclass for PS3 + OpenCV
class PS3Rover(Rover20):
def __init__(self):
# Set up basics
Rover20.__init__(self)
self.wname = 'Rover 2.0: Hit ESC to quit'
self.quit = False
# Set up controller using PyGame
pygame.display.init()
pygame.joystick.init()
self.controller = pygame.joystick.Joystick(0)
self.controller.init()
# Defaults on startup: lights off, ordinary camera
self.lightsAreOn = False
self.stealthIsOn = False
# Tracks button-press times for debouncing
self.lastButtonTime = 0
# Try to create OpenCV named window
try:
if cv:
cv.NamedWindow(self.wname, cv.CV_WINDOW_AUTOSIZE )
else:
pass
except:
pass
self.pcmfile = open('rover20.pcm', 'w')
# Automagically called by Rover class
def processAudio(self, pcmsamples, timestamp_10msec):
for samp in pcmsamples:
self.pcmfile.write('%d\n' % samp)
# Automagically called by Rover class
def processVideo(self, jpegbytes, timestamp_10msec):
# Update controller events
pygame.event.pump()
# Toggle lights
self.lightsAreOn = self.checkButton(self.lightsAreOn, BUTTON_LIGHTS, self.turnLightsOn, self.turnLightsOff)
# Toggle night vision (infrared camera)
self.stealthIsOn = self.checkButton(self.stealthIsOn, BUTTON_STEALTH, self.turnStealthOn, self.turnStealthOff)
# Move camera up/down
if self.controller.get_button(BUTTON_CAMERA_UP):
self.moveCameraVertical(1)
elif self.controller.get_button(BUTTON_CAMERA_DOWN):
self.moveCameraVertical(-1)
else:
self.moveCameraVertical(0)
# Set treads based on axes
self.setTreads(self.axis(1), self.axis(3))
# Display video image if possible
try:
if cv:
# Save image to file on disk and load as OpenCV image
fname = 'tmp.jpg'
fd = open(fname, 'w')
fd.write(jpegbytes)
fd.close()
image = cv.LoadImage(fname)
# Show image
cv.ShowImage(self.wname, image )
if cv.WaitKey(1) & 0xFF == 27: # ESC
self.quit = True
else:
pass
except:
pass
# Converts Y coordinate of specified axis to +/-1 or 0
def axis(self, index):
value = -self.controller.get_axis(index)
if value > MIN_AXIS_ABSVAL:
return 1
elif value < -MIN_AXIS_ABSVAL:
return -1
else:
return 0
# Handles button bounce by waiting a specified time between button presses
def checkButton(self, flag, buttonID, onRoutine=None, offRoutine=None):
if self.controller.get_button(buttonID):
if (time.time() - self.lastButtonTime) > MIN_BUTTON_LAG_SEC:
self.lastButtonTime = time.time()
if flag:
if offRoutine:
offRoutine()
flag = False
else:
if onRoutine:
onRoutine()
flag = True
return flag
# main -----------------------------------------------------------------------------------
if __name__ == '__main__':
# Create a PS3 Rover object
rover = PS3Rover()
# Set up signal handler for CTRL-C
signal.signal(signal.SIGINT, _signal_handler)
# Loop until user hits quit button on controller
while not rover.quit:
pass
# Shut down Rover
rover.close()
__ init__.py
'''
Python classes for interacting with the Brookstone Rover 2.0
and Rover Revolution
Copyright (C) 2015 Simon D. Levy
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
'''
import struct
import threading
import socket
import time
from blowfish import Blowfish
from adpcm import decodeADPCMToPCM
from byteutils import *
class Rover:
def __init__(self):
''' Creates a Rover object that you can communicate with.
'''
self.HOST = '192.168.1.100'
self.PORT = 80
TARGET_ID = 'AC13'
TARGET_PASSWORD = 'AC13'
self.TREAD_DELAY_SEC = 1.0
self.KEEPALIVE_PERIOD_SEC = 60
# Create command socket connection to Rover
self.commandsock = self._newSocket()
# Send login request with four arbitrary numbers
self._sendCommandIntRequest(0, [0, 0, 0, 0])
# Get login reply
reply = self._receiveCommandReply(82)
# Extract Blowfish key from camera ID in reply
cameraID = reply[25:37].decode('utf-8')
key = TARGET_ID + ':' + cameraID + '-save-private:' + TARGET_PASSWORD
# Extract Blowfish inputs from rest of reply
L1 = bytes_to_int(reply, 66)
R1 = bytes_to_int(reply, 70)
L2 = bytes_to_int(reply, 74)
R2 = bytes_to_int(reply, 78)
# Make Blowfish cipher from key
bf = _RoverBlowfish(key)
# Encrypt inputs from reply
L1,R1 = bf.encrypt(L1, R1)
L2,R2 = bf.encrypt(L2, R2)
# Send encrypted reply to Rover
self._sendCommandIntRequest(2, [L1, R1, L2, R2])
# Ignore reply from Rover
self._receiveCommandReply(26)
# Start timer task for keep-alive message every 60 seconds
self._startKeepaliveTask()
# Set up vertical camera controller
self.cameraVertical = _RoverCamera(self, 1)
# Send video-start request
self._sendCommandIntRequest(4, [1])
# Get reply from Rover
reply = self._receiveCommandReply(29)
# Create media socket connection to Rover
self.mediasock = self._newSocket()
# Send video-start request based on last four bytes of reply
self._sendRequest(self.mediasock, 'V', 0, 4, map(ord, reply[25:]))
# Send audio-start request
self._sendCommandByteRequest(8, [1])
# Ignore audio-start reply
self._receiveCommandReply(25)
# Receive images on another thread until closed
self.is_active = True
self.reader_thread = _MediaThread(self)
self.reader_thread.start()
def close(self):
''' Closes off commuincation with Rover.
'''
self.keepalive_timer.cancel()
self.is_active = False
self.commandsock.close()
if self.mediasock:
self.mediasock.close()
def turnStealthOn(self):
''' Turns on stealth mode (infrared).
'''
self._sendCameraRequest(94)
def turnStealthOff(self):
''' Turns off stealth mode (infrared).
'''
self._sendCameraRequest(95)
def moveCameraVertical(self, where):
''' Moves the camera up or down, or stops moving it. A nonzero value for the
where parameter causes the camera to move up (+) or down (-). A
zero value stops the camera from moving.
'''
self.cameraVertical.move(where)
def _startKeepaliveTask(self,):
self._sendCommandByteRequest(255)
self.keepalive_timer = \
threading.Timer(self.KEEPALIVE_PERIOD_SEC, self._startKeepaliveTask, [])
self.keepalive_timer.start()
def _sendCommandByteRequest(self, id, bytes=[]):
self._sendCommandRequest(id, len(bytes), bytes)
def _sendCommandIntRequest(self, id, intvals):
bytevals = []
for val in intvals:
for c in struct.pack('I', val):
bytevals.append(ord(c))
self._sendCommandRequest(id, 4*len(intvals), bytevals)
def _sendCommandRequest(self, id, n, contents):
self._sendRequest(self.commandsock, 'O', id, n, contents)
def _sendRequest(self, sock, c, id, n, contents):
bytes = [ord('M'), ord('O'), ord('_'), ord(c), id, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, n, 0, 0, 0, 0, 0, 0, 0]
bytes.extend(contents)
request = ''.join(map(chr, bytes))
sock.send(request)
def _receiveCommandReply(self, count):
reply = self.commandsock.recv(count)
return reply
def _newSocket(self):
sock = socket.socket()
sock.connect((self.HOST, self.PORT))
return sock
def _sendDeviceControlRequest(self, a, b) :
self._sendCommandByteRequest(250, [a,b])
def _sendCameraRequest(self, request):
self._sendCommandByteRequest(14, [request])
class Rover20(Rover):
def __init__(self):
Rover.__init__(self)
# Set up treads
self.leftTread = _RoverTread(self, 4)
self.rightTread = _RoverTread(self, 1)
def close(self):
''' Closes off commuincation with Rover.
'''
Rover.close(self)
# Stop moving treads
self.setTreads(0, 0)
def getBatteryPercentage(self):
''' Returns percentage of battery remaining.
'''
self._sendCommandByteRequest(251)
reply = self._receiveCommandReply(32)
return 15 * ord(reply[23])
def setTreads(self, left, right):
''' Sets the speed of the left and right treads (wheels). + = forward;
- = backward; 0 = stop. Values should be in [-1..+1].
'''
currTime = time.time()
self.leftTread.update(left)
self.rightTread.update(right)
def turnLightsOn(self):
''' Turns the headlights and taillights on.
'''
self._setLights(8)
def turnLightsOff(self):
''' Turns the headlights and taillights off.
'''
self._setLights(9)
def _setLights(self, onoff):
self._sendDeviceControlRequest(onoff, 0)
def processVideo(self, jpegbytes, timestamp_10msec):
''' Proccesses bytes from a JPEG image streamed from Rover.
Default method is a no-op; subclass and override to do something
interesting.
'''
pass
def processAudio(self, pcmsamples, timestamp_10msec):
''' Proccesses a block of 320 PCM audio samples streamed from Rover.
Audio is sampled at 8192 Hz and quantized to +/- 2^15.
Default method is a no-op; subclass and override to do something
interesting.
'''
pass
def _spinWheels(self, wheeldir, speed):
# 1: Right, forward
# 2: Right, backward
# 4: Left, forward
# 5: Left, backward
self._sendDeviceControlRequest(wheeldir, speed)
class Revolution(Rover):
def __init__(self):
Rover.__init__(self)
self.steerdir_prev = 0
self.command_prev = 0
self.goslow_prev = 0
self.using_turret = False
# Set up vertical camera controller
self.cameraHorizontal = _RoverCamera(self, 5)
def drive(self, wheeldir, steerdir, goslow):
goslow = 1 if goslow else 0
command = 0
if wheeldir == +1 and steerdir == 0:
command = 1
if wheeldir == -1 and steerdir == 0:
command = 2
if wheeldir == 0 and steerdir == +1:
command = 4
if wheeldir == 0 and steerdir == -1:
command = 5
if wheeldir == +1 and steerdir == -1:
command = 6
if wheeldir == +1 and steerdir == +1:
command = 7
if wheeldir == -1 and steerdir == -1:
command = 8
if wheeldir == -1 and steerdir == +1:
command = 9
if steerdir == 0 and self.steerdir_prev != 0:
command = 3
if command != self.command_prev or goslow != self.goslow_prev:
self._sendDeviceControlRequest(command, goslow)
self.steerdir_prev = steerdir
self.command_prev = command
self.goslow_prev = goslow
def processVideo(self, imgbytes, timestamp_msec):
''' Proccesses bytes from an image streamed from Rover.
Default method is a no-op; subclass and override to do something
interesting.
'''
pass
def processAudio(self, audiobytes, timestamp_msec):
''' Proccesses a block of 1024 PCM audio samples streamed from Rover.
Audio is sampled at 8192 Hz and quantized to +/- 2^15.
Default method is a no-op; subclass and override to do something
interesting.
'''
pass
def useTurretCamera(self):
''' Switches to turret camera.
'''
self._sendUseCameraRequest(1)
def useDrivingCamera(self):
''' Switches to driving camera.
'''
self._sendUseCameraRequest(2)
def moveCameraHorizontal(self, where):
''' Moves the camera up or down, or stops moving it. A nonzero value for the
where parameter causes the camera to move up (+) or down (-). A
zero value stops the camera from moving.
'''
self.cameraHorizontal.move(where)
def _sendUseCameraRequest(self, camera):
self._sendCommandByteRequest(19, [6, camera])
# "Private" classes ===========================================================
# A special Blowfish variant with P-arrays set to zero instead of digits of Pi
class _RoverBlowfish(Blowfish):
def __init__(self, key):
ORIG_P = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
self._keygen(key, ORIG_P)
# A thread for reading streaming media from the Rover
class _MediaThread(threading.Thread):
def __init__(self, rover):
threading.Thread.__init__(self)
self.rover = rover
self.BUFSIZE = 1024
def run(self):
# Accumulates media bytes
mediabytes = ''
# Starts True; set to False by Rover.close()
while self.rover.is_active:
# Grab bytes from rover, halting on failure
try:
buf = self.rover.mediasock.recv(self.BUFSIZE)
except:
break
# Do we have a media frame start?
k = buf.find('MO_V')
# Yes
if k >= 0:
# Already have media bytes?
if len(mediabytes) > 0:
# Yes: add to media bytes up through start of new
mediabytes += buf[0:k]
# Both video and audio messages are time-stamped in 10msec units
timestamp = bytes_to_uint(mediabytes, 23)
# Video bytes: call processing routine
if ord(mediabytes[4]) == 1:
self.rover.processVideo(mediabytes[36:], timestamp)
# Audio bytes: call processing routine
else:
audsize = bytes_to_uint(mediabytes, 36)
sampend = 40 + audsize
offset = bytes_to_short(mediabytes, sampend)
index = ord(mediabytes[sampend+2])
pcmsamples = decodeADPCMToPCM(mediabytes[40:sampend], offset, index)
self.rover.processAudio(pcmsamples, timestamp)
# Start over with new bytes
mediabytes = buf[k:]
# No media bytes yet: start with new bytes
else:
mediabytes = buf[k:]
# No: accumulate media bytes
else:
mediabytes += buf
class _RoverTread(object):
def __init__(self, rover, index):
self.rover = rover
self.index = index
self.isMoving = False
self.startTime = 0
def update(self, value):
if value == 0:
if self.isMoving:
self.rover._spinWheels(self.index, 0)
self.isMoving = False
else:
if value > 0:
wheel = self.index
else:
wheel = self.index + 1
currTime = time.time()
if (currTime - self.startTime) > self.rover.TREAD_DELAY_SEC:
self.startTime = currTime
self.rover._spinWheels(wheel, int(round(abs(value)*10)))
self.isMoving = True
class _RoverCamera(object):
def __init__(self, rover, stopcmd):
self.rover = rover
self.stopcmd = stopcmd
self.isMoving = False
def move(self, where):
if where == 0:
if self.isMoving:
self.rover._sendCameraRequest(self.stopcmd)
self.isMoving = False
elif not self.isMoving:
if where == 1:
self.rover._sendCameraRequest(self.stopcmd-1)
else:
self.rover._sendCameraRequest(self.stopcmd+1)
self.isMoving = True
I know almost nothing about python by the way.
I'm using windows 10 64 bit
At
https://github.com/simondlevy/RoverPylot
it says:
Tips for Windows
Rob Crawley has put a lot of work into getting RoverPylot to work
smoothly on Windows 10. Here are his changes:
Original: # Create a named temporary file for video stream tmpfile =
tempfile.NamedTemporaryFile()
Changed to: tmpfile = tempfile.NamedTemporaryFile(mode='w+b',
bufsize=0 , suffix='.avi', prefix='RoverRev',
dir='\Python27\RoverRev_WinPylot', delete=False) Original: # Wait a
few seconds, then being playing the tmp video file cmd = 'ffplay
-window_title Rover_Revolution -framerate %d %s' % (FRAMERATE, tmpfile.name)
Changed to: cmd = '/Python27/ffmpeg/bin/ffplay.exe -x 640 -y 480
-window_title Rover_Revolution -framerate %d %s' % (FRAMERATE, tmpfile.name) Your files paths may be different than those listed
below, so make your changes accordingly
Which means that the author uses Python 2.7. From your error reports I gather you use Python 3.5, which treats bytes differently. Install and use 2.7 instead.

pyqt4 QTextEdit won't work in my code because of a loop

I have this code that creates a text edit window :
class Main(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.initUI()
print("just started the ui")
def initUI(self):
print("i am in initUi")
self.text = QtGui.QTextEdit(self)
self.setCentralWidget(self.text)
# x and y coordinates on the screen, width, height
self.setGeometry(100,100,1030,800)
self.setWindowTitle("Writer")
sleep(1)
the write_msg() function is ok and writes text to my terminal as expected. but now i would like to use this function to write inside the QTextEdit. problem is that write_msg() has a while loop inside if i have the while loop the window never pop's up, if i remove the while loop window pops up, the editor is there and i can type from my keyboard anything but my function can not work while it fundamental for it.
Here is my write_msg() function :
def write_msg():
print("i am in write_msg function")
#Each analog sensor has some characters to roll
sensor16=['1','-','\\','/','*','!']
sensor15=['4','G','H','I']
sensor14=['7','P','Q','R','S']
sensor13=['*']
sensor12=['2','A','B','C']
sensor11=['5','J','K','L']
sensor10=['8','T','U','V']
sensor09=['0',' ']
sensor08=['3','D','E','F']
sensor07=['6','M','N','O']
sensor06=['9','W','X','Y','Z']
sensor05=['#']
sensor04=['BACKSPACE']
sensor03=['DELETE ALL']
sensor02=['READ']
sensor01=['TRANSMITE']
sensor=[sensor01,sensor02,sensor03,sensor04,sensor05,sensor06,sensor07,sensor08,sensor09,sensor10,sensor11,sensor12,sensor13,sensor14,sensor15,sensor16]
#the maximum number of times each sensor can be pressed
#before it rols back to the first character.
max_press=[1,1,1,1,1,5,4,4,2,4,4,4,1,5,4,6]
num_press=0
message=[]
steps=0
i=0
x=0
key=0
key_pressed=0
#message_string="kjsdfgaqlkfvbnajkefnvbsfejfhvbjhkefrbvksjehdjefbv"
#print(message_string)
#p1 = subprocess.Popen(["minimodem" , '--tx' , '300'], stdin=subprocess.PIPE)
#p1.stdin.write(bytes(message_string, 'UTF-8'))
while state == "wrt":
print("i am looping")
binary_x="{0:04b}".format(x)
GPIO.output(15, int(binary_x[0]))
GPIO.output(13, int(binary_x[1]))
GPIO.output(11, int(binary_x[2]))
GPIO.output(7, int(binary_x[3]))
# average three readings to get a more stable one
channeldata_1 = read_mcp3002(0) # get CH0 input
sleep(0.001)
channeldata_2 = read_mcp3002(0) # get CH0 input
sleep(0.001)
channeldata_3 = read_mcp3002(0) # get CH0 input
channeldata = (channeldata_1+channeldata_2+channeldata_3)/3
#
# Voltage = (CHX data * (V-ref [= 3300 mV] * 2 [= 1:2 input divider]) / 1024 [= 10bit resolution] #
voltage = int(round(((channeldata * vref * 2) / resolution),0))+ calibration
#print(voltage)
if DEBUG : print("Data (bin) {0:010b}".format(channeldata))
#key_pressed=x
if x==15 : # some problem with this sensor so i had to go and twicked the thresshold
voltage = voltage - 500
#time.sleep(0.05)
if ( voltage > 2500) : #key is released
keypressed = False
keyreleased = True
x=x+1
if ( voltage <= 2500) : #key is pressed
keypressed = True
keyreleased = False
key_pressed=x#define which key is pressed
if key_pressed==0 and key!=0:
transmite(message)
sleep(0.01)
x=x+1
if key_pressed==1:
state == "rd_msg"
x=x+1
if key_pressed==2:
sys.stdout.write('\033[2K')
sys.stdout.write('\033[1G')
message_len = len(message)
for m in range(message_len):
del message[m]
x=x+1
if key_pressed==3:
#print('\b\b')
print('\b ', end="", flush=True)
sys.stdout.write('\010')
message_len = len(message)
del message[message_len]
sleep(1)
x=x+1
if key_pressed > 3:
print("i am pressing a number")
if key == key_pressed :
while num_press <= (max_press[key_pressed]) and keyreleased==False:
# average three readings to get a more stable one
channeldata_1 = read_mcp3002(0) # get CH0 input
sleep(0.001)
channeldata_2 = read_mcp3002(0) # get CH0 input
sleep(0.001)
channeldata_3 = read_mcp3002(0) # get CH0 input
channeldata = (channeldata_1+channeldata_2+channeldata_3)/3
#
# Voltage = (CHX data * (V-ref [= 3300 mV] * 2 [= 1:2 input divider]) / 1024 [= 10bit resolution]
#
voltage = int(round(((channeldata * vref * 2) / resolution),0))+ calibration
if DEBUG : print("Data (bin) {0:010b}".format(channeldata))
if x==15 : # some problem with this sensor so i had to go and twicked the thresshold
voltage = voltage - 500
time.sleep(0.05)
if ( voltage > 2500) : #key is released
keyreleased = True
keypressed = False
sys.stdout.write('\033[1C')
char=sensor[key_pressed][num_press-1]
message.append(char)
self.text.setText(char)
num_press=0
else :
keypressed = True
keyreleased= False
if num_press <= max_press[key_pressed] and keyreleased == False:
print(sensor[key_pressed][num_press], end="", flush=True)
sys.stdout.write('\010')
num_press=num_press+1
time.sleep(0.5)
if num_press == max_press[key_pressed] :
num_press=0
if x == 16 :
x=0
key = key_pressed
I have to continuously change the value of x increasing it from 0 to 16 for this function to work properly. Any one has any idea ?
ok ! i've tried to use threading so i can run my write_msg() function but couldn't get it to work either, if i comment the threading the text editor window pops up normally, like nothing happened, and if i uncomment it it pops out this error message:
pi#raspberrypi:~ $ sudo python3 ./Documents/Examples/texting_app.py
[xcb] Unknown sequence number while processing reply
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python3: ../../src/xcb_io.c:635: _XReply: Assertion `!xcb_xlib_threads_sequence_lost' failed.
this is the code in main() to start everything:
def main():
#t = threading.Thread(target=write_msg)
#t.daemon = True
#t.start()
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())

Categories

Resources