Skip to content

Commit

Permalink
Adding the yolov8_brake_detection node for brake lights classification
Browse files Browse the repository at this point in the history
  • Loading branch information
saiperam committed Dec 14, 2024
1 parent ed79ad2 commit c0fc708
Show file tree
Hide file tree
Showing 13 changed files with 275 additions and 0 deletions.
23 changes: 23 additions & 0 deletions yolov8_brake_detection/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.5)
project(yolov8_brake_detection)

# Dependencies
find_package(ament_cmake REQUIRED)
find_package(rclpy REQUIRED)
find_package(rosidl_default_generators REQUIRED)

# Specify message files
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/BrakeStatus.msg"
)

# Python scripts
install(
PROGRAMS
yolov8_node.py
yolov8_predict_node.py
DESTINATION lib/${PROJECT_NAME}
)

# Install other package files
ament_package()
24 changes: 24 additions & 0 deletions yolov8_brake_detection/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>yolov8_brake_detection</name>
<version>0.0.0</version>
<description>This package is responsible for performing brake light detection.</description>
<maintainer email="[email protected]">root</maintainer>
<license>Apache-2.0</license>

<depend>sensor_msgs</depend>
<build_depend>rosidl_default_generators</build_depend>
<build_depend>std_msgs</build_depend>
<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>

<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>

<export>
<build_type>ament_python</build_type>
</export>
</package>
Empty file.
4 changes: 4 additions & 0 deletions yolov8_brake_detection/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[develop]
script_dir=$base/lib/yolov8_brake_detection
[install]
install_scripts=$base/lib/yolov8_brake_detection
26 changes: 26 additions & 0 deletions yolov8_brake_detection/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from setuptools import setup

package_name = 'yolov8_brake_detection'

setup(
name=package_name,
version='0.0.1',
packages=[package_name],
install_requires=[
'setuptools',
'torch',
'opencv-python',
'cv-bridge',
'rclpy',
'sensor_msgs', # Dependencies for brake light detection node
],
data_files=[
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
entry_points={
'console_scripts': [
'yolov8_node = yolov8_brake_detection.yolov8_node:main',
],
},
)
25 changes: 25 additions & 0 deletions yolov8_brake_detection/test/test_copyright.py
Original file line number Diff line number Diff line change
@@ -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'
25 changes: 25 additions & 0 deletions yolov8_brake_detection/test/test_flake8.py
Original file line number Diff line number Diff line change
@@ -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)
23 changes: 23 additions & 0 deletions yolov8_brake_detection/test/test_pep257.py
Original file line number Diff line number Diff line change
@@ -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'
Empty file.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
rosbag2_bagfile_information:
version: 5
storage_identifier: sqlite3
duration:
nanoseconds: 0
starting_time:
nanoseconds_since_epoch: 9223372036854775807
message_count: 0
topics_with_message_count:
[]
compression_format: ""
compression_mode: ""
relative_file_paths:
- rosbag2_2024_12_11-00_42_05_0.db3
files:
- path: rosbag2_2024_12_11-00_42_05_0.db3
starting_time:
nanoseconds_since_epoch: 9223372036854775807
duration:
nanoseconds: 0
message_count: 0
Binary file not shown.
104 changes: 104 additions & 0 deletions yolov8_brake_detection/yolov8_brake_detection/yolov8_node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
from ultralytics import YOLO
import cv2
from std_msgs.msg import String, Float32

class YOLOv8BrakeDetection(Node):
def __init__(self):
super().__init__('yolov8_brake_detection')

# Declare the parameter for the camera topic name
self.declare_parameter('image_topic', '/cameras/camera0')
topic_name = self.get_parameter('image_topic').get_parameter_value().string_value

# Create a subscription to the image topic
self.subscription = self.create_subscription(
Image,
topic_name, # Use the topic name from the parameter
self.image_callback,
10
)

# Publisher for brake detection results (status as string)
self.publisher = self.create_publisher(String, 'brake_detection_results', 10)
# Publisher for confidence score as a float
self.confidence_publisher = self.create_publisher(Float32, 'brake_detection_confidence', 10)

# Initialize CvBridge for converting ROS Image to OpenCV image
self.bridge = CvBridge()

# Load the YOLOv8 model
model_path = '/navigator/ros2_ws/src/yolov8_brake_detection/yolov8_brake_detection/best.pt'
try:
self.get_logger().info(f"Loading YOLO model from: {model_path}")
self.model = YOLO(model_path)
self.get_logger().info("YOLOv8 model loaded successfully.")
except Exception as e:
self.get_logger().error(f"Failed to load YOLOv8 model: {e}")
raise e

def image_callback(self, msg):
try:
# Convert ROS Image message to OpenCV image
cv_image = self.bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8')

# Run inference with YOLOv8
results = self.model(cv_image)

# Process the results (detection boxes, classes, and confidence)
for detection in results:
class_name = detection['class'] # Update as per YOLO's output format
confidence = detection['confidence']

# Publish the brake status
if class_name == 'car_BrakeOn':
self.publish_brake_status("Brake On")
print(f"Detected Brakes On")

elif class_name == 'car_BrakeOff':
self.publish_brake_status("Brake Off")
print(f"Detected Brakes Off")

except Exception as e:
self.get_logger().error(f"Error processing image: {e}")

def publish_brake_status(self, status):
try:
# Publish brake status as a string
message = String()
message.data = status
self.publisher.publish(message)
self.get_logger().info(f"Published brake status: {status}")

except Exception as e:
self.get_logger().error(f"Failed to publish brake status: {e}")

def publish_confidence(self, confidence):
try:
# Publish confidence score as a float
confidence_message = Float32()
confidence_message.data = confidence
self.confidence_publisher.publish(confidence_message)
self.get_logger().info(f"Published confidence: {confidence:.2f}")

except Exception as e:
self.get_logger().error(f"Failed to publish confidence score: {e}")

def main(args=None):
rclpy.init(args=args)

# Initialize the YOLOv8BrakeDetection node
node = YOLOv8BrakeDetection()

# Spin the node to process incoming messages
rclpy.spin(node)

# Clean up and shut down
node.destroy_node()
rclpy.shutdown()

if __name__ == '__main__':
main()

0 comments on commit c0fc708

Please sign in to comment.