지금 하고 있는 프로젝트에서 unity를 이용해서 진행하기로 하였다.
Unity에 있는 가상 카메라로 카메라 정보를 받아 이를 처리하는 방식인데,, 문제는 Unity는 C#을 베이스로 만들어진 툴이기 때문에 다른 언어로 만든 코드를 script로 넣어줄수가 없었다. 그리고 무엇보다도.. 내가 C#을 다뤄본적이 별로 없어서.. python으로 카메라 이미지를 보내줄 수 있는 방법을 찾아보았다.
우선 여러가지 방법을 찾았다. 그렇지만 기왕 ubuntu환경에서 하기로 한거, 한번 rosbridge를 이용해서 해보려고 한다.
rosbridge는 ros와 다른 tool을 이어주는 말 그대로 bridge이다. IoT를 공부하다보면 bridge기기라는게 나오는데, 센서와 엑추에이터 사이를 이어주는 역할을 해준다. 
rosbridge의 경우 나한테 조금은 친숙하다. 마카롱에서 나간 모라이 대회가 똑같이 rosbridge를 통해 ros와 모라이가 통신할 수 있도록 했었다. 이때 디버깅 하면서 조금 공부해 둔게 있기도 하고... 그나마 친숙한 rosbridge를 사용하기로 하였다...
근데..? ROS-Unity통신 관련 자료 왜이리 없냐... 날 너무 힘들게 한 아이.. 그치만 해치웠지.. 후후후...

rosbridge 설치하기

sudo apt-get install ros-noetic-rosbridge-server

rosbridge를 설치해주면 다음은 path를 지정해 주면된다.

source /opt/ros/noetic/setup.bash

그 다음은 로스브릿지 런치파일을 실행해주면 되는데... 이부분은 모라이 할때 단축어 해둔게 있어서 나는 편했다.

roslaunch rosbridge_server rosbridge_websocket.launch

그 다음 내 IP주소를 찾아내야 하는데, 이때 ifconfig를 통해 찾아도 되지만, 나는 그냥 localhost:9090으로 진행하였다.
모라이할 때 실험해보니.. 이게 제일 편하드라고..
자 이렇게 하면 rosbridge의 준비는 끝난다. 이제 unity로 넘어가보자
 

Unity에서 topic publish해주기

우선, Unity에 ROS# 패키지를 install해주어야 한다. Unity내에서 패키지를 찾아서 Assets에 넣는 방법도 있지만.. 뭔가 지금 내가 사용하고 있는 unity버전이 정상적인 버전은 절대 아닌것같아.. git을 이용한 방법으로 소개를 하겠다... (unity깔다가 내 ubuntu 맛탱이 가버렸다.. 나 우분투에서 한글 안쳐짐.. 이상하게 C드라이브에 접근할 수 있어지고.. 개발 환경도 좀 많이 바뀜.. 뭔가를 단단히 잘못한 듯.. ㅠㅠ)
home에 아래 git을 clone 받아주면 된다.

git clone https://github.com/siemens/ros-sharp.git

clone이 다 받아졌다면 사용하고자 하는 프로젝트 Assets에 드래그 해주면 된다. 쉽죠?
이제 ros에 접근할 수 있게 된다. 
여기서 잠깐..!!
Test1/Assets/RosSharp/Scripts/RosBridgeClient/RosCommuncation/에 들어가면 RosConnector.cs파일이 있다.
기본적으로 토픽으로 보낼 모든 센서에 이 RosConnector script를 넣어줘야 하기 때문에, 미리 수정해서 시작하면 편하다.
이 파일을 열어보면, 아래와 같다.

/*
© Siemens AG, 2017-2019
Author: Dr. Martin Bischoff (martin.bischoff@siemens.com)

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.
*/

using System;
using System.Threading;
using RosSharp.RosBridgeClient.Protocols;
using UnityEngine;

namespace RosSharp.RosBridgeClient
{
    public class RosConnector : MonoBehaviour
    {
        public int SecondsTimeout = 10;

        public RosSocket RosSocket { get; private set; }
        public RosSocket.SerializerEnum Serializer;
        public Protocol protocol;
        public string RosBridgeServerUrl = "ws://192.168.219.169:9090";

        public ManualResetEvent IsConnected { get; private set; }

        public virtual void Awake()
        {
            IsConnected = new ManualResetEvent(false);
            new Thread(ConnectAndWait).Start();
        }

        protected void ConnectAndWait()
        {
            RosSocket = ConnectToRos(protocol, RosBridgeServerUrl, OnConnected, OnClosed, Serializer);

            if (!IsConnected.WaitOne(SecondsTimeout * 1000))
                Debug.LogWarning("Failed to connect to RosBridge at: " + RosBridgeServerUrl);
        }

        public static RosSocket ConnectToRos(Protocol protocolType, string serverUrl, EventHandler onConnected = null, EventHandler onClosed = null, RosSocket.SerializerEnum serializer = RosSocket.SerializerEnum.Microsoft)
        {
            IProtocol protocol = ProtocolInitializer.GetProtocol(protocolType, serverUrl);
            protocol.OnConnected += onConnected;
            protocol.OnClosed += onClosed;

            return new RosSocket(protocol, serializer);
        }

        private void OnApplicationQuit()
        {
            RosSocket.Close();
        }

        private void OnConnected(object sender, EventArgs e)
        {
            IsConnected.Set();
            Debug.Log("Connected to RosBridge: " + RosBridgeServerUrl);
        }

        private void OnClosed(object sender, EventArgs e)
        {
            IsConnected.Reset();
            Debug.Log("Disconnected from RosBridge: " + RosBridgeServerUrl);
        }
    }
}

여기서 크게 바꿔줘야 할 부분은 없지만.. 나는 로컬 환경에서 진행하기로 하였으니, IP주소를 조금 바꿔주려고 한다.
코드의 32번째 줄의 ip주소를 아래와 같이 바꿔주면, 앞으로 script import할 때마다 주소를 바꿔주는 수고를 덜 수 있다.

public string RosBridgeServerUrl = "ws://localhost:9090";
여기서 하나!!
IP주소를 공부하다보면 정말 많이 헷갈린다.. ifconfig를 치면 내 IP Address를 알 수 있다는건 코딩을 하는 모두가 아는 사실일 것이다. 그런데..! 사실 ifconfig를 출력해보면 정말 많은 주소들이 뜨고, 그중 무엇을 이용해야하는지는 모르는 경우가 많다.
그렇기 때문에 여기서 한 번 정리해주도록 하겠다.

127.0.0.1과 localhost는 같은 의미이다. 그래서 위에서 localhost:9090으로 해주었지만, 이때 127.0.0.1로 해도 같은 곳에 연결된다. 127.0.0.1은 가장 흔히 사용되는 루프백 주소로, 로컬 호스트를 나타낸다. 이 주소를 사용하면 컴퓨터 자체와 통신하는 데 사용할 수 있다.

반면에 192.로 시작하는 주소는 사설 IP 주소 범위 중 하나이며, 일반적으로 내부 네트워크에서 사용된다. 루프백 주소와 사설 IP 주소의 가장 큰 차이는 사용 목적이다. 루프백 주소는 동일한 기기 내에서의 통신을 위한 것이며, 사설 IP 주소는 여러 기기 간의 내부 네트워크 통신을 위한 거다. 

자, 여기서 하나 더! ifconfig를 치면
1: lo:<LOOPBACK~~~~
2: wlp2s0: <BROADCAST~
이런식으로 뜨게 된다.
이렇게 뜰때 우리는 ip주소를 확인할 수 있는데, 하나에 두개가 보여지게 된다. 이때 brd는 broadcasting의 약자로.. inet과 속도 부분에서 큰 차이는 보이지 않는다. 그러나 역시 p-to-p통신보다는 취약하고.. 좀 번거롭다. 그러니 inet 주소를 가져오고 brd주소는 특수한 경우에 사용하면 된다.
여기서 둘!!
이번엔 IP주소에 대해 알아보자.
IP주소에는 크게 두가지 버전이 있다. IPv4(Internet Protocol version 4)와 IPv6(Interent Protocol version 6)
각 버전에는 주소가 할당되는 방식과 주소의 형식에 차이가 있다. 나는 지금 IPv4에 대한 얘기를 하려고 한다.
IPv4는 32비트 주소 공간을 사용해, 보통 4개의 8bit 블록으로 나눠진 10진수로 표현한다.
1. Public Address(공용 주소):
인터넷에서 사용되며, 고유하게 식별된다. 주소 범위는 1.0.0.0에서 223.255.255.255까지이다.

2. Private Address(사설 주소):
내부 네트워크에서 사용된다. 라우터와 NAT(Network Address Translation)을 통해 공용 주소와 통신할 수 있다.
주소 범위에는 세가지가 있다.
10.0.0.0에서 10.255.255.255 - 대규모 기업 등에서 내부 네트워크로 사용하기 적합.
172.16.0.0에서 172.31.255.255 - 중간 규모 기업 혹은 조직에서 내부 네트워크로 사용.
192.168.0.0에서 192.168.255.255 - 가정용 혹은 소규모 비즈니스 네트워크에서 사용.

3. Reserved Address:
특수한 용도로 예약된 주소이다. 대표적으로 0.0.0.0이나, 앞에서 소개한 것처럼 127.0.0.1 혹은 255.255.255.255가 있다.

이것만 알면 당신도 네트워크 할 수 있다..! 
장난이고.. 사실 내가 분명 전공 수업때 배운 내용이지만, 간혹 헷갈리는 일이 있어 한 번 정리해 보았다. 이제 안까먹었으면 좋겠다..
 
자 사담은 여기까지 하고 unity-ros통신을 이어서 진행해 보도록 하겠다.
 
SampleScence에 Emtpy Object를 추가해주고, 이름은 RosConnecter로 설정해준다.
Inspector에 들어가서 Add Component를 눌러주고 ros를 검색하면 사용가능한 Script 목록이 뜬다. 그 중 RosConnector를 선택해주고 저장해주자. 이렇게 하면 이 프로젝트는 ros와 연결이 되게 된다.
여기까지 RosConnector를 만들어주었다.
 
자, 내가 하려고 한건 Ros와 Unity사이 통신을 통해 Ros로 Image를 보내주는 것이다.
Camera를 원하는 곳에 설치하고, 화각(Field of View)까지 설정해주자. 
헷갈림 방지를 위해 카메라 이름 꼭 변경해주자.
그 다음 똑같이 Add Component를 해주면 되는데, 이때 RosConnector말고 Image Publisher의 Script를 선택해주면 자동으로 RosConnector까지 추가가 된다.
이제 topic이름과 어느카메라인지 다시 설정해주면 준비가 얼추 끝나게 된다.
잘 모르겠다면 아래 사진을 참고해볼까요??

오른쪽의 Inspector를 보고 참고해보자.
 
이제 Ros로 넘어와보면, rosbridge 터미널에 아래와 같이 연결되었음을 알리는 것을 볼 수 있다.

2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.348819]: Client connected.  1 clients total.
2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.355182]: Client connected.  2 clients total.
2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.358155]: Client connected.  3 clients total.
2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.361318]: Client connected.  4 clients total.
2023-11-22 19:08:18+0900 [-] [INFO] [1700647698.365238]: Client connected.  5 clients total.

이제 topic 잘 들어오는지 확인 해보자. 여러가지 방법이 있지만, 나는 내가 만들어둔 파이썬 코드를 실행해서 카메라가 잘 들어오고 있는지 확인했다. 

너무 잘 들어온다... 나처럼 미리 만들어둔 코드가 없는데 지금 당장 잘 들어오는지 확인하고 싶다면, rviz나 rqt를 이용하는 방법이 있다.
지금 Image publish의 Frame Id는 Camera로 되어있기 때문에, rviz에서 frame id 바꿔주고 image add 해주면 볼 수 있다.
다른 방법으로는 rqt_graph와 rqt_image이다.

$ rqt_graph
$ rqt_image_view

위의 두가지 명령어로 토픽이 잘 들어오고 있는지 확인할 수 있다.

아이 이뻐라~
 
여기서 다 소개하지는 않았지만, 그 외에도 unity 사용법 익히고.. 내 프로젝트에 맞게 통신환경 설정하고.. 무엇보다도 Unity-Ros통신 자료가 많은 편은 아니라.. 고생 좀 했다..
지금은 이렇게 받아온 이미지 처리를 진행중이다.

이번에 캡스톤디자인에서 yolo를 돌려야 하는데, 문제가 하나 있다..!

내 노트북이 연약한 내장그래픽 사용하는 gram이라는거...

그런 나에게도 yolo를 약하지만 돌릴 수 있는 방법이 있으니.. 바로 구글 colab이다.

구글 드라이브를 연동해서 무료로 gpu를 사용할 수 있다. 물론 사이즈가 큰 학습은 못하지만.. 현재 내 프로젝트는 구현만 되면 되는거 이기도 하고, 높은 정확도를 요구하지는 않아서... 노트북 사기 전까지는 이걸로 하자..

우선 google drive에 들어가서 colab워크스페이스를 열어준다.

colab에 들어왔으면 제일 먼저 해줄 일은, 런타임 유형을 gpu로 바꿔주는 거다.

상단에 런타임 - 런타임 유형변경 에서 gpu로 바꿔주자.

그다음은 내 드라이브와 연동해주어야 한다.

from google.colab import drive
drive.mount('/content/drive')

위 코드를 넣어줘서 연동을 마무리 해주자.

다음은 yolov5 git을 clone받아주자.

cd drive/MyDrive/

디렉토리 이동을 해주고,,

!git clone https://github.com/ultralytics/yolov5

위 명령어를 입력해주면 yolov5가 클론된다.

다음은 데이터셋 zip파일을 구글 드라이브에 올리자. 이때, 그냥 drive에 올리지 말고 clone받은 yolov5디렉토리 안에 올려주도록 하자

cd yolov5/
!unzip -qq "custom_dataset.zip"

위 명령어를 입력해주면, yolov5폴더 내에 custom_dataset이라는 폴더가 새로 생기게 된다. 

Yolo 학습시키기

이제 학습을 위해 yaml파일을 바꿔주어야 한다.

데이터셋은 이미 라벨링 되어있는 공공 데이터셋을 가져왔기 때문에 여기까지만 해줘도 된다.

path: /content/drive/MyDrive/yolov5/custom_dataset
train: train/images
val: valid/images
test: test/images

nc: 5
names: ['Ambulance', 'Bus', 'Car', 'Motorcycle', 'Truck']

이제 학습 돌려주면 된다.

!python train.py --data "data/custom_dataset.yaml" --epochs 100

epoch은 일단 100으로 두고 진행해보자.

열심히 돌아주렴..

Yolo로 detection시키기

여기까지는 학습을 진행하는 방법이었고, 이제 yolo로 detection하는 법을 정리해보려고 한다.

일단, 기본적으로 yolo에서 제일 기본 pt파일과 샘플 이미지를 제공한다.

sample image는 /data/images에 있다. detection해보고 싶은 이미지가 있다면 이 폴더에 jpg형태로 넣어주면 된다.

그 다음 detection 코드를 실행해주면 된다.

!python detect.py --weights yolov5s.pt --img 640 --conf 0.28 --source data/images
# display(Image(filename='runs/detect/exp/im22.jpg', width=600))

아래에 display 부분은 colab에서 돌려서 못쓰는 부분이다. 만약 gpu달린 노트북에서 진행한다면, 아마 detect되면 이미지가 나타날 것이다.

나는 detect가 끝나면 yolov5/runs/detect/ 에 들어가 직접 확인해주었다.

아래는 내가 직접 넣은 이미지를 detection해본거다. 

꽤나 잘 나와서 사실 따로 학습을 시켜야 하나..? 싶지만... 하기는 해야겠지..

딥러닝.. 어렵다.. 

'자율사물캡스톤디자인 > 자료 조사' 카테고리의 다른 글

Unity-ROS 통신하기  (0) 2023.11.22
테슬라 오토파일럿(Autopilot) 기능  (2) 2023.09.26

AutoPilot  기능 소개

오토파일럿(AutoPilot)은 전방 카메라와 레이더, 차량 둘레에 있는 12개의 초음파 센서로 차량을 조종하고 속도를 조절하는 기능이다.

지금까지는 카메라가 오토파일럿 기능의 주된 정보 원천이었다. 그동안 레이더는 이미지 처리 기술의 보조 역할을 해온것이다. 그러나 2016년 5월 오토파일럿 모드에서 사망한 사고를 계기로 작동 방식을 바꿨다. 이제는 1/10초마다 레이더를 발사해 3차원 영상을 얻는 증 사물 식별 기능을 개선했다.

오토파일럿에는 여러가지기능이 있다. 

  1. 교통 인식 크루즈 컨트롤(Traffic Aware Cruise Control)
    • 지정된 최고 속도로 운행하며 앞차와 간격이 가까워지면 속도를 줄이거나 정차. 앞차와 간격이 늘어나면다시 최고 속도로 가속
  2. 오토 스티어(Autosteer)
    • 현재의 차로를 계속 유지하면서 운행
  3. 인접 차로자동차 관찰기능
  4. 자동 차로 변경(Auto Lane Change)
    • 센서 혹은 측면 카메라로 옆 차로의 공간을 확인하여 차로 변경
  5. 오토파일럿 내비게이션 고속도로(Navigation on Autopilot on the highway)
    • 고속도로 진입로에서 나들목, 진출로까지 자율주행
  6. 오토파키(AutoPark)
    • 평행주차, 직렬주차
  7. 차량 호출(Summon; 서몬)
    • 주차장에서 무인 단거리 직진 전진, 후진
  8. 스마트 호출(Smart Summon; 스마트 서몬)
    • 옥외 주차장에서 차주의 스마트폰 위치까지 무인 자율 저속 이동
    • 스마트 호출은 옥외 주차장의 주행선 정보를 오픈스트리맵에서 사용하는 것으로 알려져 있다.

120만 화소로 360도 커버가 가능한 8개의 카메라에서 얻은 초당 36프레임의 2차원 데이터를 통해 실시간으로 추론을 진행한다. 라이다는 사용하지 않으며 순차적으로 레이더, 초음파센서 등 기타 센서들이 대부분 제거되고 있는 추세이다. 각 센서마다 데이터 생성 패턴이 다르고 sql상에 부하가 생기며 이로 인해 전처리 과정이 힘들고 데이터 엔진에 부담이 가기에 시간적으로나 금전적으로나 큰 비용이 발생하기 때문이라고 한다.

실제로 레이더를 사용하지 않는주행을 2022년 5월에 성공적으로 진행하였다.

네트워크

위치에 따라 차이가 있는 각각의 카메라 특성을 제거하기 위해 정규화 과정을 거친 데이터들은 인공 신경망(RegNet, BiFPN)을 통해 이미지의 반복적 특징을 추출하고 이를 합성한다. 여기에 쿼리 기반 어텐션 신경망을 더해, 이미지 인코딩으로 3차원 위치 정보를 얻어 규정된 쿼리로 맵핑하면 실시간으로 공간상에 3차원 점유정보가 담긴 벡터 네트워크가 생성된다.

이를 기반으로 차선 네트워크와 객체 네트워크를 생성할 수 있는데, 우선 차선 네트워크는 점유 네트워케에 지도 데이터를 더해 차선 연결을 부호화한 특수 언어를 사용한다. 격자점상으로 가능한 모든 곳에 좌표를 생성하고 여러 좌표들을 이어서 선을 만들어 차선을 생성한다.

객체 네트워크는 점유 네트워크에 속도와 가속도, 위치 등의 운동 데이터를 처리하여 타객체의 경로를 예측하는 데 쓰인다.

경로 계획

네트워크들을 기반으로 가벼운 쿼리 신경망을 추가하여 최종적인 최적화 신경망을 구축한다. 벡터 공간 상에 수 백가지 후보 경로중에 하나를 선택하고 액추에이터를 제어하여 object detection, traffic detection, line change 등의 기능이 가능하게 한다.

관심있게 본 내용

주변 환경을 인지할때 어떤 센서들을 이용해서 Sensor Fusion을 진행하는지에 대해 관심있게 보았다.

'자율사물캡스톤디자인 > 자료 조사' 카테고리의 다른 글

Unity-ROS 통신하기  (0) 2023.11.22
Google Colab으로 yolo돌리기  (3) 2023.11.12

+ Recent posts