检查不同节点不同 IP 地址、同一网络上的文件 - 可能吗?

问题描述

我有一小部分 RaspBerry Pi,都在同一个本地网络 (192.168.1.2xx) 上,都在运行 Python 3.7.3,一个 (R Pi CM3) 在 Raspbian Buster 上,另一个 (R Pi 4B 8gig)在 RaspBerry Pi OS 64 上。

我在一台设备(Pi 4B)上有一个文件,位于 /tmp/speech.wav,它是实时生成的:

192.168.1.201 - /tmp/speech.wav

我有一个在该设备上运行良好的脚本,它告诉我 .wav 文件的播放持续时间(以秒为单位):

import wave
import contextlib

def getPlayTime():
    fname = '/tmp/speech.wav'
    with contextlib.closing(wave.open(fname,'r')) as f:
        frames = f.getnframes()
        rate = f.getframerate()
        duration = round(frames / float(rate),2)
        return duration

但是 - 需要对该持续时间信息进行操作的节点正在 192.168.1.210 的另一个节点上运行。我不能简单地将各种文件全部移动到同一个节点,因为有很多事情发生,事情是有原因的。

所以我需要知道的是如何改变我的方法,以便我可以将脚本引用更改为类似以下伪代码内容

fname = '/tmp/speech.wav @ 192.168.1.201'

这样的事情可能吗?在网上搜索,我似乎遇到了数百万人在寻找如何获取 IP 地址、修复多个 IP 地址问题、修复重复 IP 地址问题……但我似乎还没有找到如何简单地检查文件正如我在此处描述的那样,在不同的 IP 地址上。我没有网络安全限制,所以任何设置都需要考虑。非常感谢您的帮助。

解决方法

有很多可能性,这可能归结为您需要多久检查一次持续时间、从多少个客户端、文件更改的频率以及您是否有其他信息要在节点之间共享。

这里有一些选项:

  • 在具有 WAV 文件的 Pi 上设置一个 SMB(Samba)服务器,并让其他节点挂载文件系统并像访问本地文件一样访问该文件

  • 在具有 WAV 文件的 Pi 上设置 NFS 服务器,让其他节点挂载文件系统并像访问本地文件一样访问该文件

  • 让其他节点使用 ssh 登录并提取持续时间,或使用 scp 检索文件 - 参见 Python 中的 paramiko

  • 在一个节点上设置 Redis 并将 WAV 文件放在那里,以便任何人都可以获取它 - 如果您有很多列表、数组、字符串、整数、哈希,这可能很有吸引力,要在 Raspberry Pi 之间快速共享的队列或集合。示例 here


这是一个非常简单的示例,它从一个节点(假设 Redis 在 192.168.0.200)将音轨写入 Redis,然后从任何其他节点读回。当然,您可能只希望写入节点在其中写入持续时间而不是整个轨道 - 这会更有效率。或者,您可能想要存储大量其他共享数据或设置。

这是作者:

#!/usr/bin/env python3

import redis
from pathlib import Path

host='192.168.1.200'

# Connect to Redis
r = redis.Redis(host)

# Load some music,or otherwise create it
music = Path('song.wav').read_bytes()

# Put music into Redis where others can see it
r.set("music",music)

这是读者:

#!/usr/bin/env python3

import redis
from pathlib import Path

host='192.168.1.200'

# Connect to Redis
r = redis.Redis(host)

# Retrieve music track from Redis
music = r.get("music")
print(f'{len(music)} bytes read from Redis')

然后,在测试期间,您可能希望从终端手动将轨道推送到 Redis:

redis-cli -x -h 192.168.0.200 set  music < OtherTrack.wav

或者手动从 Redis 检索轨道到文件:

redis-cli -h 192.168.0.200 get music > RetrievedFromRedis.wav
,

好的,这就是我最终确定的 - 并且效果很好。使用 ZeroMQ 进行消息传递,我有获取 wav 播放时间的功能,另一个收集有关将要说的语音的数据,然后在发送语音之前将所有数据发送到电机核心。运动核心处理时间问题,使下巴与语音同步。所以,我实际上并没有将生成 wav 的代码并将 wav 播放时间的长度返回到最终使用它的节点上,但事实证明消息传递足够快,所以有足够的时间空间来接收、处理和实施运动控制以完美匹配语音。将其发布在这里,以防它对将来处理类似问题的人们有所帮助。

import time
import zmq
import os
import re
import wave
import contextlib

context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5555")  #Listens for speech to output

print("Connecting to Motor Control")
jawCmd = context.socket(zmq.PUB)
jawCmd.connect("tcp://192.168.1.210:5554") #Sends to MotorFunctions for Jaw Movement

def getPlayTime():  # Checks to see if current file duration has changed
    fname = '/tmp/speech.wav'   # and if yes,sends new duration
    with contextlib.closing(wave.open(fname,'r')) as f:
        frames = f.getnframes()
        rate = f.getframerate()
        duration = round(frames / float(rate),3)
        speakTime = str(duration)
        return speakTime

def set_voice(V,T):
    T2 = '"' + T + '"'
    audioFile = "/tmp/speech.wav"  # /tmp set as tmpfs,or RAMDISK to reduce SD Card write ops

    if V == "A":
        voice = "Allison"
    elif V == "B":
        voice = "Belle"
    elif V == "C":
        voice = "Callie"
    elif V == "D":
        voice = "Dallas"
    elif V == "V":
        voice = "David"
    else:
        voice = "Belle"

    os.system("swift -n " + voice + " -o " + audioFile + " " +T2) # Record audio
    tailTrim = .5                                                 # Calculate Jaw Timing
    speakTime = eval(getPlayTime())                               # Start by getting playlength
    speakTime = round((speakTime - tailTrim),2)                  # Chop .5 s for trailing silence
    wordList = T.split()
    jawString = []
    for index in range(len(wordList)):
        wordLen = len(wordList[index])
        jawString.append(wordLen)
    jawString = str(jawString)
    speakTime = str(speakTime)
    jawString = speakTime + "|" + jawString  # 3.456|[4,2,7,4,9,3,6] - will split on "|"
    jawCmd.send_string(jawString)   # Send Jaw Operating Sequence
    os.system("aplay " + audioFile) # Play audio

pronunciationDict = {'teh':'the','process':'prawcess','Maeve':'Mayve','Mariposa':'May-reeposah','Lila':'Lala','Trump':'Ass hole'}

def adjustResponse(response):     # Adjusts spellings in output string to create better speech output.
    for key,value in pronunciationDict.items():
        if key in response or key.lower() in response:
            response = re.sub(key,value,response,flags=re.I)
    return response

SpeakText="Speech center connected and online."
set_voice(V,SpeakText) # Cepstral  Voices: A = Allison; B = Belle; C = Callie; D = Dallas; V = David;

while True:
    SpeakText = socket.recv().decode('utf-8') # .decode gets rid of the b' in front of the string
    SpeakTextX = adjustResponse(SpeakText)    # Run the string through the pronunciation dictionary
    print("SpeakText = ",SpeakTextX)

    set_voice(V,SpeakTextX)
    print("Received request: %s" % SpeakTextX)
    socket.send_string(str(SpeakTextX))       # Send data back to source for confirmation