diff --git a/docker/perception/camera_segmentation.Dockerfile b/docker/perception/camera_segmentation.Dockerfile new file mode 100644 index 00000000..7c59a6ab --- /dev/null +++ b/docker/perception/camera_segmentation.Dockerfile @@ -0,0 +1,35 @@ +# ================= Dependencies =================== +FROM ros:humble AS base + +# ADD DEPENDENCIES HERE + +# fix user permissions when deving in container +COPY docker/fixuid_setup.sh /project/fixuid_setup.sh +RUN /project/fixuid_setup.sh +USER docker:docker + +ENV DEBIAN_FRONTEND noninteractive +RUN sudo chsh -s /bin/bash +ENV SHELL=/bin/bash + +# ================= Repositories =================== +FROM base as repo + +RUN mkdir -p ~/ament_ws/src +WORKDIR /home/docker/ament_ws/src + +COPY src/perception/camera_segmentation/ camera_segmentation +COPY src/wato_msgs/sample_msgs sample_msgs + +WORKDIR /home/docker/ament_ws +RUN . /opt/ros/$ROS_DISTRO/setup.sh && \ + rosdep update && \ + rosdep install -i --from-path src --rosdistro $ROS_DISTRO -y && \ + colcon build \ + --cmake-args -DCMAKE_BUILD_TYPE=Release + +# Entrypoint will run before any CMD on launch. Sources ~/opt//setup.bash and ~/ament_ws/install/setup.bash +COPY docker/wato_ros_entrypoint.sh /home/docker/wato_ros_entrypoint.sh +COPY docker/.bashrc /home/docker/.bashrc +ENTRYPOINT ["/usr/local/bin/fixuid", "-q", "/home/docker/wato_ros_entrypoint.sh"] +CMD ["ros2", "launch", "camera_segmentation", "camera_segmentation.launch.py"] \ No newline at end of file diff --git a/profiles/docker-compose.perception.yaml b/profiles/docker-compose.perception.yaml index 81b23108..6c247762 100644 --- a/profiles/docker-compose.perception.yaml +++ b/profiles/docker-compose.perception.yaml @@ -11,3 +11,14 @@ services: user: ${FIXUID:?}:${FIXGID:?} volumes: - ../src/perception/radar_object_detection:/home/docker/ament_ws/src/radar_object_detection + camera_segmentation: + build: + context: .. + dockerfile: docker/perception/camera_segmentation.Dockerfile + cache_from: + - "${CAMERA_SEGMENTATION_IMAGE:?}:${TAG}" + - "${CAMERA_SEGMENTATION_IMAGE:?}:main" + image: "${CAMERA_SEGMENTATION_IMAGE:?}:${TAG}" + user: ${FIXUID:?}:${FIXGID:?} + volumes: + - ../src/perception/camera_segmentation:/home/docker/ament_ws/src/camera_segmentation \ No newline at end of file diff --git a/scripts/watod-setup-env.sh b/scripts/watod-setup-env.sh index ec108ba2..0234b6e5 100755 --- a/scripts/watod-setup-env.sh +++ b/scripts/watod-setup-env.sh @@ -65,7 +65,7 @@ INFRASTRUCTURE_FOXGLOVE_IMAGE=${DATA_STREAM_IMAGE:-"git.uwaterloo.ca:5050/watono # Perception RADAR_OBJECT_DETECTION_IMAGE=${RADAR_OBJECT_DETECTION_IMAGE:-"git.uwaterloo.ca:5050/watonomous/wato_monorepo/radar_object_detection"} - +CAMERA_SEGMENTATION_IMAGE=${CAMERA_SEGMENTATION_IMAGE:-"git.uwaterloo.ca:5050/watonomous/wato_monorepo/camera_segmentation"} ## -------------------------- User ID ----------------------------- FIXUID=$(id -u) @@ -121,6 +121,7 @@ echo "INFRASTRUCTURE_FOXGLOVE_IMAGE=$INFRASTRUCTURE_FOXGLOVE_IMAGE" >> "$PROFILE # Perception echo "RADAR_OBJECT_DETECTION_IMAGE=$RADAR_OBJECT_DETECTION_IMAGE" >> "$PROFILES_DIR/.env" +echo "CAMERA_SEGMENTATION_IMAGE=$CAMERA_SEGMENTATION_IMAGE" >> "$PROFILES_DIR/.env" # World Modeling # Control diff --git a/src/perception/camera_segmentation/camera_segmentation/__init__.py b/src/perception/camera_segmentation/camera_segmentation/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/src/perception/camera_segmentation/camera_segmentation/camera_segmentation_node.py b/src/perception/camera_segmentation/camera_segmentation/camera_segmentation_node.py new file mode 100755 index 00000000..b5dc7dfe --- /dev/null +++ b/src/perception/camera_segmentation/camera_segmentation/camera_segmentation_node.py @@ -0,0 +1,44 @@ +import rclpy +from rclpy.node import Node + +from std_msgs.msg import String +from sensor_msgs.msg import Image + +class CameraSegmentationNode(Node): + + def __init__(self): + super().__init__('node') + # log initialization + self.get_logger().info('Initializing node...') + # Fetch parameters from yaml file + self.declare_parameter('camera_topic', '/camera_topic') + self.declare_parameter('publish_topic', '/camera_segmentation') + camera_topic = self.get_parameter('camera_topic').get_parameter_value().string_value + publish_topic = self.get_parameter('publish_topic').get_parameter_value().string_value + self.publisher_ = self.create_publisher(Image, publish_topic, 10) + self.subscriber_ = self.create_subscription(Image, camera_topic, self.image_callback, 10) + self.i = 0 + + def image_callback(self): + msg = Image() + self.publisher_.publish(msg) + self.get_logger().info('Publishing image: "%s"' % msg.data) + self.i += 1 + + +def main(args=None): + rclpy.init(args=args) + + node = CameraSegmentationNode() + + rclpy.spin(node) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/src/perception/camera_segmentation/config/params.yaml b/src/perception/camera_segmentation/config/params.yaml new file mode 100644 index 00000000..7d2062d6 --- /dev/null +++ b/src/perception/camera_segmentation/config/params.yaml @@ -0,0 +1,4 @@ +lane_detection_node: + ros__parameters: + camera_topic: /CAM_FRONT/image_rect_compressed + publish_topic: /image_segmentation \ No newline at end of file diff --git a/src/perception/camera_segmentation/launch/camera_segmentation.launch.py b/src/perception/camera_segmentation/launch/camera_segmentation.launch.py new file mode 100644 index 00000000..1f51188e --- /dev/null +++ b/src/perception/camera_segmentation/launch/camera_segmentation.launch.py @@ -0,0 +1,35 @@ +# Copyright 2023 WATonomous +# +# 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. + +import os +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch_ros.actions import Node + +def generate_launch_description(): + + param_file_path = os.path.join( + get_package_share_directory('camera_segmentation'), + 'config', + 'params.yaml' + ) + + return LaunchDescription([ + Node( + package='camera_segmentation', + executable='camera_segmentation_node', + parameters=[param_file_path] + ) + ]) \ No newline at end of file diff --git a/src/perception/camera_segmentation/package.xml b/src/perception/camera_segmentation/package.xml new file mode 100755 index 00000000..f8f6f0c6 --- /dev/null +++ b/src/perception/camera_segmentation/package.xml @@ -0,0 +1,18 @@ + + + + camera_segmentation + 0.0.0 + TODO: Package description + docker + TODO: License declaration + + ament_copyright + ament_flake8 + ament_pep257 + python3-pytest + + + ament_python + + diff --git a/src/perception/camera_segmentation/resource/camera_segmentation b/src/perception/camera_segmentation/resource/camera_segmentation new file mode 100755 index 00000000..e69de29b diff --git a/src/perception/camera_segmentation/setup.cfg b/src/perception/camera_segmentation/setup.cfg new file mode 100755 index 00000000..932cacd8 --- /dev/null +++ b/src/perception/camera_segmentation/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/camera_segmentation +[install] +install_scripts=$base/lib/camera_segmentation diff --git a/src/perception/camera_segmentation/setup.py b/src/perception/camera_segmentation/setup.py new file mode 100755 index 00000000..883f9d5c --- /dev/null +++ b/src/perception/camera_segmentation/setup.py @@ -0,0 +1,34 @@ +from setuptools import find_packages, setup +import os +from glob import glob +from setuptools import setup + +package_name = 'camera_segmentation' + +setup( + name=package_name, + version='0.0.0', + packages=find_packages(exclude=['test']), + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + (os.path.join('share', package_name), ['package.xml']), + # Include all launch files + (os.path.join('share', package_name, 'launch'), + glob(os.path.join('launch', '*.launch.py'))), + # Include config files for parameters + (os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*.yaml'))), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='docker', + maintainer_email='docker@todo.todo', + description='TODO: Package description', + license='TODO: License declaration', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'camera_segmentation_node = camera_segmentation.camera_segmentation_node:main' + ], + }, +) diff --git a/src/perception/camera_segmentation/test/test_copyright.py b/src/perception/camera_segmentation/test/test_copyright.py new file mode 100755 index 00000000..97a39196 --- /dev/null +++ b/src/perception/camera_segmentation/test/test_copyright.py @@ -0,0 +1,25 @@ +# 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 + + +# Remove the `skip` decorator once the source file(s) have a copyright header +@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') +@pytest.mark.copyright +@pytest.mark.linter +def test_copyright(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found errors' diff --git a/src/perception/camera_segmentation/test/test_flake8.py b/src/perception/camera_segmentation/test/test_flake8.py new file mode 100755 index 00000000..27ee1078 --- /dev/null +++ b/src/perception/camera_segmentation/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/src/perception/camera_segmentation/test/test_pep257.py b/src/perception/camera_segmentation/test/test_pep257.py new file mode 100755 index 00000000..b234a384 --- /dev/null +++ b/src/perception/camera_segmentation/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/watod-config.sh b/watod-config.sh index ade01782..d917e066 100755 --- a/watod-config.sh +++ b/watod-config.sh @@ -7,7 +7,7 @@ ## - production : configs for all containers required in production ## - samples : starts sample ROS2 pubsub nodes -# ACTIVE_PROFILES="" +ACTIVE_PROFILES="vis_tools perception" ## Name to append to docker containers. DEFAULT = @@ -18,4 +18,4 @@ ## Tag to use. Images are formatted as : with forward slashes replaced with dashes. ## DEFAULT = -# TAG="" +TAG="justin"