Skip to content

Commit 515a894

Browse files
committed
Revert "chore: remove rai_hmi"
This reverts commit b580439.
1 parent 286b178 commit 515a894

16 files changed

+1294
-0
lines changed

src/rai_hmi/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# RAI HMI
2+
3+
The RAI HMI (Human-Machine Interface) allows users to converse with the robot and order new tasks to be added to the queue. Communication topics use plaintext, but can be connected from ASR (Automatic Speech Recognition) and to TTS (Text To Speech) nodes to enable a voice interface.
4+
5+
> **NOTE:** Currently the node is tailored for the Husarion ROSBot XL demo use case. It is expected that it can be generalized to other use cases when `rai_whoami` package is fully developed and integrated.
6+
7+
## ROS 2 Interface
8+
9+
### Subscribed Topics
10+
11+
- **`from_human`** (`std_msgs/String`): Incoming plaintext messages from the user.
12+
13+
### Published Topics
14+
15+
- **`to_human`** (`std_msgs/String`): Outgoing plaintext messages for the user.
16+
- **`task_addition_requests`** (`std_msgs/String`): Tasks to be added to the queue, in JSON format.
17+
18+
## Task JSON Schema
19+
20+
Tasks published on the `task_addition_request` follow the schema below:
21+
22+
```json
23+
{
24+
"$schema": "http://json-schema.org/draft-04/schema#",
25+
"type": "object",
26+
"properties": {
27+
"name": {
28+
"type": "string"
29+
},
30+
"description": {
31+
"type": "string"
32+
},
33+
"priority": {
34+
"type": "string",
35+
"enum": ["highest", "high", "medium", "low", "lowest"]
36+
},
37+
"robot": {
38+
"type": "string"
39+
}
40+
},
41+
"required": ["name", "description", "priority"]
42+
}
43+
```
44+
45+
Optional field `"robot"` is currently not implemented and is intended to be used in a fleet setting, where a specific robot can be requested to perform the task in question.

src/rai_hmi/package.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0"?>
2+
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
3+
<package format="3">
4+
<name>rai_hmi</name>
5+
<version>0.1.0</version>
6+
<description>A Human-Machine Interface (HMI) to converse with the robot.</description>
7+
<maintainer email="[email protected]">Adam Gotlib</maintainer>
8+
<license>Apache-2.0</license>
9+
10+
<test_depend>python3-pytest</test_depend>
11+
12+
<export>
13+
<build_type>ament_python</build_type>
14+
</export>
15+
</package>

src/rai_hmi/rai_hmi/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (C) 2024 Robotec.AI
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.

src/rai_hmi/rai_hmi/agent.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Copyright (C) 2024 Robotec.AI
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
import uuid
17+
from typing import List
18+
19+
from langchain.tools import tool
20+
from rai.agents.conversational_agent import create_conversational_agent
21+
from rai.node import RaiBaseNode
22+
from rai.tools.ros.native import GetCameraImage, Ros2GetRobotInterfaces
23+
from rai.utils.model_initialization import get_llm_model
24+
25+
from rai_hmi.base import BaseHMINode
26+
from rai_hmi.chat_msgs import MissionMessage
27+
from rai_hmi.task import Task, TaskInput
28+
from rai_hmi.text_hmi_utils import Memory
29+
30+
31+
def initialize_agent(hmi_node: BaseHMINode, rai_node: RaiBaseNode, memory: Memory):
32+
llm = get_llm_model(model_type="complex_model")
33+
34+
@tool
35+
def get_mission_memory(uid: str) -> List[MissionMessage]:
36+
"""List mission memory. It contains the information about running tasks. Mission uid is required."""
37+
return memory.get_mission_memory(uid)
38+
39+
@tool
40+
def submit_mission_to_the_robot(task: TaskInput):
41+
"""Use this tool submit the task to the robot. The task will be handled by the executor part of your system."""
42+
43+
uid = uuid.uuid4()
44+
hmi_node.execute_mission(
45+
Task(
46+
name=task.name,
47+
description=task.description,
48+
priority=task.priority,
49+
uid=str(uid),
50+
)
51+
)
52+
return f"UID={uid} | Task added to the queue: {task.model_dump_json()}"
53+
54+
node_tools = tools = [
55+
Ros2GetRobotInterfaces(node=rai_node),
56+
GetCameraImage(node=rai_node),
57+
]
58+
task_tools = [submit_mission_to_the_robot, get_mission_memory]
59+
tools = hmi_node.tools + node_tools + task_tools
60+
61+
agent = create_conversational_agent(
62+
llm, tools, hmi_node.system_prompt, logger=hmi_node.get_logger()
63+
)
64+
return agent

src/rai_hmi/rai_hmi/api.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright (C) 2024 Robotec.AI
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import re
16+
from abc import abstractmethod
17+
from queue import Queue
18+
19+
from rclpy.callback_groups import ReentrantCallbackGroup
20+
from rclpy.qos import DurabilityPolicy, HistoryPolicy, QoSProfile, ReliabilityPolicy
21+
from std_msgs.msg import String
22+
23+
from rai_hmi.base import BaseHMINode
24+
25+
26+
def split_message(message: str):
27+
sentences = re.split(r"(?<=\.)\s|[:!]", message)
28+
for sentence in sentences:
29+
if sentence:
30+
yield sentence
31+
32+
33+
class GenericVoiceNode(BaseHMINode):
34+
def __init__(self, node_name: str, queue: Queue, robot_description_package: str):
35+
super().__init__(node_name, queue, robot_description_package)
36+
37+
self.callback_group = ReentrantCallbackGroup()
38+
reliable_qos = QoSProfile(
39+
reliability=ReliabilityPolicy.RELIABLE,
40+
durability=DurabilityPolicy.TRANSIENT_LOCAL,
41+
history=HistoryPolicy.KEEP_ALL,
42+
)
43+
self.hmi_subscription = self.create_subscription(
44+
String,
45+
"/from_human",
46+
self.handle_human_message,
47+
qos_profile=reliable_qos,
48+
)
49+
self.hmi_publisher = self.create_publisher(
50+
String,
51+
"/to_human",
52+
qos_profile=reliable_qos,
53+
callback_group=self.callback_group,
54+
)
55+
56+
@abstractmethod
57+
def _handle_human_message(self, msg: String):
58+
pass
59+
60+
def handle_human_message(self, msg: String):
61+
self.processing = True
62+
self._handle_human_message(msg)
63+
self.processing = False

0 commit comments

Comments
 (0)