Skip to content

Commit cda9aae

Browse files
VulcanAI Tutorials (#256)
* Refs #23739: Tutorial base Signed-off-by: cferreiragonz <[email protected]> * Refs #23739: Basic tools tutorials Signed-off-by: cferreiragonz <[email protected]> * Refs #23739: Add turtlesim tutorial Signed-off-by: cferreiragonz <[email protected]> * Refs #23739: Unify package name Signed-off-by: cferreiragonz <[email protected]> * Refs #23739: Add whole package Signed-off-by: cferreiragonz <[email protected]> * Refs #23739: Pentagon video, update imports, split tools code Signed-off-by: cferreiragonz <[email protected]> * Refs #23739: Fix timeout arg name Signed-off-by: Carlos Ferreira González <[email protected]> * Refs #23739: Apply typos review Signed-off-by: Carlos Ferreira González <[email protected]> * Refs #23739: Move tutorial, fix imports, spelling Signed-off-by: Carlos Ferreira González <[email protected]> * Refs #23739: Url Signed-off-by: Carlos Ferreira González <[email protected]> * Refs #23739: Revision & Spelling wordlist Signed-off-by: Carlos Ferreira González <[email protected]> * Refs #23739: Add Beta note, figure, minor fixes Signed-off-by: Carlos Ferreira González <[email protected]> * Refs #23739: Pip installation warning Signed-off-by: Carlos Ferreira González <[email protected]> --------- Signed-off-by: cferreiragonz <[email protected]> Signed-off-by: Carlos Ferreira González <[email protected]>
1 parent aa20e43 commit cda9aae

35 files changed

+1846
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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>vulcanai_turtlesim_demo</name>
5+
<version>0.1.0</version>
6+
<description>Demo package for VulcanAI library with ROS 2 turtlesim</description>
7+
<author email="[email protected]">Carlos Ferreira</author>
8+
<maintainer email="[email protected]">Carlos Ferreira</maintainer>
9+
<license>Apache License 2.0</license>
10+
11+
<depend>rclpy</depend>
12+
<depend>std_srvs</depend>
13+
<depend>geometry_msgs</depend>
14+
<depend>turtlesim</depend>
15+
16+
<exec_depend>python3-vulcanai</exec_depend>
17+
18+
<export>
19+
<build_type>ament_python</build_type>
20+
</export>
21+
</package>

code/vulcanai_turtlesim/vulcanai_turtlesim_demo/resource/vulcanai_turtlesim_demo

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[develop]
2+
script_dir=$base/lib/vulcanai_turtlesim_demo
3+
[install]
4+
install_scripts=$base/lib/vulcanai_turtlesim_demo
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from setuptools import find_packages, setup
2+
3+
package_name = 'vulcanai_turtlesim_demo'
4+
5+
setup(
6+
name=package_name,
7+
version='0.0.0',
8+
packages=find_packages(exclude=['test']),
9+
data_files=[
10+
('share/ament_index/resource_index/packages',
11+
['resource/' + package_name]),
12+
('share/' + package_name, ['package.xml']),
13+
],
14+
install_requires=['setuptools'],
15+
zip_safe=True,
16+
maintainer='root',
17+
maintainer_email='[email protected]',
18+
description='TODO: Package description',
19+
license='TODO: License declaration',
20+
# tests_require=['pytest'],
21+
entry_points={
22+
"console_scripts": [
23+
"vulcanai_turtlesim_demo = vulcanai_turtlesim_demo.ros2_node:main",
24+
],
25+
"turtle_tools": [
26+
"turtle_tools = vulcanai_turtlesim_demo.turtlesim_tools",
27+
],
28+
},
29+
)

code/vulcanai_turtlesim/vulcanai_turtlesim_demo/vulcanai_turtlesim_demo/__init__.py

Whitespace-only changes.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""
2+
This file contains a ROS 2 SharedNode and the main entrypoint to test the turtlesim tools.
3+
"""
4+
5+
import threading
6+
7+
import rclpy
8+
from rclpy.node import Node
9+
from rclpy.task import Future
10+
11+
from vulcanai import VulcanConsole
12+
13+
14+
class SharedNode(Node):
15+
def __init__(self, name: str = "vulcanai_shared_node"):
16+
super().__init__(name)
17+
# Dictionary to store created clients
18+
self._vulcan_clients = {}
19+
# Dictionary to store created publishers
20+
self._vulcan_publishers = {}
21+
22+
# Ensure entities creation is thread-safe.
23+
self.node_lock = threading.Lock()
24+
25+
def get_client(self, srv_type, srv_name):
26+
"""
27+
Get a cached client for the specified service type and name or
28+
create a new one if it doesn't exist.
29+
"""
30+
key = (srv_type, srv_name)
31+
with self.node_lock:
32+
if key not in self._vulcan_clients:
33+
client = self.create_client(srv_type, srv_name)
34+
self._vulcan_clients[key] = client
35+
self.get_logger().info(f"Created new client for {srv_name}")
36+
return self._vulcan_clients[key]
37+
38+
def get_publisher(self, msg_type, topic_name):
39+
"""
40+
Get a cached publisher for the specified message type and topic name or
41+
create a new one if it doesn't exist.
42+
"""
43+
key = (msg_type, topic_name)
44+
with self.node_lock:
45+
if key not in self._vulcan_publishers:
46+
publisher = self.create_publisher(msg_type, topic_name, 10)
47+
self._vulcan_publishers[key] = publisher
48+
self.get_logger().info(f"Created new publisher for {topic_name}")
49+
return self._vulcan_publishers[key]
50+
51+
def wait_for_message(self, msg_type, topic: str, timeout_sec: float = None):
52+
"""
53+
Block until a message is received or timeout expires.
54+
Subscriptions are created on demand and destroyed after use to avoid
55+
handling spins and callbacks in a separate thread.
56+
"""
57+
future = Future()
58+
59+
def callback(msg):
60+
if not future.done():
61+
future.set_result(msg)
62+
63+
sub = self.create_subscription(msg_type, topic, callback, 10)
64+
65+
rclpy.spin_until_future_complete(self, future, timeout_sec=timeout_sec)
66+
self.destroy_subscription(sub)
67+
68+
if future.done():
69+
return future.result()
70+
return None
71+
72+
73+
def main(args=None):
74+
# Create a ROS 2 node that will be used by the tools to avoid
75+
# recurrent creation and destruction of DDS Participants
76+
rclpy.init(args=args)
77+
node = SharedNode(name="vulcanai_shared_node")
78+
79+
user_context = """\
80+
You are controlling the turtlesim simulation from ROS 2.
81+
The simulation has one or more turtles that can move around, drawing on the screen as they go."""
82+
83+
console = VulcanConsole()
84+
console.manager.register_tools_from_entry_points("turtle_tools")
85+
console.manager.add_user_context(user_context)
86+
# Add the shared node to the console manager blackboard to be used by tools
87+
console.manager.bb["main_node"] = node
88+
console.run()
89+
90+
91+
if __name__ == '__main__':
92+
main()

0 commit comments

Comments
 (0)