PC から Jetson nano への音声データ送信:ソースコード:robot_speaker_subscriber_function.py

CHUNK_SIZEはもっと小さくてもおそらく平気。

# Copyright 2016 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Copyright 2022 robot-creation-diary.com
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# チュートリアルの内容から、HMDのオイラー角を受け取りそれに合わせて
# サーボモータを制御するように変更してある
# 使用機材:サーボモータ:Miuzei MS18、サーボモータコントローラ:20軸サーボモータコントローラ WR-MSXX

import rclpy
from rclpy.node import Node
from cpp_pubsub.msg import RobotSpeakerMsg
import serial
import copy
import numpy as np
import pyaudio

import matplotlib.pyplot as plt
import time 
CHANNELS = 1
SAMPLE_RATE = 44100
SAMPLE_WIDTH = 2
CHUNK_SIZE = 65536  # バッファーサイズ(2の累乗)

class RobotSpeakerSubscriber(Node):

    def __init__(self):
        super().__init__('robot_speaker_subscriber')
        self.subscription = self.create_subscription(
            RobotSpeakerMsg,
            'robot_speaker_topic',
            self.listener_callback,
            10)

        self.subscription  # prevent unused variable warning
        self.debuf_time=time.time()
        self.pre_debug_count = 0
        # 10のデータをまとめることで平滑化する
        self.buffer_size = 3
        self.audio_data_buffer = [None] * self.buffer_size 
        self.audio_data_read_count = 0
        self.pre_audio_data_read_count = 0
        self.audio_data_write_count = 0
        self.volume = 5
        # PyAudioの初期化
        p = pyaudio.PyAudio()

        # 出力ストリームを開く(スピーカに再生)
        self.output_stream = p.open(format=p.get_format_from_width(SAMPLE_WIDTH),
                               channels=CHANNELS,
                               rate=SAMPLE_RATE,
                               output=True,
                               frames_per_buffer=CHUNK_SIZE)
        print("pyaudio start")
    def __del__(self):
 
        pass

    def listener_callback(self, msg):



        # #audio#########################################
        audio_data = copy.deepcopy(msg.audio_data)
        if self.pre_debug_count == msg.debug_count:
            #self.debuf_time=time.time()
            time.sleep(0.001)            
            return
        if 0 < len(audio_data): 
            self.audio_data_buffer[self.audio_data_write_count] = np.array(audio_data)
            self.audio_data_buffer[self.audio_data_write_count]=\
                np.clip( self.audio_data_buffer[self.audio_data_write_count]*self.volume, -32768, 32786).astype(np.int16)
            wcbuf = (self.audio_data_write_count + 1) % self.buffer_size 
            if wcbuf != self.audio_data_read_count:
                self.audio_data_write_count = wcbuf
 
        if None is not self.audio_data_buffer[self.audio_data_read_count]:
            rcbuf = (self.audio_data_read_count + 1) % self.buffer_size 
            if rcbuf != self.audio_data_write_count:
                self.audio_data_read_count = rcbuf
            if self.pre_audio_data_read_count != self.audio_data_read_count:
                self.output_stream.write(
                    bytes(self.audio_data_buffer[self.audio_data_read_count]))
            self.pre_audio_data_read_count = self.audio_data_read_count
            print("debug_count,", msg.debug_count)
            #self.debug_prot(audio_data)
            print("interval 2",time.time()-self.debuf_time)
            self.debuf_time=time.time()
        #time.sleep(0.03)
        self.pre_debug_count = msg.debug_count
    def debug_prot(self, data):
                # 左右チャンネルに分割
        left_channel = data[::2]  # 偶数番目が左チャンネル
        right_channel = data[1::2]  # 奇数番目が右チャンネル

        # 波形をプロットする(左チャンネル)
        plt.subplot(2, 1, 1)
        plt.plot(left_channel)
        plt.title("Left Channel")
        plt.ylim(-32768, 32767)

        # 波形をプロットする(右チャンネル)
        plt.subplot(2, 1, 2)
        plt.plot(right_channel)
        plt.title("Right Channel")
        plt.ylim(-32768, 32767)
        #print ("right_channel",right_channel)
        # プロットを更新
        plt.pause(0.01)
        plt.clf()

def main(args=None):
    rclpy.init(args=args)

    minimal_subscriber = RobotSpeakerSubscriber()

    rclpy.spin(minimal_subscriber)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_subscriber.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()