Skip to content

Commit

Permalink
Added Build and Test Workflows (#58)
Browse files Browse the repository at this point in the history
* Added build and test workflow

* Corrected IMAGE_NAME varibles in run_devel.sh script

* Corrected pull_requests trigger name

* Removed -it option from docker run & added docker attach step

* Removed PERCEP_WS_PATH environment variable and used github.workspace instead

* Corrected container name in docker run

* Corrected volume mount path

* Removed not required arguments from docker run

* Removed docker attach & used docker exec for colcon build

* Added | character in run for multi-line command

* Added container_name environment variable

* Added jobs for lint and test

* Updated linting job, added matrix for linter

* Added package name field to lint job

* Removed pep8 and mypy linter from action workflows

* Added copyright notice, corrected according to lint

* Updated worflow to pass arguments for linter, made some corrections

* Removed arguments from workflow

* Updated flake8 test to use setup.cfg as the config

* Updated workflow to pass config argument to flake8 lint

* Fixed variable name typo

* Corrected variable used for config path

* Updated lin job to setup ros humble

* Added ros distribution field for lint steps

* Updated flake8 config from default ament_flake8 config

* Added project wide flake8 config file, some more lint corrections
  • Loading branch information
jasmeet0915 authored Feb 8, 2024
1 parent efb16f7 commit 9eb121a
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 205 deletions.
6 changes: 6 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[flake8]
extend-ignore = B902,C816,D100,D101,D102,D103,D104,D105,D106,D107,D203,D212,D404,I202,Q000
import-order-style = google
max-line-length = 125
show-source = true
statistics = true
65 changes: 65 additions & 0 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Build and Test Workflows

on:
pull_request:
branches:
- main
- develop
push:
branches:
- main

jobs:
ament_lint:
name: Lint and Codecheck
runs-on: ubuntu-latest
steps:
- name: Code Checkout
uses: actions/checkout@v4
- name: Setup ROS
uses: ros-tooling/setup-ros@master
- name: Ament Copyright Lint
uses: ros-tooling/action-ros-lint@master
with:
distribution: humble
linter: copyright
package-name: "*"
- name: Ament Flake8 Lint
uses: ros-tooling/action-ros-lint@master
with:
distribution: humble
linter: flake8
package-name: "*"
arguments: '--config=${{ github.workspace }}/.flake8'
- name: Ament PEP257 Lint
uses: ros-tooling/action-ros-lint@master
with:
distribution: humble
linter: pep257
package-name: "*"
- name: Ament xmllint Lint
uses: ros-tooling/action-ros-lint@master
with:
distribution: humble
linter: xmllint
package-name: "*"

build_source:
name: Build Docker Image and ROS 2 Packages
runs-on: ubuntu-latest
env:
CONTAINER_NAME: perception_pipeline
PERCEP_WS: /root/percep_ws
steps:
- name: Code Checkout
uses: actions/checkout@v4
- name: Build Docker Image
run: docker build . --file Dockerfile.ubuntu -t ${{ github.repository }}:latest
- name: Run Docker Image
run: |
docker run -it -d --name $CONTAINER_NAME \
-v ${{ github.workspace }}:$PERCEP_WS/src \
${{ github.repository }}:latest
- name: Build ROS 2 Packages in Container
run: docker exec $CONTAINER_NAME bash -c \
"source /opt/ros/humble/setup.bash && cd $PERCEP_WS && colcon build"
6 changes: 3 additions & 3 deletions docker_scripts/run_devel.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

xhost +local:root

IMAGE_NAME="object_detection"
IMAGE_NAME="perception_pipeline"
IMAGE_TAG="latest"
CONTAINER_NAME="object_detection"
CONTAINER_NAME="perception_pipeline"

# Build the image if it doesn't exist
if docker inspect "$IMAGE_NAME:$IMAGE_TAG" &> /dev/null; then
Expand Down Expand Up @@ -69,4 +69,4 @@ docker run --gpus all --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864
--env CYCLONEDDS_URI=/ddsconfig.xml \
--env="QT_X11_NO_MITSHM=1" \
--env="DISPLAY" \
object_detection:latest
$IMAGE_NAME:$IMAGE_TAG
19 changes: 9 additions & 10 deletions object_detection/launch/object_detection.launch.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Copyright (c) 2018 Intel Corporation
# Copyright (c) 2023 A.T.O.M ROBOTICS
#
# 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
# 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,
Expand All @@ -27,15 +27,14 @@ def generate_launch_description():
'config',
'params.yaml'
)
node=Node(
package = 'object_detection',
name = 'object_detection',
executable = 'ObjectDetection',
parameters = [params],

node = Node(
package='object_detection',
name='object_detection',
executable='ObjectDetection',
parameters=[params],
output="screen",
emulate_tty = True
emulate_tty=True
)


return LaunchDescription([node])
19 changes: 17 additions & 2 deletions object_detection/object_detection/DetectorBase.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
# Copyright (c) 2023 A.T.O.M ROBOTICS
#
# 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 abc import ABC, abstractmethod

import numpy as np


Expand All @@ -17,7 +32,7 @@ def create_predictions_list(self, class_ids, confidences, boxes):
}

self.predictions.append(obj_dict)

@abstractmethod
def build_model(self, model_dir_path: str, weight_file_name: str) -> None:
pass
Expand All @@ -28,4 +43,4 @@ def load_classes(self, model_dir_path: str) -> None:

@abstractmethod
def get_predictions(self, cv_image: np.ndarray) -> list[dict]:
pass
pass
67 changes: 39 additions & 28 deletions object_detection/object_detection/Detectors/RetinaNet.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# Copyright (c) 2023 A.T.O.M ROBOTICS
#
# 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 keras_retinanet import models
Expand All @@ -7,58 +21,55 @@
from ..DetectorBase import DetectorBase


class RetinaNet(DetectorBase) :
def __init(self) :
class RetinaNet(DetectorBase):

def __init(self):
super.__init__()

def build_model(self, model_dir_path, weight_file_name) :
def build_model(self, model_dir_path, weight_file_name):
model_path = os.path.join(model_dir_path, weight_file_name)
try:

try:
self.model = models.load_model(model_path, backbone_name='resnet50')
except:
raise Exception("Error loading given model from path: {}. Maybe the file doesn't exist?".format(model_path))
except Exception as e:
print("Loading the model failed with exception {}".format(e))
raise Exception("Error loading given model from path: {}.".format(model_path) +
"Maybe the file doesn't exist?")

def load_classes(self, model_dir_path) :
def load_classes(self, model_dir_path):
self.class_list = []

with open(model_dir_path + "/classes.txt", "r") as f:
self.class_list = [cname.strip() for cname in f.readlines()]

return self.class_list

def get_predictions(self, cv_image) :
def get_predictions(self, cv_image):
if cv_image is None:
# TODO: show warning message (different color, maybe)
return None

else :

else:
# copy to draw on
self.frame = cv_image.copy()
# preprocess image for network
input = preprocess_image(self.frame)
input, scale = resize_image(input)
processed_img = preprocess_image(self.frame)
processed_img, scale = resize_image(processed_img)

# process image
boxes_all, confidences_all, class_ids_all = self.model.predict_on_batch(np.expand_dims(input, axis=0))
boxes_all, confidences_all, class_ids_all = self.model.predict_on_batch(np.expand_dims(processed_img, axis=0))

boxes, confidences, class_ids = [], [], []
for index in range(len(confidences_all[0])) :
if confidences_all[0][index]!=-1 :

for index in range(len(confidences_all[0])):
if confidences_all[0][index] != -1:
confidences.append(confidences_all[0][index])
boxes.append(boxes_all[0][index])
class_ids.append(class_ids_all[0][index])



# correct for image scale
#boxes = [x/scale for x in boxes]
# boxes = [x/scale for x in boxes]
boxes = [[int(coord/scale) for coord in box] for box in boxes]

super().create_predictions_list(class_ids, confidences, boxes)

return self.predictions


return self.predictions
Loading

0 comments on commit 9eb121a

Please sign in to comment.