reSpeaker XVF3800 上の ROS2
はじめに

このプロジェクトでは、音声検出と到来方向 (DOA) 推定に焦点を当てながら、ReSpeaker XVF3800 を ROS2 と統合してロボットアプリケーションに利用する方法を示します。Turtlesim ノードを使用して音声入力に基づくロボット制御をシミュレートし、PID 制御による精密な動作を実現します。本チュートリアルでは、ROS2 環境のセットアップ、ReSpeaker XVF3800 の設定、およびロボット制御に音声コマンドを適用する方法を取り上げます。最後まで進めることで、音声インターフェースをロボティクスに接続し、ナビゲーションのための基本的な制御アルゴリズムを使用する方法を理解できます。

ホストコンピュータへの ROS 2 のインストール方法
このプロジェクトでは、ミドルウェアとして ROS 2 Humble を使用します。ROS 2 を初めてインストールする場合は、公式インストールガイドに従って詳細な手順を確認してください。
ROS 2 Humble インストールガイド (Ubuntu)
ReSpeaker USB Mic Array のセットアップ
ロボットや音声アプリケーションに ReSpeaker USB Mic Array を使用する場合は、Ubuntu システム上で次の手順に従って設定してください。
デバイスの Vendor ID と Product ID を確認する
デバイスの ID を確認するには、次を実行します。
lsusb
ReSpeaker デバイス(例: vendor 0x2886, product 0x001A)を探します。
デバイス用の udev ルールを作成する
ReSpeaker Mic Array に適切なパーミッションを付与するため、新しい udev ルールを作成します。
sudo nano /etc/udev/rules.d/50-respeaker.rules
ファイルに次の行を追加します。
# ReSpeaker USB Mic Array
SUBSYSTEM=="usb", ATTR{idVendor}=="2886", ATTR{idProduct}=="0018", MODE="0666", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="2886", ATTR{idProduct}=="001a", MODE="0666", GROUP="plugdev"
udev ルールを再読み込みしてサービスを再起動する
変更を反映させるために、udev ルールを再読み込みし、サービスを再起動します。
sudo udevadm control --reload-rules
sudo udevadm trigger
sudo service udev restart
新しいルールを適用するために、ReSpeaker USB Mic Array を一度抜き差ししてください。
ROS2 ワークスペースのセットアップと ROS2 によるロボット制御
このガイドでは、ROS2 ワークスペースのセットアップ、カスタム ROS2 パッケージの作成、Python を用いたロボット制御、そして ROS2 プロジェクトで使用するための ReSpeaker USB Mic Array の設定手順を順を追って説明します。
必要な依存関係のインストール
Python Colcon 拡張機能のインストール
まず、ROS2 パッケージをビルドするために必要な Python 拡張機能がインストールされていることを確認します。
sudo apt install python3-colcon-common-extensions
Colcon の自動補完を設定する(オプション)
colcon の自動補完を設定する必要がある場合は、次を実行します。
cd /usr/share/colcon_argcomplete/hook/
ls
gedit ~/.bashrc
clear
その後、環境を再読み込みするために source ~/.bashrc を追加します。
source ~/.bashrc
ROS2 ワークスペースを作成する
新しい ROS2 ワークスペースを作成し、環境を準備します。
mkdir ros2_ws
cd ros2_ws/
mkdir src
colcon build
ROS2 ワークスペースを source する
ワークスペースをビルドしたら、環境変数を設定するために source します。
source ~/ros2_ws/install/setup.bash
新しいターミナルを開くたびに自動的にワークスペースを source するには、この行を ~/.bashrc に追加できます。
echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc
source ~/.bashrc
新しい ROS2 パッケージを作成する
それでは、ロボットコントローラ用の新しい ROS2 パッケージを作成しましょう。このパッケージはビルドに ament_python を使用し、依存関係として rclpy を利用します。
cd ~/ros2_ws/src
ros2 pkg create my_robot_controller --build-type ament_python --dependencies rclpy
ロボット制御用の Python スクリプトを追加する
新しく作成したパッケージに移動し、ロボットを制御するための Python スクリプト(例: rotate_doa.py)を作成します。
cd my_robot_controller/
touch rotate_doa.py
chmod +x rotate_doa.py
VS Code などのエディタを使用して、任意の制御ロジックでスクリプトを編集します。
cd ..
code .
rotate_doa.py
import sys
import struct
import usb.core
import usb.util
import time
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
from turtlesim.msg import Pose
from std_msgs.msg import Float32
import math
# name, resid, cmdid, length, type
PARAMETERS = {
"VERSION": (48, 0, 4, "ro", "uint8"),
"AEC_AZIMUTH_VALUES": (33, 75, 16 + 1, "ro", "radians"),
"DOA_VALUE": (20, 18, 4 + 1, "ro", "uint16"),
}
class ReSpeaker:
TIMEOUT = 100000
def __init__(self, dev):
self.dev = dev
def write(self, name, value):
pass
def read(self, name):
try:
data = PARAMETERS[name]
except KeyError:
return
resid = data[0]
cmdid = 0x80 | data[1]
length = data[2]
response = self.dev.ctrl_transfer(
usb.util.CTRL_IN | usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE,
0, cmdid, resid, length, self.TIMEOUT)
if data[4] == 'uint8':
result = response.tolist()
elif data[4] == 'radians':
byte_data = response.tobytes()
float1, float2, float3, float4 = struct.unpack('<ffff', byte_data[1:17])
result = [float1 * 180 / 3.1415926,
float2 * 180 / 3.1415926,
float3 * 180 / 3.1415926,
float4 * 180 / 3.1415926]
elif data[4] == 'uint16':
result = response.tolist()
return result
def close(self):
"""
close the interface
"""
usb.util.dispose_resources(self.dev)
def find(vid=0x2886, pid=0x001A):
dev = usb.core.find(idVendor=vid, idProduct=pid)
if not dev:
return None
return ReSpeaker(dev)
class AngleController(Node):
def __init__(self):
super().__init__('angle_controller')
self.target_angle = 0.0
self.pose_sub = self.create_subscription(Pose, '/turtle1/pose', self.pose_callback, 10)
self.cmd_pub = self.create_publisher(Twist, '/turtle1/cmd_vel', 10)
# PID params
self.kp = 1.5
self.ki = 0.0
self.kd = 0.2
self.integral = 0.0
self.prev_error = 0.0
self.prev_time = self.get_clock().now()
def publish_angle(self, angle_deg: float):
self.target_angle = math.radians(angle_deg) # Convert to radians
self.get_logger().info(f"New target angle: {angle_deg:.2f}°")
def pose_callback(self, msg: Pose):
current_yaw = msg.theta
error = self.normalize_angle(self.target_angle - current_yaw)
now = self.get_clock().now()
dt = (now - self.prev_time).nanoseconds / 1e9
self.prev_time = now
self.integral += error * dt
derivative = (error - self.prev_error) / dt if dt > 0 else 0.0
control = self.kp * error + self.ki * self.integral + self.kd * derivative
twist = Twist()
twist.angular.z = control
self.cmd_pub.publish(twist)
self.prev_error = error
@staticmethod
def normalize_angle(angle):
while angle > math.pi:
angle -= 2.0 * math.pi
while angle < -math.pi:
angle += 2.0 * math.pi
return angle
def main(args=None):
rclpy.init(args=args)
node = AngleController()
# Setup ReSpeaker device
dev = find()
if not dev:
node.get_logger().error("No ReSpeaker device found")
return
# Function to handle publishing DOA angle when speech is detected
def publish_doa_angle():
result = dev.read("DOA_VALUE")
if result:
speech_detected = result[3]
doa_angle = result[1]
if speech_detected: # If speech is detected
node.publish_angle(doa_angle)
node.get_logger().info(f"Speech detected, DOA angle: {doa_angle}°")
# Timer to check for DOA updates every 1 second
timer = node.create_timer(1.0, publish_doa_angle)
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
dev.close()
if __name__ == '__main__':
main()
これらの依存関係を package.xml に追加します
<depend>rclpy</depend>
<depend>geometry_msgs</depend>
<depend>turtlesim</depend>
<depend>std_msgs</depend>
このエンドポイントを package.xml に追加します
entry_points={
'console_scripts': [
'rotate_doa = my_controller.rotate_doa:main',
],
},
パッケージをビルドして実行する
Python スクリプトを編集したら、パッケージをビルドします。
colcon build
source ~/ros2_ws/install/setup.bash
最後に、次のコマンドでパッケージを実行します。
ros2 run my_robot_controller rotate_doa
別のターミナルでは、基本的な ROS2 ノード(テスト用に turtlesim など)を実行することもできます。
ros2 run turtlesim turtlesim_node
技術サポートと製品ディスカッション
弊社製品をお選びいただきありがとうございます。私たちは、製品をできるだけスムーズにご利用いただけるよう、さまざまなサポートを提供しています。お好みやニーズに応じてお選びいただける複数のコミュニケーションチャネルをご用意しています。