Hi I wrote a ROS Node in python which imports pyaudio for processing audio. I am using virtulenv with all python modules installed. I can run my Node in Pycharm however when i use rosrun mic_pkg mic_app.py. I'm getting following error
AttributeError: 'module' object has no attribute 'PyAudio'
Here is my node to run.
#!/usr/bin/env python
import pyaudio
import numpy as np
import struct
import rospy
from std_msgs.msg import Float64
class AudioInterface:
def __init__ (self):
self.NSAMPLES = 92000
self.CHUNK = 1024 * 4
self.FORMAT = 8
self.CHANNELS = 1
self.RATE = 92000 # Hz or 152000, 192000 max
self.RECORD_SECONDS = 3
self.FRAMES = []
self.interface = pyaudio.PyAudio ()
self.stream = self.interface.open (format=self.FORMAT,
channels=self.CHANNELS, rate=self.RATE, input=True,
frames_per_buffer=self.CHUNK)
self.stream.start_stream ()
self.set_device_index ()
def __del__ (self):
self.stream.stop_stream ()
self.interface.terminate ()
def set_device_index (self):
for i in range (self.interface.get_device_count ()):
devinfo = self.interface.get_device_info_by_index (i)
print ('Device %{}: %{}'.format (i, devinfo['name']))
for keyword in ['mic', 'input']:
if keyword in devinfo['name'].lower ():
print ('Found an input: device {} - {}'.format (i, devinfo['name']))
self.device_index = i
def get_chunks (self):
for i in range (0, int (self.RATE / self.CHUNK * self.RECORD_SECONDS)):
data = np.frombuffer (self.stream.read (self.CHUNK), dtype=np.int16)
data = data / 1000
self.FRAMES.append (data)
return self.FRAMES
def get_audio_block (self):
data = np.frombuffer (self.stream.read (self.RATE), dtype=np.int16)
data = data / 1000
return data
class AudioProcessing:
#staticmethod
def calc_fft (array):
fftdata = np.abs (np.fft.rfft (array))
return fftdata
#staticmethod
def calc_rms (array):
rms = np.sqrt (np.mean (array ** 2))
return rms
#staticmethod
def calc_mean (array):
result = np.mean (array)
return result
#staticmethod
def normalize (array):
buff = []
min_value = min (array)
max_value = max (array)
for x in array:
y = (x - min_value) / (max_value - min_value)
buff.append (y)
return buff
#staticmethod
def zeros (array):
for n in range (0, 38000):
array[n] = 0
for k in range (42000, len (array)):
array[k] = 0
return array
LEAK_TRIGGER = 0.25
is_leaking = False
trigger = False
if __name__ == "__main__":
mic = AudioInterface ()
is_leaking = False
rospy.init_node ('microphone_node', anonymous=False)
pub = rospy.Publisher ('mic_data', Float64, queue_size=10)
rate = rospy.Rate (10)
while not rospy.is_shutdown ():
audio = mic.get_audio_block ()
audio_freq = AudioProcessing.calc_fft (audio)
audio_normalized = AudioProcessing.normalize (audio)
fft_normalized = AudioProcessing.normalize (audio_freq)
fft_normalized = AudioProcessing.zeros (fft_normalized)
max_val = max (fft_normalized)
hello_str = "hello world %s" % rospy.get_time ()
pub.publish (max_val)
rospy.loginfo (max_val)
rate.sleep ()
I can't tell whether this is not finding package issue or maybe some problem with pyaudio module itself. How do I import python modules (like pyaudio) to ROS Node Please help. Thanks!
Edit i do catkin_make each time i make some changes to the code and it passes with no errors.
Related
I'm trying to build a PID controller on Python. Below is so far my implementation. Although the syntax is coherent, this is still pseudocode.
def PID(self, Kp, Ki, Kd, reference_velocity, vehicle_velocity, current_time, last_update_time):
desired_velocity = 0
Kp = 0
Ki = 0
Kd = 0
error = reference_velocity - vehicle_velocity
delta_time = current_time - last_update_time
proportional = Kp * error
integral = Ki * error
derivative = Kd * ((error - last_error) / (delta_time))
desired_velocity = proportional + integral + derivative
return desired_velocity
I am trying to figure out the last_error through what I already have given here but I couldn't figure it out.
Store the errors or the last error in a container in the function's outer scope.
errors = []
def PID(...):
...
errors.append(error)
return desired_velocity
Then in the function that last error can be retrieved with.
...
last_error = errors[-1]
Or you could make your controller a class whose instances are initialized with constants and starting parameters, and keeps records (a container like a list) of past errors. The calculation for the current/next output control signal would be a method that could be called with current parameter values.
Using your algorithm - something like this.
class PID:
def __init__(self,setpoint,t_now,Kp=0,Ki=0,Kd=0):
self.setpoint = setpoint
self.t_last = t_now
self.Kp = Kp
self.Ki = Ki
self.Kd = Kd
self.last_error = 0
def adjust(self,process,t_now):
error = process - self.setpoint
delta_time = t_now - self.t_last
proportional = self.Kp * error
integral = self.Ki * error
derivative = self.Kd * ((error - self.last_error) / (delta_time))
desired_process = proportional + integral + derivative
self.t_last = t_now
self.last_error = error
return desired_process
Usage:
v_controller = PID(setpoint=66, t_now=0, Kp=.2, Kd=.1, Ki=1)
# or
#parameters = {'setpoint':66, 't_now':0, 'Kp':.2, 'Kd':.1, 'Ki':1}
#v_controller = PID(**parameters)
print(v_controller.adjust(66.1,1))
print(v_controller.adjust(66.2,2))
print(v_controller.adjust(65.9,3))
print('-------------')
parameters = {'setpoint':66, 't_now':0, 'Kp':.2, 'Kd':.1, 'Ki':1.5}
v_controller = PID(**parameters)
print(v_controller.adjust(66.1,1))
print(v_controller.adjust(66.2,2))
print(v_controller.adjust(65.9,3))
print('-------------')
parameters = {'setpoint':66, 't_now':0, 'Kp':1.25, 'Kd':.2, 'Ki':.5}
v_controller = PID(**parameters)
print(v_controller.adjust(66.1,1))
print(v_controller.adjust(66.2,2))
print(v_controller.adjust(65.9,3))
Result
>>>
0.12999999999999262
0.2500000000000043
-0.1499999999999929
-------------
0.17999999999998975
0.3500000000000057
-0.19999999999999005
-------------
0.1949999999999889
0.37000000000000666
-0.2349999999999895
>>>
I have a code for a VoiceActivityDetector and want to give out the value speech_ratio which is in a function
I tried to set up a new function to print out the value
def __init__(self, wave_input_filename):
self._read_wav(wave_input_filename)._convert_to_mono()
self.sample_window = 0.02 #20 ms
self.sample_overlap = 0.01 #10ms
self.speech_window = 0.5 #half a second
self.speech_energy_threshold = 0.6 #60% of energy in voice band
self.speech_start_band = 300
self.speech_end_band = 3000
#self.speech_ratio = 0
def detect_speech(self):
""" Detects speech regions based on ratio between speech band energy
and total energy.
Output is array of window numbers and speech flags (1 - speech, 0 - nonspeech).
"""
detected_windows = np.array([])
sample_window = int(self.rate * self.sample_window)
sample_overlap = int(self.rate * self.sample_overlap)
data = self.data
sample_start = 0
start_band = self.speech_start_band
end_band = self.speech_end_band
while (sample_start < (len(data) - sample_window)):
sample_end = sample_start + sample_window
if sample_end>=len(data): sample_end = len(data)-1
data_window = data[sample_start:sample_end]
energy_freq = self._calculate_normalized_energy(data_window)
sum_voice_energy = self._sum_energy_in_band(energy_freq, start_band, end_band)
sum_full_energy = sum(energy_freq.values())
speech_ratio = sum_voice_energy/sum_full_energy
#self.speech_ratio2 = speech_ratio
# Hipothesis is that when there is a speech sequence we have ratio of energies more than Threshold
speech_ratio = speech_ratio>self.speech_energy_threshold
detected_windows = np.append(detected_windows,[sample_start, speech_ratio])
sample_start += sample_overlap
detected_windows = detected_windows.reshape(int(len(detected_windows)/2),2)
detected_windows[:,1] = self._smooth_speech_detection(detected_windows)
return detected_windows
def printing(self):
print(self.speech_ratio)
return self.speech_ratio
When I set speech_ratio as a variable in the init it does not change the variable later on in the detect_speech function.
If I do not initialize speech_ratio in the init function it wont be a attribute of my object at all.
You use self.speech_ratio to try and print the value; you should use the same expression to assign to it.
I show you below an example of code using pycuda with "kernel" code included in itself (with SourceModule)
import pycuda
import pycuda.driver as cuda
from pycuda.compiler import SourceModule
import threading
import numpy
class GPUThread(threading.Thread):
def __init__(self, number, some_array):
threading.Thread.__init__(self)
self.number = number
self.some_array = some_array
def run(self):
self.dev = cuda.Device(self.number)
self.ctx = self.dev.make_context()
self.array_gpu = cuda.mem_alloc(some_array.nbytes)
cuda.memcpy_htod(self.array_gpu, some_array)
test_kernel(self.array_gpu)
print "successful exit from thread %d" % self.number
self.ctx.pop()
del self.array_gpu
del self.ctx
def test_kernel(input_array_gpu):
mod = SourceModule("""
__global__ void f(float * out, float * in)
{
int idx = threadIdx.x;
out[idx] = in[idx] + 6;
}
""")
func = mod.get_function("f")
output_array = numpy.zeros((1,512))
output_array_gpu = cuda.mem_alloc(output_array.nbytes)
func(output_array_gpu,
input_array_gpu,
block=(512,1,1))
cuda.memcpy_dtoh(output_array, output_array_gpu)
return output_array
cuda.init()
some_array = numpy.ones((1,512), dtype=numpy.float32)
num = cuda.Device.count()
gpu_thread_list = []
for i in range(num):
gpu_thread = GPUThread(i, some_array)
gpu_thread.start()
gpu_thread_list.append(gpu_thread)
I would like to use the same method but instead of using a "kernel code", I would like to do multiple calls of a function which is external (not a function like "kernel code"), i.e a classical function defined in my main program and which takes in argument different parameters shared by all the main program. Is it possible ?
People who have practiced Matlab may know the function arrayfun where B = arrayfun(func,A) is a vector of results given by applying function funcfor each element of vector A.
Actually, it is a version of what is commonly called the map function: I would like to do the same but with GPU/pycuda version.
Update 1
Sorry, I forgot from the beginning of my post to say what I call an extern and classical function. Here is below an example of function which is used in main section :
def integ(I1):
function_A = aux_fun_LU(way, ecs, I1[0], I1[1])
integrale_A = 0.25*delta_x*delta_y*np.sum(function_A[0:-1, 0:-1] + function_A[1:, 0:-1] + function_A[0:-1, 1:] + function_A[1:, 1:])
def g():
for j in range(6*i, 6*i+6):
for l in range(j, 6*i+6):
yield j, l
## applied integ function to g() generator.
## Here I a using simple map function (no parallelization)
if __name__ == '__main__':
map(integ, g())
Update 2
Maybe a solution would be to call the extern function from a kernel code, benefiting as well of the high GPU power of multiple calls on kernel code. But how to deal with the returned value of this extern function to get it back into main program?
Update 3
Here is below what I have tried:
# Class GPUThread
class GPUThread(threading.Thread):
def __init__(self, number, some_array):
threading.Thread.__init__(self)
self.number = number
self.some_array = some_array
def run(self):
self.dev = cuda.Device(self.number)
self.ctx = self.dev.make_context()
self.array_gpu = cuda.mem_alloc(some_array.nbytes)
cuda.memcpy_htod(self.array_gpu, some_array)
test_kernel(self.array_gpu)
print "successful exit from thread %d" % self.number
self.ctx.pop()
del self.array_gpu
del self.ctx
def test_kernel(input_array_gpu):
mod1 = SourceModule("""
__device__ void integ1(int *I1)
{
function_A = aux_fun_LU(way, ecs, I1[0], I1[1]);
integrale_A = 0.25*delta_x*delta_y*np.sum(function_A[0:-1, 0:-1] + function_A[1:, 0:-1] + function_A[0:-1, 1:] + function_A[1:, 1:]);
}""")
func1 = mod1.get_function("integ1")
# Calling function
func1(input_array_gpu)
# Define couples (i,j) to build Fisher matrix
def g1():
for j in range(6*i, 6*i+6):
for l in range(j, 6*i+6):
yield j, l
# Cuda init
if __name__ == '__main__':
cuda.init()
# Input gTotal lists
some_array1 = np.array(list(g1()))
print 'some_array1 = ', some_array1
# Parameters for cuda
num = cuda.Device.count()
gpu_thread_list = []
for i in range(num):
gpu_thread = GPUThread(i, some_array1)
#gpu_thread = GPUThread(i, eval("some_array"+str(j)))
gpu_thread.start()
gpu_thread_list.append(gpu_thread)
I get the following error at the execution:
`Traceback (most recent call last):
File "/Users/mike/anaconda2/envs/py2cuda/lib/python2.7/threading.py", line 801, in __bootstrap_inner
self.run()
File "Example_GPU.py", line 1232, in run
self.array_gpu = cuda.mem_alloc(some_array.nbytes)
NameError: global name 'some_array' is not defined`
I can't see what's wrong with the variable 'some_array' and the line
self.array_gpu = cuda.mem_alloc(some_array.nbytes)
What can I try next?
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()
I encountered this error when running a testbench, together with a synchronizer built on two existing D-FFs.
File "/home/runner/design.py", line 28, in Sync
#always_seq(clk.posedge, reset=reset)
File "/usr/share/myhdl-0.8/lib/python/myhdl/_always_seq.py", line 76, in _always_seq_decorator
raise AlwaysSeqError(_error.ArgType)
myhdl.AlwaysError: decorated object should be a classic (non-generator) function
My testbench is outlined as follows
from myhdl import *
from random import randrange
HALF_PERIOD = delay(10) ### This makes a 20-ns clock signal
ACTIVE_HIGH = 1
G_DELAY = delay(15)
def Main():
### Signal declaration
clk, d, dout = [Signal(intbv(0)) for i in range(3)]
reset = ResetSignal(1,active=ACTIVE_HIGH,async=True)
### Module Instantiation
S1 = Sync(dout, d, clk,reset)
### Clk generator
#always(HALF_PERIOD)
def ClkGen():
clk.next = not clk
### TB def
#instance
def Driver():
yield(HALF_PERIOD)
reset.next = 0
for i in range(4):
yield(G_DELAY)
d.next = not d
raise StopSimulation
return ClkGen, Driver, S1
m1 = traceSignals(Main)
sim = Simulation(m1)
sim.run()
And my synchronizer is coded as follows.
from myhdl import *
from DFF import *
def Sync(dout,din,clk,reset):
""" The module consists of two FFs with one internal signal
External signals
dout : output
din : input
clk : input
Internal signal:
F2F : output-to-input signal that connects two FFs together
"""
### Connectivity
F2F = Signal(intbv(0))
F1 = DFF(F2F,din,clk,reset)
F2 = DFF(dout,F2F,clk,reset)
### Function
#always_seq(clk.posedge,reset=reset)
def SyncLogic():
if reset:
F2F.next = 0
dout.next = 0
else:
F2F.next = din
yield(WIRE_DELAY)
dout.next = F2F
return SyncLogic
and the FF prototype is coded as follows.
from myhdl import *
def DFF(dout,din,clk,reset):
#always_seq(clk.posedge, reset=reset)
def Flogic():
if reset:
dout.next = 0
else:
dout.next = din
return Flogic
The testbench did work with the similar testbench I coded earlier(with slight modification), but it didn't work when combining two modules together. Please clarify. Thank you.
To model a wire delay, use the "delay" argument in the Signal.
change
#always_seq(clk.posedge,reset=reset)
def SyncLogic():
if reset:
F2F.next = 0
dout.next = 0
else:
F2F.next = din
yield(WIRE_DELAY)
dout.next = F2F
return SyncLogic
to:
dout = Signal(<type>, delay=WIRE_DELAY)
# ...
#always_seq(clk.posedge, reset=reset)
def synclogic():
dout.next = din
With the "always_seq" don't define the reset (it is automatically added). If you want to explicitly define the reset use "#always(clock.posedge, reset.negedge)".