respeaker_node.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Author: furushchev <furushchev@jsk.imi.i.u-tokyo.ac.jp>
4 
5 from respeaker_ros import *
6 
7 
8 class RespeakerNode(object):
9  def __init__(self):
10  rospy.on_shutdown(self.on_shutdown)
11  self.update_rate = rospy.get_param("~update_rate", 10.0)
12  self.sensor_frame_id = rospy.get_param("~sensor_frame_id", "respeaker_base")
13  self.doa_xy_offset = rospy.get_param("~doa_xy_offset", 0.0)
14  self.doa_yaw_offset = rospy.get_param("~doa_yaw_offset", 90.0)
15  self.speech_prefetch = rospy.get_param("~speech_prefetch", 0.5)
16  self.speech_continuation = rospy.get_param("~speech_continuation", 0.5)
17  self.speech_max_duration = rospy.get_param("~speech_max_duration", 7.0)
18  self.speech_min_duration = rospy.get_param("~speech_min_duration", 0.1)
19  suppress_pyaudio_error = rospy.get_param("~suppress_pyaudio_error", True)
20  #
23  self.is_speeching = False
24  self.speech_stopped = rospy.Time(0)
25  self.prev_is_voice = None
26  self.prev_doa = None
27  # advertise
28  self.pub_vad = rospy.Publisher("is_speeching", Bool, queue_size=1, latch=True)
29  self.pub_doa_raw = rospy.Publisher("sound_direction", Int32, queue_size=1, latch=True)
30  self.pub_doa = rospy.Publisher("sound_localization", PoseStamped, queue_size=1, latch=True)
31  self.pub_audio = rospy.Publisher("audio", AudioData, queue_size=10)
32  self.pub_speech_audio = rospy.Publisher("speech_audio", AudioData, queue_size=10)
33  # init config
34  self.config = None
35  self.dyn_srv = Server(RespeakerConfig, self.on_config)
36  # start
37  self.respeaker_audio = RespeakerAudio(self.on_audio, suppress_error=suppress_pyaudio_error)
39  self.speech_prefetch * self.respeaker_audio.rate * self.respeaker_audio.bitdepth / 8.0)
41  self.respeaker_audio.start()
42  self.info_timer = rospy.Timer(rospy.Duration(1.0 / self.update_rate),
43  self.on_timer)
44  self.timer_led = None
45  self.sub_led = rospy.Subscriber("status_led", ColorRGBA, self.on_status_led)
46 
47  def on_shutdown(self):
48  self.info_timer.shutdown()
49  try:
50  self.respeaker.close()
51  except:
52  pass
53  finally:
54  self.respeaker = None
55  try:
56  self.respeaker_audio.stop()
57  except:
58  pass
59  finally:
60  self.respeaker_audio = None
61 
62  def on_config(self, config, level):
63  if self.config is None:
64  # first get value from device and set them as ros parameters
65  for name in config.keys():
66  config[name] = self.respeaker.read(name)
67  else:
68  # if there is different values, write them to device
69  for name, value in config.items():
70  prev_val = self.config[name]
71  if prev_val != value:
72  self.respeaker.write(name, value)
73  self.config = config
74  return config
75 
76  def on_status_led(self, msg):
77  self.respeaker.set_led_color(r=msg.r, g=msg.g, b=msg.b, a=msg.a)
78  if self.timer_led and self.timer_led.is_alive():
79  self.timer_led.shutdown()
80  self.timer_led = rospy.Timer(rospy.Duration(3.0),
81  lambda e: self.respeaker.set_led_trace(),
82  oneshot=True)
83 
84  def on_audio(self, data):
85  self.pub_audio.publish(AudioData(data=data))
86  if self.is_speeching:
87  if len(self.speech_audio_buffer) == 0:
89  self.speech_audio_buffer += data
90  else:
91  self.speech_prefetch_buffer += data
93 
94  def on_timer(self, event):
95  stamp = event.current_real or rospy.Time.now()
96  is_voice = self.respeaker.is_voice()
97  doa_rad = math.radians(self.respeaker.direction - 180.0)
99  doa_rad, math.radians(self.doa_yaw_offset))
100  doa = int(math.degrees(doa_rad))
101 
102  # vad
103  if is_voice != self.prev_is_voice:
104  self.pub_vad.publish(Bool(data=is_voice))
105  self.prev_is_voice = is_voice
106 
107  # doa
108  if doa != self.prev_doa:
109  self.pub_doa_raw.publish(Int32(data=doa))
110  self.prev_doa = doa
111 
112  msg = PoseStamped()
113  msg.header.frame_id = self.sensor_frame_id
114  msg.header.stamp = stamp
115  ori = T.quaternion_from_euler(math.radians(doa), 0, 0)
116  msg.pose.position.x = self.doa_xy_offset * np.cos(doa_rad)
117  msg.pose.position.y = self.doa_xy_offset * np.sin(doa_rad)
118  msg.pose.orientation.w = ori[0]
119  msg.pose.orientation.x = ori[1]
120  msg.pose.orientation.y = ori[2]
121  msg.pose.orientation.z = ori[3]
122  self.pub_doa.publish(msg)
123 
124  # speech audio
125  if is_voice:
126  self.speech_stopped = stamp
127  if stamp - self.speech_stopped < rospy.Duration(self.speech_continuation):
128  self.is_speeching = True
129  elif self.is_speeching:
130  buf = self.speech_audio_buffer
131  self.speech_audio_buffer = b""
132  self.is_speeching = False
133  duration = 8.0 * len(buf) * self.respeaker_audio.bitwidth
134  duration = duration / self.respeaker_audio.rate / self.respeaker_audio.bitdepth
135  rospy.loginfo("Speech detected for %.3f seconds" % duration)
136  if self.speech_min_duration <= duration < self.speech_max_duration:
137 
138  self.pub_speech_audio.publish(AudioData(data=buf))
139 
140 
141 if __name__ == '__main__':
142  rospy.init_node("respeaker_node")
144  rospy.spin()
def on_config(self, config, level)
static double shortest_angular_distance(double from, double to)


respeaker_ros
Author(s): Yuki Furuta
autogenerated on Sat Jun 24 2023 02:40:34