diff --git a/README.md b/README.md index 018616e..64aaa75 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Ref: https://docs.ros.org/en/foxy/Tutorials/Beginner-Client-Libraries/Creating-A cd ~ ``` -4. Go to src folder in your workspace +4. Go to src folder in your workspace. Change my_name_ws accordingly ```shell script cd my_name_ws/src/ @@ -55,6 +55,65 @@ sudo rosdep init rosdep update ``` +5. Open VSCode, got to the menu and select file, an then select open folder and select our workspace in home. This show our workspace in the VScode explorer + +6. In a terminal go to your workspace + +```shell script +colcon build +``` + +7. Sourve the overlay according to your distro + +```shell script +source /opt/ros/foxy/setup.bash +``` +8. + +```shell script +. install/local_setup.bash +``` + + +## Virtual Environment Setup in Linux + +https://docs.ros.org/en/foxy/How-To-Guides/Using-Python-Packages.html + +```shell script +sudo apt install python3-pip +``` + +```shell script +sudo apt install python3-virtualenv +``` +### Make a virtual env and activate it + +From your workspace directory run this command + +```shell script +virtualenv -p python3 ./venv +``` +```shell script +source ./venv/bin/activate +``` + +Make sure that colcon doesn’t try to build the venv +```shell script +touch ./venv/COLCON_IGNORE +``` + + +Next, install the Python packages that you want in your virtual environment: + +if any requirement file is in the src folder, then install them for command line + +```shell script +pip install -r src/requirements.txt +``` + +Now you can build your workspace and run your python node that depends on packages installed in your virtual environment. + + ## Source Control Recommendations @@ -66,3 +125,8 @@ rosdep update BUENOS DIAS :) +ADIOS +hola willy +HOla reyes + +Feliz cumpleaños willy :) diff --git a/henry_pkg/henry_pkg/__init__.py b/henry_pkg/henry_pkg/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/henry_pkg/henry_pkg/fis.py b/henry_pkg/henry_pkg/fis.py new file mode 100644 index 0000000..cebfbda --- /dev/null +++ b/henry_pkg/henry_pkg/fis.py @@ -0,0 +1,33 @@ +import numpy as np +import skfuzzy as fuzz +from skfuzzy import control as ctrl + +# New Antecedent/Consequent objects hold universe variables and membership +# functions +quality = ctrl.Antecedent(np.arange(0, 11, 1), 'quality') +service = ctrl.Antecedent(np.arange(0, 11, 1), 'service') +tip = ctrl.Consequent(np.arange(0, 26, 1), 'tip') + +# Auto-membership function population is possible with .automf(3, 5, or 7) +quality.automf(3) +service.automf(3) + +# Custom membership functions can be built interactively with a familiar, +# Pythonic API +tip['low'] = fuzz.trimf(tip.universe, [0, 0, 13]) +tip['medium'] = fuzz.trimf(tip.universe, [0, 13, 25]) +tip['high'] = fuzz.trimf(tip.universe, [13, 25, 25]) + +rule1 = ctrl.Rule(quality['poor'] | service['poor'], tip['low']) +rule2 = ctrl.Rule(service['average'], tip['medium']) +rule3 = ctrl.Rule(service['good'] | quality['good'], tip['high']) + +rule1.view() + +tipping_ctrl = ctrl.ControlSystem([rule1, rule2, rule3]) + +def main(args=None): + print() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/henry_pkg/henry_pkg/my_pub.py b/henry_pkg/henry_pkg/my_pub.py new file mode 100644 index 0000000..fff0ae1 --- /dev/null +++ b/henry_pkg/henry_pkg/my_pub.py @@ -0,0 +1,39 @@ +import rclpy +from rclpy.node import Node + +from std_msgs.msg import String + + +class MinimalPublisher(Node): + + def __init__(self): + super().__init__('minimal_publisher') + self.publisher_ = self.create_publisher(String, 'topic', 10) + timer_period = 0.5 # seconds + self.timer = self.create_timer(timer_period, self.timer_callback) + self.i = 0 + + def timer_callback(self): + msg = String() + msg.data = 'Hello World: %d' % self.i + self.publisher_.publish(msg) + self.get_logger().info('Publishing: "%s"' % msg.data) + self.i += 1 + + +def main(args=None): + rclpy.init(args=args) + + minimal_publisher = MinimalPublisher() + + rclpy.spin(minimal_publisher) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + minimal_publisher.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/henry_pkg/henry_pkg/server.py b/henry_pkg/henry_pkg/server.py new file mode 100644 index 0000000..cfd482f --- /dev/null +++ b/henry_pkg/henry_pkg/server.py @@ -0,0 +1,55 @@ +import rclpy +from rclpy.node import Node +from sensor_msgs.msg import Image +from lolito_interfaces.srv import CaptureImage + + +class ImageCaptureServer(Node): + def __init__(self): + super().__init__('image_capture_server') + self.srv = self.create_service(CaptureImage, 'capture_image', self.capture_image_callback) + + def capture_image_callback(self, request, response): + # Aquí es donde capturamos la imagen y la enviamos como respuesta + image = self.capture_image() + response.image = image + return response + + def capture_image(self): + # En este ejemplo, utilizamos la biblioteca OpenCV para capturar la imagen + import cv2 + + # Capturamos la imagen de la cámara web + cap = cv2.VideoCapture(0) + _, frame = cap.read() + + # Convertimos la imagen capturada a un mensaje ROS + msg = Image() + msg.header.frame_id = 'camera' + msg.encoding = 'bgr8' + msg.height, msg.width, _ = frame.shape + msg.step = 3 * msg.width + msg.data = frame.tobytes() + + # Liberamos la cámara web + cap.release() + + return msg + + +def main(args=None): + rclpy.init(args=args) + + node = ImageCaptureServer() + + try: + rclpy.spin(node) + except KeyboardInterrupt: + pass + + node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/henry_pkg/package.xml b/henry_pkg/package.xml new file mode 100644 index 0000000..abad098 --- /dev/null +++ b/henry_pkg/package.xml @@ -0,0 +1,30 @@ + + + + henry_pkg + 0.0.0 + TODO: Package description + roncanciovl + Apache License 2.0 + + rclpy + std_msgs + sensor_msgs + example_interfaces + + rosidl_default_generators + rosidl_default_runtime + rosidl_interface_packages + + + + ament_copyright + + ament_flake8 + ament_pep257 + python3-pytest + + + ament_python + + diff --git a/henry_pkg/resource/henry_pkg b/henry_pkg/resource/henry_pkg new file mode 100644 index 0000000..e69de29 diff --git a/henry_pkg/setup.cfg b/henry_pkg/setup.cfg new file mode 100644 index 0000000..6beb4db --- /dev/null +++ b/henry_pkg/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/henry_pkg +[install] +install-scripts=$base/lib/henry_pkg diff --git a/henry_pkg/setup.py b/henry_pkg/setup.py new file mode 100644 index 0000000..a3dc297 --- /dev/null +++ b/henry_pkg/setup.py @@ -0,0 +1,27 @@ +from setuptools import setup + +package_name = 'henry_pkg' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='roncanciovl', + maintainer_email='henryroncanciovelandia@gmail.com', + description='TODO: Package description', + license='Apache License 2.0', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'talker = henry_pkg.my_pub:main', + 'imageServer = henry_pkg.server:main', + ], + }, +) diff --git a/henry_pkg/test/test_copyright.py b/henry_pkg/test/test_copyright.py new file mode 100644 index 0000000..cc8ff03 --- /dev/null +++ b/henry_pkg/test/test_copyright.py @@ -0,0 +1,23 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# 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. + +from ament_copyright.main import main +import pytest + + +@pytest.mark.copyright +@pytest.mark.linter +def test_copyright(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found errors' diff --git a/henry_pkg/test/test_flake8.py b/henry_pkg/test/test_flake8.py new file mode 100644 index 0000000..27ee107 --- /dev/null +++ b/henry_pkg/test/test_flake8.py @@ -0,0 +1,25 @@ +# Copyright 2017 Open Source Robotics Foundation, Inc. +# +# 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. + +from ament_flake8.main import main_with_errors +import pytest + + +@pytest.mark.flake8 +@pytest.mark.linter +def test_flake8(): + rc, errors = main_with_errors(argv=[]) + assert rc == 0, \ + 'Found %d code style errors / warnings:\n' % len(errors) + \ + '\n'.join(errors) diff --git a/henry_pkg/test/test_pep257.py b/henry_pkg/test/test_pep257.py new file mode 100644 index 0000000..b234a38 --- /dev/null +++ b/henry_pkg/test/test_pep257.py @@ -0,0 +1,23 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# 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. + +from ament_pep257.main import main +import pytest + + +@pytest.mark.linter +@pytest.mark.pep257 +def test_pep257(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found code style errors / warnings' diff --git a/lolito/CMakeLists.txt b/lolito/CMakeLists.txt new file mode 100644 index 0000000..69d94d8 --- /dev/null +++ b/lolito/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.5) +project(lolito) + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +find_package(ament_cmake_python REQUIRED) +find_package(rclpy REQUIRED) +find_package(std_msgs REQUIRED) + +ament_python_install_package(Scripts/) + +install(PROGRAMS + Scripts/pub-raul.py + DESTINATION lib/${PROJECT_NAME} +) +# uncomment the following section in order to fill in +# further dependencies manually. +# find_package( REQUIRED) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # uncomment the line when a copyright and license is not present in all source files + #set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # uncomment the line when this package is not in a git repo + #set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/lolito/Scripts/__init__.py b/lolito/Scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lolito/Scripts/pub-raul.py b/lolito/Scripts/pub-raul.py new file mode 100644 index 0000000..89ca552 --- /dev/null +++ b/lolito/Scripts/pub-raul.py @@ -0,0 +1,41 @@ +#!usr/bin/env python3 + + +import rclpy +from rclpy.node import Node + +from std_msgs.msg import String + +class MinimalPublisher(Node): + + def __init__(self): + super().__init__('minimal_publisher') + self.publisher_ = self.create_publisher(String, 'topic', 10) + timer_period = 0.5 # seconds + self.timer = self.create_timer(timer_period, self.timer_callback) + self.i = 0 + + def timer_callback(self): + msg = String() + msg.data = 'Bless kchon %d' % self.i + self.publisher_.publish(msg) + self.get_logger().info('Publishing: "%s"' % msg.data) + self.i += 1 + + +def main(args=None): + rclpy.init(args=args) + + minimal_publisher = MinimalPublisher() + + rclpy.spin(minimal_publisher) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + minimal_publisher.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/lolito/lolito/__init__.py b/lolito/lolito/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lolito/lolito/scripts/pubhen.py b/lolito/lolito/scripts/pubhen.py new file mode 100755 index 0000000..65e1fad --- /dev/null +++ b/lolito/lolito/scripts/pubhen.py @@ -0,0 +1,42 @@ + +#!/home/roncanciovl/ros2class_ws/venv/bin/python3 + +import rclpy +from rclpy.node import Node + +from std_msgs.msg import String + + +class MinimalPublisher(Node): + + def __init__(self): + super().__init__('minimal_publisher') + self.publisher_ = self.create_publisher(String, 'topic', 10) + timer_period = 0.5 # seconds + self.timer = self.create_timer(timer_period, self.timer_callback) + self.i = 0 + + def timer_callback(self): + msg = String() + msg.data = 'Hello World: %d' % self.i + self.publisher_.publish(msg) + self.get_logger().info('Publishing: "%s"' % msg.data) + self.i += 1 + + +def main(args=None): + rclpy.init(args=args) + + minimal_publisher = MinimalPublisher() + + rclpy.spin(minimal_publisher) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + minimal_publisher.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/lolito/package.xml b/lolito/package.xml new file mode 100644 index 0000000..cb09290 --- /dev/null +++ b/lolito/package.xml @@ -0,0 +1,22 @@ + + + + lolito + 0.0.0 + TODO: Package description + roncanciovl + TODO: License declaration + + + ament_cmake + ament_cmake_python + rclpy + std_msgs + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/lolito_interfaces/CMakeLists.txt b/lolito_interfaces/CMakeLists.txt new file mode 100644 index 0000000..aef6e8c --- /dev/null +++ b/lolito_interfaces/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.5) +project(lolito_interfaces) + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +find_package(sensor_msgs REQUIRED) +find_package(rosidl_default_generators REQUIRED) + +rosidl_generate_interfaces(${PROJECT_NAME} + "srv/CaptureImage.srv" + DEPENDENCIES sensor_msgs # Add packages that above messages depend on, in this case geometry_msgs for Sphere.msg +) +# uncomment the following section in order to fill in +# further dependencies manually. +# find_package( REQUIRED) + +ament_export_dependencies(rosidl_default_runtime) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # uncomment the line when a copyright and license is not present in all source files + #set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # uncomment the line when this package is not in a git repo + #set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/lolito_interfaces/package.xml b/lolito_interfaces/package.xml new file mode 100644 index 0000000..d5e7244 --- /dev/null +++ b/lolito_interfaces/package.xml @@ -0,0 +1,26 @@ + + + + lolito_interfaces + 0.0.0 + TODO: Package description + roncanciovl + TODO: License declaration + ament_cmake + sensor_msgs + + rosidl_default_generators + + rosidl_default_runtime + + rosidl_interface_packages + + + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/lolito_interfaces/srv/CaptureImage.srv b/lolito_interfaces/srv/CaptureImage.srv new file mode 100644 index 0000000..f0cd11e --- /dev/null +++ b/lolito_interfaces/srv/CaptureImage.srv @@ -0,0 +1,3 @@ +bool req +--- +sensor_msgs/Image my_image \ No newline at end of file diff --git a/raul_pkg/launch/python_parameters_launch.py b/raul_pkg/launch/python_parameters_launch.py new file mode 100644 index 0000000..8b1831b --- /dev/null +++ b/raul_pkg/launch/python_parameters_launch.py @@ -0,0 +1,36 @@ +from launch import LaunchDescription +from launch_ros.actions import Node + +def generate_launch_description(): + return LaunchDescription([ + Node( + package='raul_pkg', + executable='rpm2ls', + name='lineal_speed_joaquin', + output='screen', + emulate_tty=True, + parameters=[ + {'radius': 0.5} + ] + ), + Node( + package='raul_pkg', + executable='rpm2ls', + name='lineal_speed_juan', + output='screen', + emulate_tty=True, + parameters=[ + {'radius': 0.3} + ] + ), + Node( + package='raul_pkg', + executable='rpmpub', + name='rpm_pub', + output='screen', + emulate_tty=True, + parameters=[ + {'rpms':5} + ] + ) + ]) \ No newline at end of file diff --git a/raul_pkg/package.xml b/raul_pkg/package.xml new file mode 100644 index 0000000..47215ec --- /dev/null +++ b/raul_pkg/package.xml @@ -0,0 +1,31 @@ + + + + raul_pkg + 0.0.0 + TODO: Package description + raul + Apache License 2.0 + + cv_bridge + cv_bridge + image_transport + image_transport + sensor_msgs + sensor_msgs + OpenCV + OpenCV + rclpy + std_msgs + ros2launch + ament_copyright + ament_flake8 + ament_pep257 + python3-pytest + + lolito_interfaces + sensor_msgs + + ament_python + + diff --git a/raul_pkg/raul_pkg/__init__.py b/raul_pkg/raul_pkg/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/raul_pkg/raul_pkg/client.py b/raul_pkg/raul_pkg/client.py new file mode 100644 index 0000000..9cc63b7 --- /dev/null +++ b/raul_pkg/raul_pkg/client.py @@ -0,0 +1,38 @@ +import rclpy +from lolito_interfaces.srv import CaptureImage +from sensor_msgs.msg import Image +import cv2 +from cv_bridge import CvBridge + +def send_request(node): + client = node.create_client(CaptureImage, 'capture_image') + image_sub = node.create_subscription(Image, 'capture_image', handle_image, 10) + req = CaptureImage.Request() + + while not client.wait_for_service(timeout_sec=1.0): + node.get_logger().info('Servicio no disponible, esperando...') + + future = client.call_async(req) + rclpy.spin_until_future_complete(node, future) + + if future.result() is not None: + node.get_logger().info('Respuesta: %d' % future.result().sum) + else: + node.get_logger().info('Error en la solicitud') + +def handle_image(msg): + bridge = CvBridge() + image = bridge.imgmsg_to_cv2(msg, desired_encoding='passthrough') + cv2.imshow('Imagen recibida', image) + cv2.waitKey(0) + pass + +def main(args=None): + rclpy.init(args=args) + node = rclpy.create_node('client_raul') + send_request(node) + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/raul_pkg/raul_pkg/pub_raul.py b/raul_pkg/raul_pkg/pub_raul.py new file mode 100644 index 0000000..fff0ae1 --- /dev/null +++ b/raul_pkg/raul_pkg/pub_raul.py @@ -0,0 +1,39 @@ +import rclpy +from rclpy.node import Node + +from std_msgs.msg import String + + +class MinimalPublisher(Node): + + def __init__(self): + super().__init__('minimal_publisher') + self.publisher_ = self.create_publisher(String, 'topic', 10) + timer_period = 0.5 # seconds + self.timer = self.create_timer(timer_period, self.timer_callback) + self.i = 0 + + def timer_callback(self): + msg = String() + msg.data = 'Hello World: %d' % self.i + self.publisher_.publish(msg) + self.get_logger().info('Publishing: "%s"' % msg.data) + self.i += 1 + + +def main(args=None): + rclpy.init(args=args) + + minimal_publisher = MinimalPublisher() + + rclpy.spin(minimal_publisher) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + minimal_publisher.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/raul_pkg/raul_pkg/pub_rpm.py b/raul_pkg/raul_pkg/pub_rpm.py new file mode 100644 index 0000000..d4bb6d2 --- /dev/null +++ b/raul_pkg/raul_pkg/pub_rpm.py @@ -0,0 +1,42 @@ +import rclpy +from rclpy.node import Node + +from std_msgs.msg import String + +RPMS = 3 + +class MinimalPublisher(Node): + + def __init__(self): + super().__init__('Nodo_RPM') + self.declare_parameter('rpms',RPMS) + self.publisher_ = self.create_publisher(String, 'RPM', 10) + timer_period = 1 # seconds + self.timer = self.create_timer(timer_period, self.timer_callback) + self.i = 0 + + def timer_callback(self): + rpmenv = self.get_parameter('rpms').value + msg = String() + msg.data = str(rpmenv) + self.publisher_.publish(msg) + self.get_logger().info('Publishing: "%s"' % msg.data) + self.i += 1 + + +def main(args=None): + rclpy.init(args=args) + + minimal_publisher = MinimalPublisher() + + rclpy.spin(minimal_publisher) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + minimal_publisher.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/raul_pkg/raul_pkg/rpm2ls.py b/raul_pkg/raul_pkg/rpm2ls.py new file mode 100644 index 0000000..e9b3755 --- /dev/null +++ b/raul_pkg/raul_pkg/rpm2ls.py @@ -0,0 +1,39 @@ +import rclpy +from rclpy.node import Node +from std_msgs.msg import String + +WHEEL_RADIUS = 5 #en cm + +class MyNode(Node): + + def __init__(self): + super().__init__('node_lineal_speed') + self.declare_parameter('radius',WHEEL_RADIUS) + self.publisher_ = self.create_publisher(String, 'lineal_speed', 10) + self.subscription = self.create_subscription( + String, + 'RPM', + self.listener_callback, + 10) + self.subscription # prevent unused variable warning + + def listener_callback(self, msg): + #self.get_logger().info('I heard: "%s"' % msg.data) + radio = self.get_parameter('radius').value + numin=(float(msg.data)/60)*2*3.141516*radio + print(numin) + msg.data=str(numin) + self.publisher_.publish(msg) + +def main(args=None): + rclpy.init(args=args) + + my_node = MyNode() + + rclpy.spin(my_node) + + my_node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/raul_pkg/raul_pkg/server.py b/raul_pkg/raul_pkg/server.py new file mode 100644 index 0000000..7c82e51 --- /dev/null +++ b/raul_pkg/raul_pkg/server.py @@ -0,0 +1,57 @@ +#Create a node server to receive a message and capture photo and send to client +# Path: src/willy_pkg/willy_pkg/probar.py +# Compare this snippet from src/willy_pkg/willy_pkg/foto_servidor.py: + +import rclpy +from rclpy.node import Node +from sensor_msgs.msg import Image +from lolito_interfaces.srv import CaptureImage + +class ImageCaptureServer(Node): + def __init__(self): + super().__init__('willy_server') + self.srv = self.create_service(CaptureImage, 'capture_image', self.capture_image_callback) + + def capture_image_callback(self, request, response): + # Aquí es donde capturamos la imagen y la enviamos como respuesta + image = self.capture_image() + response.image = image + return response + + def capture_image(self): + # En este ejemplo, utilizamos la biblioteca OpenCV para capturar la imagen + import cv2 + + # Capturamos la imagen de la cámara web + cap = cv2.VideoCapture(0) + _, frame = cap.read() + + # Convertimos la imagen capturada a un mensaje ROS + msg = Image() + msg.header.frame_id = 'camera' + msg.encoding = 'bgr8' + msg.height, msg.width, _ = frame.shape + msg.step = 3 * msg.width + msg.data = frame.tobytes() + + # Liberamos la cámara web + cap.release() + + return msg + + +def main(args=None): + rclpy.init(args=args) + + node = ImageCaptureServer() + + try: + rclpy.spin(node) + except KeyboardInterrupt: + pass + + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/raul_pkg/raul_pkg/sub_raul.py b/raul_pkg/raul_pkg/sub_raul.py new file mode 100644 index 0000000..1e546d4 --- /dev/null +++ b/raul_pkg/raul_pkg/sub_raul.py @@ -0,0 +1,37 @@ +import rclpy +from rclpy.node import Node + +from std_msgs.msg import String + + +class MinimalSubscriber(Node): + + def __init__(self): + super().__init__('node_Raul') + self.subscription = self.create_subscription( + String, + 'lineal_speed', + self.listener_callback, + 10) + self.subscription # prevent unused variable warning + + def listener_callback(self, msg): + self.get_logger().info('I heard: "%s"' % msg.data) + + +def main(args=None): + rclpy.init(args=args) + + minimal_subscriber = MinimalSubscriber() + + rclpy.spin(minimal_subscriber) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + minimal_subscriber.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/raul_pkg/resource/raul_pkg b/raul_pkg/resource/raul_pkg new file mode 100644 index 0000000..e69de29 diff --git a/raul_pkg/setup.cfg b/raul_pkg/setup.cfg new file mode 100644 index 0000000..8ca868b --- /dev/null +++ b/raul_pkg/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/raul_pkg +[install] +install-scripts=$base/lib/raul_pkg diff --git a/raul_pkg/setup.py b/raul_pkg/setup.py new file mode 100644 index 0000000..367111c --- /dev/null +++ b/raul_pkg/setup.py @@ -0,0 +1,33 @@ +from setuptools import setup +import os +from glob import glob + +package_name = 'raul_pkg' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + (os.path.join('share', package_name), glob('launch/*launch.[pxy][yma]*')), + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='raul', + maintainer_email='alvaroraulurdanetag@gmail.com', + description='TODO: Package description', + license='Apache License 2.0', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'talker = raul_pkg.pub_raul:main', + 'listener = raul_pkg.sub_raul:main', + 'rpm2ls = raul_pkg.rpm2ls:main', + 'rpmpub = raul_pkg.pub_rpm:main', + 'server = raul_pkg.server:main' + ], + }, +) \ No newline at end of file diff --git a/raul_pkg/test/test_copyright.py b/raul_pkg/test/test_copyright.py new file mode 100644 index 0000000..cc8ff03 --- /dev/null +++ b/raul_pkg/test/test_copyright.py @@ -0,0 +1,23 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# 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. + +from ament_copyright.main import main +import pytest + + +@pytest.mark.copyright +@pytest.mark.linter +def test_copyright(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found errors' diff --git a/raul_pkg/test/test_flake8.py b/raul_pkg/test/test_flake8.py new file mode 100644 index 0000000..27ee107 --- /dev/null +++ b/raul_pkg/test/test_flake8.py @@ -0,0 +1,25 @@ +# Copyright 2017 Open Source Robotics Foundation, Inc. +# +# 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. + +from ament_flake8.main import main_with_errors +import pytest + + +@pytest.mark.flake8 +@pytest.mark.linter +def test_flake8(): + rc, errors = main_with_errors(argv=[]) + assert rc == 0, \ + 'Found %d code style errors / warnings:\n' % len(errors) + \ + '\n'.join(errors) diff --git a/raul_pkg/test/test_pep257.py b/raul_pkg/test/test_pep257.py new file mode 100644 index 0000000..b234a38 --- /dev/null +++ b/raul_pkg/test/test_pep257.py @@ -0,0 +1,23 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# 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. + +from ament_pep257.main import main +import pytest + + +@pytest.mark.linter +@pytest.mark.pep257 +def test_pep257(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found code style errors / warnings' diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a504033 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,76 @@ +action-tutorials-py==0.9.4 +ament-copyright==0.9.7 +ament-cppcheck==0.9.7 +ament-cpplint==0.9.7 +ament-flake8==0.9.7 +ament-index-python==1.1.0 +ament-lint==0.9.7 +ament-lint-cmake==0.9.7 +ament-package==0.9.5 +ament-pep257==0.9.7 +ament-uncrustify==0.9.7 +ament-xmllint==0.9.7 +demo-nodes-py==0.9.4 +domain-coordinator==0.9.2 +examples-rclpy-executors==0.9.4 +examples-rclpy-minimal-action-client==0.9.4 +examples-rclpy-minimal-action-server==0.9.4 +examples-rclpy-minimal-client==0.9.4 +examples-rclpy-minimal-publisher==0.9.4 +examples-rclpy-minimal-service==0.9.4 +examples-rclpy-minimal-subscriber==0.9.4 +henry-pkg==0.0.0 +launch==0.10.10 +launch-ros==0.11.7 +launch-testing==0.10.10 +launch-testing-ros==0.11.7 +launch-xml==0.10.10 +launch-yaml==0.10.10 +networkx==3.0 +numpy==1.24.2 +osrf-pycommon==0.1.11 +quality-of-service-demo-py==0.9.4 +ros2action==0.9.12 +ros2bag==0.3.9 +ros2cli==0.9.12 +ros2component==0.9.12 +ros2doctor==0.9.12 +ros2interface==0.9.12 +ros2launch==0.11.7 +ros2lifecycle==0.9.12 +ros2multicast==0.9.12 +ros2node==0.9.12 +ros2param==0.9.12 +ros2pkg==0.9.12 +ros2run==0.9.12 +ros2service==0.9.12 +ros2topic==0.9.12 +rosidl-runtime-py==0.9.1 +rpyutils==0.2.0 +rqt==1.1.2 +rqt-action==0.4.9 +rqt-console==1.1.2 +rqt-graph==1.1.3 +rqt-gui==1.1.2 +rqt-gui-py==1.1.2 +rqt-moveit==1.0.1 +rqt-msg==1.0.5 +rqt-plot==1.1.1 +rqt-publisher==1.3.0 +rqt-py-console==1.0.2 +rqt-reconfigure==1.0.8 +rqt-robot-dashboard==0.5.8 +rqt-robot-monitor==1.0.5 +rqt-robot-steering==1.0.0 +rqt-runtime-monitor==1.0.0 +rqt-service-caller==1.0.5 +rqt-shell==1.0.2 +rqt-srv==1.0.3 +rqt-tf-tree==1.0.2 +rqt-top==1.0.2 +rqt-topic==1.3.0 +scikit-fuzzy==0.4.2 +scipy==1.10.1 +sros2==0.9.5 +teleop-twist-keyboard==2.3.2 +topic-monitor==0.9.4