├── .gitignore
├── .gitlab-ci.yml
├── CMakeLists.txt
├── Code-Of-Conduct.md
├── Dockerfile
├── FindLibRT.cmake
├── LICENSE
├── README.md
└── src
├── catch.hpp
├── cluon-complete-v0.0.127.hpp
├── opendlv-standard-message-set-v0.9.6.odvd
└── template-opencv.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2022 Christian Berger
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | # Which Docker image shall be used on the GitLab runner?
17 | image: registry.git.chalmers.se/courses/dit638/students/docker/docker:19.03.3
18 |
19 | # Details about how to connect to the Docker service to run this build.
20 | variables:
21 | DOCKER_HOST: tcp://docker:2375
22 | DOCKER_TLS_CERTDIR: ""
23 |
24 | #New
25 | DOCKER_DRIVER: overlay2
26 | DOCKER_BUILDKIT: 1
27 | DOCKER_CLI_EXPERIMENTAL: enabled
28 | BUILDX_URL: https://github.com/docker/buildx/releases/download/v0.3.1/buildx-v0.3.1.linux-amd64
29 | BUILDX_BUILDER: Multiplatform_builder
30 | BUILDX_PLATFORM: linux/amd64,linux/arm64,linux/arm/v7
31 | IMAGE: registry.git.chalmers.se/courses/dit638/students/2022-group-02
32 |
33 |
34 | services:
35 | - name: registry.git.chalmers.se/courses/dit638/students/docker/docker:19.03.3-dind
36 | alias: docker
37 |
38 | stages:
39 | - build
40 | - deploy
41 |
42 | # Display information before we start the build.
43 | before_script:
44 | - docker info
45 | - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
46 |
47 |
48 | # This section describes what shall be done to build and test the project.
49 | build-and-test:
50 | only:
51 | - branches
52 | tags:
53 | - docker-build
54 | stage: build
55 | script:
56 | - docker build -f Dockerfile .
57 |
58 |
59 | # This section describes what shall be done to deploy artefacts from the project.
60 | release:
61 | when: on_success
62 | only:
63 | refs:
64 | - tags
65 | variables:
66 | - $CI_COMMIT_TAG =~ /^v(\d+\.)?(\d+\.)?(\*|\d+)$/
67 | tags:
68 | - docker-build
69 | stage: deploy
70 | before_script:
71 | - mkdir -p $HOME/.docker/cli-plugins/
72 | - wget -O $HOME/.docker/cli-plugins/docker-buildx $BUILDX_URL
73 | - chmod a+x $HOME/.docker/cli-plugins/docker-buildx
74 | - "echo -e '{\n \"experimental\": \"enabled\"\n}' | tee $HOME/.docker/config.json"
75 | - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
76 | - docker buildx create --use --driver docker-container --name ${BUILDX_BUILDER} --platform=${BUILDX_PLATFORM}
77 | - docker buildx inspect --bootstrap ${BUILDX_BUILDER}
78 | - docker buildx ls
79 | - docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}
80 | script:
81 | - docker buildx build --platform=${BUILDX_PLATFORM} -t ${IMAGE}:"$CI_COMMIT_TAG" --push "."
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2020 Christian Berger
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | cmake_minimum_required(VERSION 3.2)
17 |
18 | project(template-opencv)
19 |
20 | ################################################################################
21 | # Defining the relevant versions of OpenDLV Standard Message Set and libcluon.
22 | # The OpenDLV Standard Message Set contains a set of messages usually used in automotive research project.
23 | set(OPENDLV_STANDARD_MESSAGE_SET opendlv-standard-message-set-v0.9.6.odvd)
24 | # libcluon is a small and portable middleware to easily realize high-performance microservices with C++: https://github.com/chrberger/libcluon
25 | set(CLUON_COMPLETE cluon-complete-v0.0.127.hpp)
26 |
27 | ################################################################################
28 | # Set the search path for .cmake files.
29 | set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}" ${CMAKE_MODULE_PATH})
30 |
31 | ################################################################################
32 | # This project requires C++14 or newer.
33 | set(CMAKE_CXX_STANDARD 14)
34 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
35 | set(CMAKE_CXX_EXTENSIONS OFF)
36 | # Build a static binary.
37 | set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
38 | # Add further warning levels to increase the code quality.
39 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \
40 | -D_XOPEN_SOURCE=700 \
41 | -D_FORTIFY_SOURCE=2 \
42 | -O2 \
43 | -fstack-protector \
44 | -fomit-frame-pointer \
45 | -pipe \
46 | -Weffc++ \
47 | -Wall -Wextra -Wshadow -Wdeprecated \
48 | -Wdiv-by-zero -Wfloat-equal -Wfloat-conversion -Wsign-compare -Wpointer-arith \
49 | -Wuninitialized -Wunreachable-code \
50 | -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-but-set-parameter -Wunused-but-set-variable \
51 | -Wunused-value -Wunused-variable -Wunused-result \
52 | -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn")
53 | # Threads are necessary for linking the resulting binaries as the network communication is running inside a thread.
54 | set(THREADS_PREFER_PTHREAD_FLAG ON)
55 | find_package(Threads REQUIRED)
56 |
57 | ################################################################################
58 | # Extract cluon-msc from cluon-complete.hpp.
59 | # cluon-msc is the message compiler that compiles a .odvd message specification into a header-only C++ file.
60 | add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/cluon-msc
61 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
62 | COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/src/${CLUON_COMPLETE} ${CMAKE_BINARY_DIR}/cluon-complete.hpp
63 | COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_BINARY_DIR}/cluon-complete.hpp ${CMAKE_BINARY_DIR}/cluon-complete.cpp
64 | COMMAND ${CMAKE_CXX_COMPILER} -o ${CMAKE_BINARY_DIR}/cluon-msc ${CMAKE_BINARY_DIR}/cluon-complete.cpp -std=c++14 -pthread -D HAVE_CLUON_MSC
65 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/${CLUON_COMPLETE})
66 |
67 | ################################################################################
68 | # Generate opendlv-standard-message-set.hpp from ${OPENDLV_STANDARD_MESSAGE_SET} file.
69 | add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/opendlv-standard-message-set.hpp
70 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
71 | COMMAND ${CMAKE_BINARY_DIR}/cluon-msc --cpp --out=${CMAKE_BINARY_DIR}/opendlv-standard-message-set.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/${OPENDLV_STANDARD_MESSAGE_SET}
72 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/${OPENDLV_STANDARD_MESSAGE_SET} ${CMAKE_BINARY_DIR}/cluon-msc)
73 | # Add current build directory as include directory as it contains generated files.
74 | include_directories(SYSTEM ${CMAKE_BINARY_DIR})
75 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
76 |
77 | ################################################################################
78 | # Gather all object code first to avoid double compilation.
79 | set(LIBRARIES Threads::Threads)
80 |
81 | if(UNIX)
82 | if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
83 | find_package(LibRT REQUIRED)
84 | set(LIBRARIES ${LIBRARIES} ${LIBRT_LIBRARIES})
85 | include_directories(SYSTEM ${LIBRT_INCLUDE_DIR})
86 | endif()
87 | endif()
88 |
89 | # This project uses OpenCV for image processing.
90 | find_package(OpenCV REQUIRED core highgui imgproc)
91 | include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS})
92 | set(LIBRARIES ${LIBRARIES} ${OpenCV_LIBS})
93 |
94 | ################################################################################
95 | # Create executable.
96 | add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/src/${PROJECT_NAME}.cpp)
97 | target_link_libraries(${PROJECT_NAME} ${LIBRARIES})
98 |
99 | # Add dependency to OpenDLV Standard Message Set.
100 | add_custom_target(generate_opendlv_standard_message_set_hpp DEPENDS ${CMAKE_BINARY_DIR}/opendlv-standard-message-set.hpp)
101 | add_dependencies(${PROJECT_NAME} generate_opendlv_standard_message_set_hpp)
102 |
103 | ################################################################################
104 | # Install executable.
105 | install(TARGETS ${PROJECT_NAME} DESTINATION bin COMPONENT ${PROJECT_NAME})
106 |
--------------------------------------------------------------------------------
/Code-Of-Conduct.md:
--------------------------------------------------------------------------------
1 | **How do we plan to collaborate?**
2 |
3 | We are a well knit group that during this project will work all together on all tasks (if possible), this to broaden the individual learning outcome. We plan to avoid splitting up assignments to “save time”, because it has lessened learning outcomes in the past.
4 | Most of our collaboration will take place online and on Discord (or zoom if needed). We prefer to run the code-sessions this way to make it so that all can see and interact (live share or similar software) simultaneously. After these years of distance studies we have developed some working techniques and strategies regarding meeting and other groups related interactions that we find to work well, we intend to use these in this project as well and therefore we will conduct most of our non-programming sessions online as well.
5 | We plan on having planned and set meetings/session slots on Wednesday as well as Fridays, these days suit our individual schedules well and let us put down multiple hour in continuum to not lose the “flow”. We feel that we, as a group, aren't performing at our best with small sessions and rather use long ones so as not to lose the momentum.
6 | As we plan on working together on all assignments we feel that the scrum practises as a whole don’t work for us. For instance would not a scrum meeting make much sense because we intend to all work together on all parts. But we will still use the essence of agile development in this project.
7 |
8 | **How do we ensure that everyone in our group stays informed about the individual Contributions?**
9 |
10 | The majority of the communication between team members, including individual contributions will be through Discord. Individual contributions may be through voice calls during the meetings. Individual contributions may also occur through text communication, which provides an alternative resource to look up previous individual contributions. Every team member is expected to regularly attend voice meetings and check for new text-based messages.
11 | If one or more team members lose access to Discord or are unavailable during meetings, then vital information may be communicated through phone-based messages/calls.
12 |
13 | **How do we ensure knowledge transfer among our team members?**
14 |
15 | Through regular meetings, where every team member is involved, our plan is to jointly develop and produce a solution. Due to team-programming, our gain in knowledge should be equivalent across all team members, primarily since questions and/or progressing through the development phase, may lead to clarifications. Team-programming ensures that knowledge is jointly accumulated.
16 |
17 | **What is our usual communication plan?**
18 |
19 | The plan is to utilize Discord for communication within the team. Both voice and text communication within the group occurs in Discord. If one or more team members miss out on information, then the other team members will communicate the most vital information/summary to that team member. Communication and collaboration occurs primarily online, but in the cases where on-site collaboration is preferred by the team members, or where online collaboration becomes difficult to accomplish, then the collaboration may be shifted towards on-site collaboration, with the possibility to discuss whether any temporary or permanent changes would be made. Currently, on-site collaboration will play a minor role for our group, with the exception for cases mentioned above.
20 |
21 | **How will we solve conflicts?**
22 |
23 | In order to prevent conflicts from occuring, each team member agrees to respect one another, and should avoid conflicts and hostile behavior towards any other team member. By showing respect, and allowing all team members to voice their opinions and concerns, the likelihood of conflicts may be considered reduced to a minimum. As mentioned below, our group prioritizes openness, which includes the ability to speak out on cases of unfair treatment/hostility. Our utmost priority is to make sure that the team members enjoy collaborating together, which also means that our utmost priority is to treat everyone with respect.
24 |
25 | As of yet, no conflicts have occured. The priority of our group is to have ‘openness’ and ‘transparency’ between all team members. Each member is free to voice their opinions, concerns, and views, free of conflicts. We expect each and every team member to act in a respectful manner towards another team member.
26 | In the unexpected case where conflicts do occur, then a discussion between all team members will take place, and where every team member is able to voice their opinion.
27 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2020 Christian Berger
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 | #
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 |
16 | # First stage for building the software:
17 | FROM ubuntu:18.04 as builder
18 | MAINTAINER Christian Berger "christian.berger@gu.se"
19 |
20 | ENV DEBIAN_FRONTEND noninteractive
21 |
22 | # Upgrade the Ubuntu 18.04 LTS base image
23 | RUN apt-get update -y && \
24 | apt-get upgrade -y && \
25 | apt-get dist-upgrade -y
26 |
27 | # Install the development libraries for OpenCV
28 | RUN apt-get install -y --no-install-recommends \
29 | ca-certificates \
30 | cmake \
31 | build-essential \
32 | libopencv-dev
33 |
34 | # Include this source tree and compile the sources
35 | ADD . /opt/sources
36 | WORKDIR /opt/sources
37 | RUN cd /opt/sources && \
38 | mkdir build && \
39 | cd build && \
40 | cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/tmp .. && \
41 | make && make install
42 |
43 |
44 | # Second stage for packaging the software into a software bundle:
45 | FROM ubuntu:18.04
46 | MAINTAINER Christian Berger "christian.berger@gu.se"
47 |
48 | ENV DEBIAN_FRONTEND noninteractive
49 |
50 | RUN apt-get update -y && \
51 | apt-get upgrade -y && \
52 | apt-get dist-upgrade -y
53 |
54 | RUN apt-get install -y --no-install-recommends \
55 | libopencv-core3.2 \
56 | libopencv-highgui3.2 \
57 | libopencv-imgproc3.2
58 |
59 | WORKDIR /usr/bin
60 | COPY --from=builder /tmp/bin/template-opencv .
61 | # This is the entrypoint when starting the Docker container; hence, this Docker image is automatically starting our software on its creation
62 | ENTRYPOINT ["/usr/bin/template-opencv"]
63 |
--------------------------------------------------------------------------------
/FindLibRT.cmake:
--------------------------------------------------------------------------------
1 | # You may redistribute this program and/or modify it under the terms of
2 | # the GNU General Public License as published by the Free Software Foundation,
3 | # either version 3 of the License, or (at your option) any later version.
4 | #
5 | # This program is distributed in the hope that it will be useful,
6 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
7 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8 | # GNU General Public License for more details.
9 | #
10 | # You should have received a copy of the GNU General Public License
11 | # along with this program. If not, see .
12 |
13 | if(NOT LIBRT_FOUND)
14 |
15 | IF(${CMAKE_C_COMPILER} MATCHES "arm")
16 | # We are on ARM.
17 | find_path(LIBRT_INCLUDE_DIR
18 | NAMES
19 | time.h
20 | PATHS
21 | ${LIBRTDIR}/include/
22 | )
23 |
24 | find_file(
25 | LIBRT_LIBRARIES librt.a
26 | PATHS
27 | ${LIBRTDIR}/lib/
28 | /usr/lib/arm-linux-gnueabihf/
29 | /usr/lib/arm-linux-gnueabi/
30 | )
31 | set (LIBRT_DYNAMIC "Using static library.")
32 |
33 | if (NOT LIBRT_LIBRARIES)
34 | find_library(
35 | LIBRT_LIBRARIES rt
36 | PATHS
37 | ${LIBRTDIR}/lib/
38 | /usr/lib/arm-linux-gnueabihf/
39 | /usr/lib/arm-linux-gnueabi/
40 | )
41 | set (LIBRT_DYNAMIC "Using dynamic library.")
42 | endif (NOT LIBRT_LIBRARIES)
43 | ELSE()
44 | IF("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
45 | # We are on x86_64.
46 | find_path(LIBRT_INCLUDE_DIR
47 | NAMES
48 | time.h
49 | PATHS
50 | ${LIBRTDIR}/include/
51 | )
52 |
53 | find_file(
54 | LIBRT_LIBRARIES librt.a
55 | PATHS
56 | ${LIBRTDIR}/lib/
57 | /usr/lib/x86_64-linux-gnu/
58 | /usr/local/lib64/
59 | /usr/lib64/
60 | /usr/lib/
61 | )
62 | set (LIBRT_DYNAMIC "Using static library.")
63 |
64 | if (NOT LIBRT_LIBRARIES)
65 | find_library(
66 | LIBRT_LIBRARIES rt
67 | PATHS
68 | ${LIBRTDIR}/lib/
69 | /usr/lib/x86_64-linux-gnu/
70 | /usr/local/lib64/
71 | /usr/lib64/
72 | /usr/lib/
73 | )
74 | set (LIBRT_DYNAMIC "Using dynamic library.")
75 | endif (NOT LIBRT_LIBRARIES)
76 | ELSE()
77 | # We are on x86.
78 | find_path(LIBRT_INCLUDE_DIR
79 | NAMES
80 | time.h
81 | PATHS
82 | ${LIBRTDIR}/include/
83 | )
84 |
85 | find_file(
86 | LIBRT_LIBRARIES librt.a
87 | PATHS
88 | ${LIBRTDIR}/lib/
89 | /usr/lib/i386-linux-gnu/
90 | /usr/local/lib/
91 | /usr/lib/
92 | )
93 | set (LIBRT_DYNAMIC "Using static library.")
94 |
95 | if (NOT LIBRT_LIBRARIES)
96 | find_library(
97 | LIBRT_LIBRARIES rt
98 | PATHS
99 | ${LIBRTDIR}/lib/
100 | /usr/lib/i386-linux-gnu/
101 | /usr/local/lib/
102 | /usr/lib/
103 | )
104 | set (LIBRT_DYNAMIC "Using dynamic library.")
105 | endif (NOT LIBRT_LIBRARIES)
106 | ENDIF()
107 | ENDIF()
108 |
109 | if (LIBRT_INCLUDE_DIR AND LIBRT_LIBRARIES)
110 | set (LIBRT_FOUND TRUE)
111 | endif (LIBRT_INCLUDE_DIR AND LIBRT_LIBRARIES)
112 |
113 | if (LIBRT_FOUND)
114 | message(STATUS "Found librt: ${LIBRT_INCLUDE_DIR}, ${LIBRT_LIBRARIES} ${LIBRT_DYNAMIC}")
115 | else (LIBRT_FOUND)
116 | if (Librt_FIND_REQUIRED)
117 | message (FATAL_ERROR "Could not find librt, try to setup LIBRT_PREFIX accordingly")
118 | endif (Librt_FIND_REQUIRED)
119 | endif (LIBRT_FOUND)
120 |
121 | endif (NOT LIBRT_FOUND)
122 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [2022] [Group 2]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 2022-group-02 | Algorithm for steering wheel angle
2 |
3 | ## Description
4 |
5 | This algorithm is data driven and is integrated with [opendlv-vehicle-view](https://github.com/chalmers-revere/opendlv-vehicle-view). The algorithm uses object detection in the data from the video feed from [opendlv-vehicle-view](https://github.com/chalmers-revere/opendlv-vehicle-view) along side with other sensor readings to compute an accurate steering angle output close to what the actual steering wheel angle was at the time of the video feed.
6 |
7 |
8 | ## Installation
9 | Latest release:
10 |
11 | 
12 |
13 | ## Usage
14 | The system is ran alongside with [opendlv-vehicle-view](https://github.com/chalmers-revere/opendlv-vehicle-view) and [h264decoder](https://github.com/chalmers-revere/opendlv-video-h264-decoder) (to extract h264 frames into a shared memory area to provide access to ARGB pixels in the frames). By using shared memory, the system is able to detect cones of different color and detemine the heading direction including the needed steering wheel angles for the wheels.
15 |
16 | The algorithm produces an output in the terminal for each video frame containing the sample timestamp together with the calculated steering wheel angle.
17 |
18 |
19 | ## Authors and acknowledgment
20 | **Authors and contributors:**
21 |
22 |
Caisesiume [(GitHub)](https://github.com/Caisesiume) [(GitLab)](https://git.chalmers.se/simonar)
23 |
24 |
JohanAxell [(GitHub)](https://github.com/johanaxell) [(GitLab)](https://git.chalmers.se/johanaxe)
25 |
26 |
Jidarv [(GitHub)](https://github.com/Jidarv)[(GitLab)](https://git.chalmers.se/jidarv)
27 |
28 |
RobbanGit [(GitHub)](https://github.com/RobbanGit) [(GitLab)](https://git.chalmers.se/robinhan)
29 |
30 |
Asiya [(GitHub)](https://github.com/Asiya-Ismail)[(GitLab)](https://git.chalmers.se/asiya)
31 |
32 | **Acknowledgment:**
33 |
34 | Thanks to University of Gothenburg, Chalmers University of Technology and Christian Berger for setting up this project possiblility.
35 |
36 |
37 | ## License
38 | For this project a [MIT License](https://git.chalmers.se/courses/dit638/students/2022-group-02/-/blob/main/LICENSE) applies.
39 |
40 | ## Project status
41 | The current project state:
42 |
43 | The project development is in its ending phase. There might only be occational updates to this repository.
44 |
45 |
46 | ## Collaboration with the team members
47 |
48 | See Code-of-Conduct.
49 |
50 |
--------------------------------------------------------------------------------
/src/opendlv-standard-message-set-v0.9.6.odvd:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Chalmers Revere
3 | *
4 | * This program is free software; you can redistribute it and/or
5 | * modify it under the terms of the GNU General Public License
6 | * as published by the Free Software Foundation; either version 2
7 | * of the License, or (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program; if not, write to the Free Software
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 | */
18 |
19 | message opendlv.sim.Frame [id = 1001] {
20 | float x [id = 1];
21 | float y [id = 2];
22 | float z [id = 3];
23 | float roll [id = 4];
24 | float pitch [id = 5];
25 | float yaw [id = 6];
26 | }
27 |
28 | message opendlv.sim.KinematicState [id = 1002] {
29 | float vx [id = 1];
30 | float vy [id = 2];
31 | float vz [id = 3];
32 | float rollRate [id = 4];
33 | float pitchRate [id = 5];
34 | float yawRate [id = 6];
35 | }
36 |
37 | message opendlv.body.ComponentInfo [id = 1021] {
38 | string description [id = 1];
39 | float x [id = 2];
40 | float y [id = 3];
41 | float z [id = 4];
42 | }
43 |
44 | message opendlv.body.ActuatorInfo [id = 1022] {
45 | string description [id = 1];
46 | float x [id = 2];
47 | float y [id = 3];
48 | float z [id = 4];
49 | uint32 signalId [id = 5];
50 | float minValue [id = 6];
51 | float maxValue [id = 7];
52 | }
53 |
54 | message opendlv.body.SensorInfo [id = 1023] {
55 | string description [id = 1];
56 | float x [id = 2];
57 | float y [id = 3];
58 | float z [id = 4];
59 | uint32 signalId [id = 5];
60 | float accuracyStd [id = 6];
61 | uint16 minFrequency [id = 7];
62 | }
63 |
64 | message opendlv.body.SignalInfo [id = 1024] {
65 | string description [id = 1];
66 | uint32 signalId [id = 2];
67 | float accuracyStd [id = 3];
68 | uint16 minFrequency [id = 4];
69 | }
70 |
71 | message opendlv.proxy.AccelerationReading [id = 1030] {
72 | float accelerationX [id = 1];
73 | float accelerationY [id = 2];
74 | float accelerationZ [id = 3];
75 | }
76 |
77 | message opendlv.proxy.AngularVelocityReading [id = 1031] {
78 | float angularVelocityX [id = 1];
79 | float angularVelocityY [id = 2];
80 | float angularVelocityZ [id = 3];
81 | }
82 |
83 | message opendlv.proxy.MagneticFieldReading [id = 1032] {
84 | float magneticFieldX [id = 1];
85 | float magneticFieldY [id = 2];
86 | float magneticFieldZ [id = 3];
87 | }
88 |
89 | message opendlv.proxy.AltitudeReading [id = 1033] {
90 | float altitude [id = 1];
91 | }
92 |
93 | message opendlv.proxy.PressureReading [id = 1034] {
94 | float pressure [id = 1];
95 | }
96 |
97 | message opendlv.proxy.TemperatureReading [id = 1035] {
98 | float temperature [id = 1];
99 | }
100 |
101 | message opendlv.proxy.TorqueReading [id = 1036] {
102 | float torque [id = 1];
103 | }
104 |
105 | message opendlv.proxy.VoltageReading [id = 1037] {
106 | float voltage [id = 1];
107 | }
108 |
109 | message opendlv.proxy.AngleReading [id = 1038] {
110 | float angle [id = 1];
111 | }
112 |
113 | message opendlv.proxy.DistanceReading [id = 1039] {
114 | float distance [id = 1];
115 | }
116 |
117 | message opendlv.proxy.SwitchStateReading [id = 1040] {
118 | int16 state [id = 1];
119 | }
120 |
121 | message opendlv.proxy.PedalPositionReading [id = 1041] {
122 | float position [id = 1];
123 | }
124 |
125 | message opendlv.proxy.GroundSteeringReading [id = 1045] {
126 | float groundSteering [id = 1];
127 | }
128 |
129 | message opendlv.proxy.GroundSpeedReading [id = 1046] {
130 | float groundSpeed [id = 1];
131 | }
132 |
133 | message opendlv.proxy.WheelSpeedReading [id = 1047] {
134 | float wheelSpeed [id = 1];
135 | }
136 |
137 | message opendlv.proxy.WeightReading [id = 1050] {
138 | float weight [id = 1];
139 | }
140 |
141 | message opendlv.proxy.GeodeticHeadingReading [id = 1051] {
142 | float northHeading [id = 1];
143 | }
144 |
145 | message opendlv.proxy.GeodeticWgs84Reading [id = 19] {
146 | double latitude [id = 1];
147 | double longitude [id = 3];
148 | }
149 |
150 | message opendlv.proxy.ImageReading [id = 1055] {
151 | string fourcc [id = 1];
152 | uint32 width [id = 2];
153 | uint32 height [id = 3];
154 | bytes data [id = 4];
155 | }
156 |
157 | message opendlv.proxy.ImageReadingShared [id = 14] {
158 | string name [id = 1];
159 | uint32 size [id = 2];
160 | uint32 width [id = 3];
161 | uint32 height [id = 4];
162 | uint32 bytesPerPixel [id = 5];
163 | }
164 |
165 | message opendlv.proxy.PointCloudReading [id = 49] {
166 | float startAzimuth [id = 1];
167 | float endAzimuth [id = 2];
168 | uint8 entriesPerAzimuth [id = 3];
169 | bytes distances [id = 4];
170 | uint8 numberOfBitsForIntensity [id = 5];
171 | }
172 |
173 | message opendlv.proxy.PointCloudReadingShared [id = 28] {
174 | string name [id = 1];
175 | uint32 size [id = 2];
176 | uint32 width [id = 3];
177 | uint32 height [id = 4];
178 | uint8 numberOfComponentsPerPoint [id = 5];
179 | }
180 |
181 | // V2xReading?
182 |
183 |
184 | message opendlv.proxy.PressureRequest [id = 1080] {
185 | float pressure [id = 1];
186 | }
187 |
188 | message opendlv.proxy.TemperatureRequest [id = 1081] {
189 | float temperature [id = 1];
190 | }
191 |
192 | message opendlv.proxy.TorqueRequest [id = 1082] {
193 | float torque [id = 1];
194 | }
195 |
196 | message opendlv.proxy.VoltageRequest [id = 1083] {
197 | float voltage [id = 1];
198 | }
199 |
200 | message opendlv.proxy.AngleRequest [id = 1084] {
201 | float angle [id = 1];
202 | }
203 |
204 | message opendlv.proxy.SwitchStateRequest [id = 1085] {
205 | int16 state [id = 1];
206 | }
207 |
208 | message opendlv.proxy.PedalPositionRequest [id = 1086] {
209 | float position [id = 1];
210 | }
211 |
212 | message opendlv.proxy.PulseWidthModulationRequest [id = 1087] {
213 | uint32 dutyCycleNs [id = 1];
214 | }
215 |
216 | message opendlv.proxy.GroundSteeringRequest [id = 1090] {
217 | float groundSteering [id = 1];
218 | }
219 |
220 | message opendlv.proxy.GroundSpeedRequest [id = 1091] {
221 | float groundSpeed [id = 1];
222 | }
223 |
224 | message opendlv.proxy.GroundAccelerationRequest [id = 1092] {
225 | float groundAcceleration [id = 1];
226 | }
227 |
228 | message opendlv.proxy.GroundDecelerationRequest [id = 1093] {
229 | float groundDeceleration [id = 1];
230 | }
231 |
232 | message opendlv.proxy.WheelSpeedRequest [id = 1094] {
233 | float wheelSpeed [id = 1];
234 | }
235 |
236 | // V2xRequest?
237 |
238 |
239 | message opendlv.system.SignalStatusMessage [id = 1100] {
240 | int32 code [id = 1];
241 | string description [id = 2];
242 | }
243 |
244 | message opendlv.system.SystemOperationState [id = 1101] {
245 | int32 code [id = 1];
246 | string description [id = 2];
247 | }
248 |
249 | message opendlv.system.NetworkStatusMessage [id = 1102] {
250 | int32 code [id = 1];
251 | string description [id = 2];
252 | }
253 |
254 |
255 |
256 | message opendlv.logic.sensation.Direction [id = 1110] {
257 | float azimuthAngle [id = 1];
258 | float zenithAngle [id = 2];
259 | }
260 |
261 | message opendlv.logic.sensation.Point [id = 1111] {
262 | float azimuthAngle [id = 1];
263 | float zenithAngle [id = 2];
264 | float distance [id = 3];
265 | }
266 |
267 | message opendlv.logic.sensation.Geolocation [id = 1116] {
268 | double latitude [id = 1];
269 | double longitude [id = 2];
270 | float altitude [id = 3];
271 | float heading [id = 4];
272 | }
273 |
274 | message opendlv.logic.sensation.Equilibrioception [id = 1017] {
275 | float vx [id = 1];
276 | float vy [id = 2];
277 | float vz [id = 3];
278 | float rollRate [id = 4];
279 | float pitchRate [id = 5];
280 | float yawRate [id = 6];
281 | }
282 |
283 |
284 |
285 | message opendlv.logic.perception.Object [id = 1130] {
286 | uint32 objectId [id = 1];
287 | }
288 |
289 | message opendlv.logic.perception.ObjectType [id = 1131] {
290 | uint32 objectId [id = 1];
291 | uint32 type [id = 2];
292 | }
293 |
294 | message opendlv.logic.perception.ObjectProperty [id = 1132] {
295 | uint32 objectId [id = 1];
296 | string property [id = 2];
297 | }
298 |
299 | message opendlv.logic.perception.ObjectDirection [id = 1133] {
300 | uint32 objectId [id = 1];
301 | float azimuthAngle [id = 2];
302 | float zenithAngle [id = 3];
303 | }
304 |
305 | message opendlv.logic.perception.ObjectDistance [id = 1134] {
306 | uint32 objectId [id = 1];
307 | float distance [id = 2];
308 | }
309 |
310 | message opendlv.logic.perception.ObjectAngularBlob [id = 1135] {
311 | uint32 objectId [id = 1];
312 | float width [id = 2];
313 | float height [id = 3];
314 | }
315 |
316 | message opendlv.logic.perception.GroundSurface [id = 1140] {
317 | uint32 surfaceId [id = 1];
318 | }
319 |
320 | message opendlv.logic.perception.GroundSurfaceType [id = 1141] {
321 | uint32 surfaceId [id = 1];
322 | uint32 type [id = 2];
323 | }
324 |
325 | message opendlv.logic.perception.GroundSurfaceProperty [id = 1142] {
326 | uint32 surfaceId [id = 1];
327 | string property [id = 2];
328 | }
329 |
330 | message opendlv.logic.perception.GroundSurfaceArea [id = 1143] {
331 | uint32 surfaceId [id = 1];
332 | float x1 [id = 2];
333 | float y1 [id = 3];
334 | float x2 [id = 4];
335 | float y2 [id = 5];
336 | float x3 [id = 6];
337 | float y3 [id = 7];
338 | float x4 [id = 8];
339 | float y4 [id = 9];
340 | }
341 |
342 |
343 | message opendlv.logic.action.AimDirection [id = 1171] {
344 | float azimuthAngle [id = 1];
345 | float zenithAngle [id = 2];
346 | }
347 |
348 | message opendlv.logic.action.AimPoint [id = 1172] {
349 | float azimuthAngle [id = 1];
350 | float zenithAngle [id = 2];
351 | float distance [id = 3];
352 | }
353 |
354 | message opendlv.logic.action.PreviewPoint [id = 1173] {
355 | float azimuthAngle [id = 1];
356 | float zenithAngle [id = 2];
357 | float distance [id = 3];
358 | }
359 |
360 | message opendlv.logic.cognition.GroundSteeringLimit [id = 1191] {
361 | float steeringLimit [id = 1];
362 | }
363 |
364 | message opendlv.logic.cognition.GroundSpeedLimit [id = 1192] {
365 | float speedLimit [id = 1];
366 | }
367 |
--------------------------------------------------------------------------------
/src/template-opencv.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2020 Christian Berger
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | // Include the single-file, header-only middleware libcluon to create high-performance microservices
19 | #include "cluon-complete.hpp"
20 | // Include the OpenDLV Standard Message Set that contains messages that are usually exchanged for automotive or robotic applications
21 | #include "opendlv-standard-message-set.hpp"
22 |
23 | // Include the GUI and image processing header files from OpenCV
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | auto calculateSteering(double rightIR, double leftIR, int rightCones, int leftCones, double steering)
31 | {
32 | double incrementSteering = 0.045;
33 | steering = 0;
34 |
35 | if (rightIR <= 0.007)
36 | {
37 | steering = steering + incrementSteering;
38 | }
39 | if (leftIR <= 0.007)
40 | {
41 | steering = steering - incrementSteering;
42 | }
43 |
44 | if (rightCones == 0)
45 | {
46 | steering = -0.15;
47 | }
48 | if (leftCones == 0)
49 | {
50 | steering = 0.15;
51 | }
52 | return steering;
53 | }
54 |
55 | int32_t main(int32_t argc, char **argv)
56 | {
57 | int32_t retCode{1};
58 | int yellowCones = 6;
59 | int blueCones = 0;
60 | double leftIR;
61 | double rightIR;
62 | double steering = 0.0;
63 | int directionEstablished = 0;
64 | std::string carDirection;
65 | int numberClockwise = 0;
66 | int numberCounterclockwise = 0;
67 |
68 |
69 |
70 | // Parse the command line parameters as we require the user to specify some mandatory information on startup.
71 | auto commandlineArguments = cluon::getCommandlineArguments(argc, argv);
72 | if ((0 == commandlineArguments.count("cid")) ||
73 | (0 == commandlineArguments.count("name")) ||
74 | (0 == commandlineArguments.count("width")) ||
75 | (0 == commandlineArguments.count("height")))
76 | {
77 | std::cerr << argv[0] << " attaches to a shared memory area containing an ARGB image." << std::endl;
78 | std::cerr << "Usage: " << argv[0] << " --cid= --name= [--verbose]" << std::endl;
79 | std::cerr << " --cid: CID of the OD4Session to send and receive messages" << std::endl;
80 | std::cerr << " --name: name of the shared memory area to attach" << std::endl;
81 | std::cerr << " --width: width of the frame" << std::endl;
82 | std::cerr << " --height: height of the frame" << std::endl;
83 | std::cerr << "Example: " << argv[0] << " --cid=253 --name=img --width=640 --height=480 --verbose" << std::endl;
84 | }
85 | else
86 | {
87 | // Extract the values from the command line parameters
88 | const std::string NAME{commandlineArguments["name"]};
89 | const uint32_t WIDTH{static_cast(std::stoi(commandlineArguments["width"]))};
90 | const uint32_t HEIGHT{static_cast(std::stoi(commandlineArguments["height"]))};
91 | const bool VERBOSE{commandlineArguments.count("verbose") != 0};
92 |
93 | // Attach to the shared memory.
94 | std::unique_ptr sharedMemory{new cluon::SharedMemory{NAME}};
95 | if (sharedMemory && sharedMemory->valid())
96 | {
97 | std::clog << argv[0] << ": Attached to shared memory '" << sharedMemory->name() << " (" << sharedMemory->size() << " bytes)." << std::endl;
98 |
99 | // Interface to a running OpenDaVINCI session where network messages are exchanged.
100 | // The instance od4 allows you to send and receive messages.
101 | cluon::OD4Session od4{static_cast(std::stoi(commandlineArguments["cid"]))};
102 |
103 | opendlv::proxy::GroundSteeringRequest gsr;
104 | opendlv::proxy::VoltageReading infrared;
105 | std::mutex infraredMutex;
106 | std::mutex gsrMutex;
107 | auto onGroundSteeringRequest = [&gsr, &gsrMutex](cluon::data::Envelope &&env)
108 | {
109 | // The envelope data structure provide further details, such as sampleTimePoint as shown in this test case:
110 | // https://github.com/chrberger/libcluon/blob/master/libcluon/testsuites/TestEnvelopeConverter.cpp#L31-L40
111 | std::lock_guard lck(gsrMutex);
112 | gsr = cluon::extractMessage(std::move(env));
113 | };
114 | od4.dataTrigger(opendlv::proxy::GroundSteeringRequest::ID(), onGroundSteeringRequest);
115 |
116 | ///Infrared sensor
117 |
118 | auto onVoltageReading = [&infrared, &infraredMutex, &rightIR, &leftIR, &yellowCones, &blueCones, &steering](cluon::data::Envelope &&env)
119 | {
120 | std::lock_guard lck(infraredMutex);
121 | infrared = cluon::extractMessage(std::move(env));
122 | if (env.senderStamp() == 3)
123 | {
124 | rightIR = infrared.voltage();
125 | }
126 | else if (env.senderStamp() == 1)
127 | {
128 | leftIR = infrared.voltage();
129 | }
130 | };
131 |
132 | od4.dataTrigger(opendlv::proxy::VoltageReading::ID(), onVoltageReading);
133 |
134 | // Endless loop; end the program by pressing Ctrl-C.
135 | while (od4.isRunning())
136 | {
137 | // OpenCV data structure to hold an image.
138 | cv::Mat img;
139 |
140 | // Wait for a notification of a new frame.
141 | sharedMemory->wait();
142 |
143 | // Lock the shared memory.
144 | sharedMemory->lock();
145 | {
146 | // Copy the pixels from the shared memory into our own data structure.
147 | cv::Mat wrapped(HEIGHT, WIDTH, CV_8UC4, sharedMemory->data());
148 | img = wrapped.clone();
149 | }
150 |
151 | std::pair pair = sharedMemory->getTimeStamp();
152 | cluon::data::TimeStamp sampleT = pair.second;
153 | int64_t tStamp = cluon::time::toMicroseconds(sampleT);
154 | std::string ts = std::to_string(tStamp);
155 | std::string sampleTimeVar = "Sample Time: " + ts;
156 | sharedMemory->unlock();
157 |
158 |
159 |
160 | // HSV values reference: https://www.codespeedy.com/splitting-rgb-and-hsv-values-in-an-image-using-opencv-python/
161 | // Solution partly inspired by: https://stackoverflow.com/questions/9018906/detect-rgb-color-interval-with-opencv-and-c
162 | // AND: https://solarianprogrammer.com/2015/05/08/detect-red-circles-image-using-opencv/
163 |
164 | // Cone color detection
165 |
166 | using namespace cv;
167 | using namespace std;
168 |
169 | cv::Mat originalImg;
170 | img.copyTo(originalImg);
171 |
172 | cv::Mat hsvIMG;
173 | img.copyTo(hsvIMG);
174 |
175 | // Draw box around unnecessary part of car(to avoid conflicts with inrange below)
176 | cv::rectangle(img, cv::Point(150, 385), cv::Point(500, 500), cv::Scalar(0, 0, 0), CV_FILLED);
177 | // Draw box in region above cones, to avoid conflicts with irrelevant objects.
178 | cv::rectangle(img, cv::Point(0, 0), cv::Point(650, 250), cv::Scalar(0, 0, 0), CV_FILLED);
179 |
180 | cv::cvtColor(img, hsvIMG, cv::COLOR_BGR2HSV);
181 |
182 | cv::Mat justYellowColor;
183 | cv::Mat justYellowColor2;
184 | cv::Mat justBlueColor;
185 |
186 | inRange(hsvIMG, cv::Scalar(12, 20, 20), cv::Scalar(70, 100, 250), justYellowColor); // Yellow(low, high) - Yellow cones
187 | inRange(hsvIMG, cv::Scalar(8, 20, 20), cv::Scalar(11, 100, 250), justYellowColor2); // Yellow(low, high) - Yellow cones copy for lower ranges
188 | inRange(hsvIMG, cv::Scalar(80, 125, 8), cv::Scalar(135, 255, 210), justBlueColor); // Blue(low, high) - Blue cones
189 |
190 | justYellowColor = justYellowColor | justYellowColor2;
191 |
192 | cv::Rect bounding_rect;
193 | vector> yellowcontours; // Vector for storing yellow contours
194 | vector> bluecontours; // Vector for storing blue contours
195 | cv::findContours(justBlueColor, bluecontours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
196 | cv::findContours(justYellowColor, yellowcontours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
197 |
198 |
199 |
200 | cv::Rect boundRectangleYellow;
201 | cv::Rect boundRectangleBlue;
202 |
203 | cv::Rect largestboundRectangleBlue;
204 | cv::Rect largestboundRectangleYellow;
205 |
206 | int amountOfYellowCones = 0;
207 | int amountOfBlueCones = 0;
208 |
209 | int largestAreaYellow = 0;
210 | int largestAreaBlue = 0;
211 |
212 | for (unsigned int i = 0; i < bluecontours.size(); i++)
213 | {
214 | boundRectangleBlue = cv::boundingRect(bluecontours[i]);
215 | if (boundRectangleBlue.area() > 80)
216 | {
217 | cv::rectangle(img, boundRectangleBlue.tl(), boundRectangleBlue.br(), cv::Scalar(0, 255, 0), 3); //<-- Light green rectangles
218 |
219 | if (boundRectangleBlue.area() > largestAreaBlue)
220 | {
221 | largestAreaBlue = boundRectangleBlue.area();
222 | largestboundRectangleBlue = cv::boundingRect(bluecontours[i]);
223 | }
224 |
225 | if (boundRectangleBlue.area() > 120)
226 | {
227 | amountOfBlueCones += 1;
228 | }
229 | }
230 | }
231 |
232 | for (unsigned int i = 0; i < yellowcontours.size(); i++)
233 | {
234 | boundRectangleYellow = cv::boundingRect(yellowcontours[i]);
235 | if (boundRectangleYellow.area() > 80)
236 | {
237 |
238 | cv::rectangle(img, boundRectangleYellow.tl(), boundRectangleYellow.br(), cv::Scalar(6, 82, 58), 3); //<-- Dark green rectangles
239 |
240 | if (boundRectangleYellow.area() > largestAreaYellow)
241 | {
242 | largestAreaYellow = boundRectangleYellow.area();
243 | largestboundRectangleYellow = cv::boundingRect(yellowcontours[i]);
244 | }
245 |
246 | if (boundRectangleYellow.area() > 120)
247 | {
248 | amountOfYellowCones += 1;
249 | }
250 | }
251 | }
252 |
253 | if (directionEstablished < 10 && (largestboundRectangleBlue.x != 0) && (boundRectangleYellow.x != 0))
254 | {
255 | if (largestboundRectangleBlue.x < largestboundRectangleYellow.x)
256 | {
257 | numberClockwise++;
258 | }
259 | else if (largestboundRectangleBlue.x > largestboundRectangleYellow.x)
260 | {
261 | numberCounterclockwise++;
262 | }
263 |
264 | if (numberClockwise > numberCounterclockwise)
265 | {
266 | carDirection = "Clockwise";
267 | }
268 | else if (numberCounterclockwise > numberClockwise)
269 | {
270 | carDirection = "Counter-Clockwise";
271 | }
272 |
273 | directionEstablished++;
274 | }
275 |
276 | if (carDirection == "Clockwise")
277 | {
278 | steering = calculateSteering(rightIR, leftIR, amountOfYellowCones, amountOfBlueCones, steering);
279 | }
280 | if (carDirection == "Counter-Clockwise")
281 | {
282 | steering = calculateSteering(rightIR, leftIR, amountOfBlueCones, amountOfYellowCones, steering);
283 | }
284 | std::cout << "Group_02;" << tStamp << ";" << steering << std::endl;
285 |
286 | cv::rectangle(img, cv::Point(50, 50), cv::Point(100, 100), cv::Scalar(0, 0, 255));
287 |
288 | {
289 | std::lock_guard lck(gsrMutex);
290 |
291 | }
292 |
293 |
294 | if (VERBOSE)
295 | {
296 | cv::imshow(sharedMemory->name().c_str(), img);
297 | cv::waitKey(1);
298 | }
299 | }
300 | }
301 | retCode = 0;
302 | }
303 | return retCode;
304 | }
305 |
--------------------------------------------------------------------------------