Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 音声をON/OFF切り替える設定を追加 #88

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/signage/config/signage_param.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,13 @@ signage:
accept_start: 5.0 # second
monitor_width: 1920
monitor_height: 540
announce:
emergency: true
restart_engage: true
door_close: true
door_open: true
engage: true
thank_you: true
in_emergency: true
going_to_depart: true
going_to_arrive: true
2 changes: 2 additions & 0 deletions src/signage/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
<version>0.1.0</version>
<description>The signage package</description>

<maintainer email="[email protected]">yabuta</maintainer>

Check warning on line 7 in src/signage/package.xml

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (yabuta)

<license>Apache License 2.0</license>
<exec_depend>ament_index_python</exec_depend>
<exec_depend>signage_version</exec_depend>

<depend>autoware_auto_system_msgs</depend>
<depend>python-pulsectl-pip</depend>

Check warning on line 14 in src/signage/package.xml

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (pulsectl)
<depend>rclpy</depend>
<depend>tier4_api_msgs</depend>
<depend>tier4_debug_msgs</depend>
<depend>tier4_external_api_msgs</depend>
<depend>tier4_hmi_msgs</depend>
<depend>diagnostic_updater</depend>

<export>
<build_type>ament_python</build_type>
Expand Down
Binary file removed src/signage/resource/sound/arrived.wav
Binary file not shown.
Binary file added src/signage/resource/sound/restart_engage.wav
Binary file not shown.
Binary file not shown.
Binary file removed src/signage/resource/sound/wait_for_walker.wav
Binary file not shown.
1 change: 1 addition & 0 deletions src/signage/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def package_files(directory):
("share/" + package_name, ["package.xml"]),
("share/" + package_name + "/launch", ["launch/signage.launch.xml"]),
("share/" + package_name + "/config", ["config/signage_param.yaml"]),
("share/" + package_name + "/config", ["config/announce_settings.yaml"]),
],
install_requires=["setuptools"],
zip_safe=True,
Expand Down
45 changes: 45 additions & 0 deletions src/signage/src/signage/announce_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
# -*- coding: utf-8 -*-
# This Python file uses the following encoding: utf-8

import os

from PyQt5.QtMultimedia import QSound
from rclpy.duration import Duration
from ament_index_python.packages import get_package_share_directory

from dataclasses import asdict

# The higher the value, the higher the priority
PRIORITY_DICT = {
"emergency": 3,
Expand All @@ -20,20 +24,35 @@
"going_to_arrive": 1,
}

CURRENT_VOLUME_PATH = "/opt/autoware/volume.txt"


class AnnounceControllerProperty:
def __init__(self, node, autoware_interface, parameter_interface):
super(AnnounceControllerProperty, self).__init__()

self._node = node
self._parameter = parameter_interface.parameter
self._announce_settings = parameter_interface.announce_settings
self._current_announce = ""
self._pending_announce_list = []
self._sound = QSound("")
self._prev_depart_and_arrive_type = ""
self._package_path = get_package_share_directory("signage") + "/resource/sound/"
self._check_playing_timer = self._node.create_timer(1, self.check_playing_callback)

self._pulse = Pulse()
if os.path.isfile(CURRENT_VOLUME_PATH):
with open(CURRENT_VOLUME_PATH, "r") as f:
self._sink = self._pulse.get_sink_by_name(
self._pulse.server_info().default_sink_name
)
self._pulse.volume_set_all_chans(self._sink, float(f.readline()))

Check warning on line 50 in src/signage/src/signage/announce_controller.py

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (chans)

self._get_volume_pub = self._node.create_publisher(Float32, "~/get/volume", 1)
self._node.create_timer(1.0, self.publish_volume_callback)
self._node.create_service(SetVolume, "~/set/volume", self.set_volume)

def process_pending_announce(self):
try:
for play_sound in self._pending_announce_list:
Expand Down Expand Up @@ -62,10 +81,21 @@
self._sound = QSound(self._package_path + message + ".wav")
self._sound.play()

# skip announce by setting
def check_announce_or_not(self, message):
try:
return asdict(self._announce_settings).get(message, False)
except Exception as e:
self._node.get_logger().error("check announce or not: " + str(e))
return False

def send_announce(self, message):
priority = PRIORITY_DICT.get(message, 0)
previous_priority = PRIORITY_DICT.get(self._current_announce, 0)

if not self.check_announce_or_not(message):
return

if priority == 3:
self._sound.stop()
self.play_sound(message)
Expand Down Expand Up @@ -100,3 +130,18 @@
# To stop repeat announcement
self.send_announce(message)
self._prev_depart_and_arrive_type = message

def publish_volume_callback(self):
self._sink = self._pulse.get_sink_by_name(self._pulse.server_info().default_sink_name)
self._get_volume_pub.publish(Float32(data=self._sink.volume.value_flat))

def set_volume(self, request, response):
try:
self._sink = self._pulse.get_sink_by_name(self._pulse.server_info().default_sink_name)
self._pulse.volume_set_all_chans(self._sink, request.volume)

Check warning on line 141 in src/signage/src/signage/announce_controller.py

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (chans)
with open(CURRENT_VOLUME_PATH, "w") as f:
f.write(f"{self._sink.volume.value_flat}\n")
response.status.code = ResponseStatus.SUCCESS
except Exception:
response.status.code = ResponseStatus.ERROR
return response
28 changes: 28 additions & 0 deletions src/signage/src/signage/autoware_diagnostic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020 Tier IV, Inc. All rights reserved.
#
# 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.

# ========================================================================
# This code is used to public the diagnostic to autoware and let autoware
# to decide the hazard level
# ========================================================================

import diagnostic_updater

class AutowareDiagnostic():
def init_updater(self, node, name, update_function, hardware_id):
updater = diagnostic_updater.Updater(node, 1)
updater.setHardwareID(hardware_id)
updater.add(name, update_function)
return updater
19 changes: 17 additions & 2 deletions src/signage/src/signage/autoware_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@

import rclpy
from dataclasses import dataclass
from autoware_adapi_v1_msgs.msg import (

Check warning on line 6 in src/signage/src/signage/autoware_interface.py

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (adapi)
RouteState,
MrmState,
OperationModeState,
MotionState,
LocalizationInitializationState,
VelocityFactorArray,
)
import signage.signage_utils as utils
from tier4_debug_msgs.msg import Float64Stamped
from tier4_external_api_msgs.msg import DoorStatus


@dataclass
class AutowareInformation:
autoware_control: bool = False
Expand All @@ -31,6 +31,7 @@
def __init__(self, node):
self._node = node
self.information = AutowareInformation()
self.is_disconnected = False

sub_qos = rclpy.qos.QoSProfile(
history=rclpy.qos.QoSHistoryPolicy.KEEP_LAST,
Expand Down Expand Up @@ -75,19 +76,28 @@
self._sub_motion_state = node.create_subscription(
MotionState, "/api/motion/state", self.sub_motion_state_callback, api_qos
)
self._sub_localiztion_initializtion_state = node.create_subscription(

Check warning on line 79 in src/signage/src/signage/autoware_interface.py

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (localiztion)

Check warning on line 79 in src/signage/src/signage/autoware_interface.py

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (initializtion)
LocalizationInitializationState,
"/api/localization/initialization_state",
self.sub_localization_initialization_state_callback,
api_qos,
)
self._sub_velocity_factors = node.create_subscription(
VelocityFactorArray,
"/api/planning/velocity_factors",
self.sub_velocity_factors_callback,
sub_qos,
)
self._autoware_connection_time = self._node.get_clock().now()
self._node.create_timer(2, self.reset_timer)

def reset_timer(self):
if utils.check_timeout(self._node.get_clock().now(), self._autoware_connection_time, 10):
self.information = AutowareInformation()
self._node.get_logger().error("Autoware disconnected", throttle_duration_sec=10)
self.is_disconnected = True
else:
self.is_disconnected = False

def sub_operation_mode_callback(self, msg):
try:
Expand Down Expand Up @@ -116,7 +126,6 @@

def sub_path_distance_callback(self, msg):
try:
self._autoware_connection_time = self._node.get_clock().now()
self.information.goal_distance = msg.data
except Exception as e:
self._node.get_logger().error("Unable to get the goal distance, ERROR: " + str(e))
Expand All @@ -134,3 +143,9 @@
self._node.get_logger().error(
"Unable to get the localization init state, ERROR: " + str(e)
)

def sub_velocity_factors_callback(self, msg):
try:
self._autoware_connection_time = self._node.get_clock().now()
except Exception as e:
self._node.get_logger().error("Unable to get the velocity factors, ERROR: " + str(e))
20 changes: 20 additions & 0 deletions src/signage/src/signage/heartbeat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# !/usr/bin/env python3
# -*- coding: utf-8 -*-

from signage.autoware_diagnostic import AutowareDiagnostic
from diagnostic_msgs.msg import DiagnosticStatus

class Heartbeat:
def __init__(self, node):
self._node = node

self._diagnostic_updater = AutowareDiagnostic().init_updater(
self._node,
"/system/signage_connection : signage heartbeat",
self.handle_heartbeat_diagnostics,
"none",
)

def handle_heartbeat_diagnostics(self, stat):
stat.summary(DiagnosticStatus.OK, "signage is working")
return stat
33 changes: 33 additions & 0 deletions src/signage/src/signage/parameter_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,23 @@ class SignageParameter:
monitor_width: int = 1920
monitor_height: int = 540

@dataclass
class AnnounceParameter:
emergency: bool = True
restart_engage: bool = True
door_close: bool = True
door_open: bool = True
engage: bool = True
arrived: bool = True
thank_you: bool = True
in_emergency: bool = True
going_to_depart: bool = True
going_to_arrive: bool = True

class ParameterInterface:
def __init__(self, node):
self.parameter = SignageParameter()
self.announce_settings = AnnounceParameter()

node.declare_parameter("signage_stand_alone", False)
node.declare_parameter("ignore_manual_driving", False)
Expand Down Expand Up @@ -64,3 +77,23 @@ def __init__(self, node):
self.parameter.monitor_height = (
node.get_parameter("monitor_height").get_parameter_value().integer_value
)

node.declare_parameter("announce.emergency", True)
node.declare_parameter("announce.restart_engage", True)
node.declare_parameter("announce.door_close", True)
node.declare_parameter("announce.door_open", True)
node.declare_parameter("announce.engage", True)
node.declare_parameter("announce.thank_you", True)
node.declare_parameter("announce.in_emergency", True)
node.declare_parameter("announce.going_to_depart", True)
node.declare_parameter("gannounce.oing_to_arrive", True)

announce_prefix = node.get_parameters_by_prefix("announce")

for key in announce_prefix.keys():
setattr(
self.announce_settings,
key,
announce_prefix[key].get_parameter_value().bool_value,
)

6 changes: 4 additions & 2 deletions src/signage/src/signage/route_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from datetime import datetime
import signage.signage_utils as utils
from tier4_external_api_msgs.msg import DoorStatus
from autoware_adapi_v1_msgs.msg import (

Check warning on line 11 in src/signage/src/signage/route_handler.py

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (adapi)
RouteState,
MrmState,
OperationModeState,
Expand Down Expand Up @@ -141,7 +141,7 @@
self._engage_trigger_time,
self._parameter.accept_start,
):
self._announce_interface.send_announce("engage")
self._announce_interface.send_announce("restart_engage")
self._engage_trigger_time = self._node.get_clock().now()

if self._autoware.information.motion_state == MotionState.STARTING:
Expand Down Expand Up @@ -370,7 +370,9 @@
self._viewController.next_station_list = self._display_details.next_station_list
self._viewController.display_phrase = self._display_phrase

if (
if self._autoware.is_disconnected:
view_mode = "emergency_stopped"
elif (
not self._autoware.information.autoware_control
and not self._parameter.ignore_manual_driving
):
Expand Down
3 changes: 3 additions & 0 deletions src/signage/src/signage/signage.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import rclpy
from rclpy.node import Node

from signage.heartbeat import Heartbeat
from signage.view_controller import ViewControllerProperty
from signage.announce_controller import AnnounceControllerProperty
from signage.autoware_interface import AutowareInterface
Expand All @@ -25,6 +26,8 @@ def main(args=None):
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()

heartbeat = Heartbeat(node)
autoware_interface = AutowareInterface(node)
autoware_interface = AutowareInterface(node)
parameter_interface = ParameterInterface(node)
ros_service_interface = RosServiceInterface(node, parameter_interface)
Expand Down
Loading