728x90

https://www.teachmemicro.com/arduino-pid-control-tutorial

https://ko.m.wikipedia.org/wiki/PID_%EC%A0%9C%EC%96%B4%EA%B8%B0

 

 

 제어 시스템에서 제어기는 시스템의 출력이 목표 입력값이 되도록 고쳐나가야 합니다. 가장 유명한 제어기중 하나는 PID 제어기로 비례, 적분, 미분의 약어라고 할수 있습니다. 이번에는 아두이노 PID 튜토리얼에 대해서 살펴보면서 이 프로젝트에 제어기가 어떻게 사용되는지 알아봅시다.

 

 

앞으로 볼 내용은 아래와 같겠습니다.

 

1. PID가 뭘까?

 1.1 비례 제어

 1.2 적분 제어

 1.3 미분 제어

2. PID 제어 구현

3. 아두이노 PID 라이브러리

4. 마치면서

 

 

 

1. PID란 무엇일까?

 PID는 비례, 적분, 미분의 줄임말이라고 할수 있습니다. 또한 시스템에서 제어기가 요란을 대처하는 방법이라고도 할수 있는데요. 여기서 말하는 제어기는 피드백 시스템에 존재하는 제어기를 말합니다. 그래서 특정 수치값을 읽고 내가 할수있는 일을 하는거라고 할수 있겠습니다.

 

 피드벡 시스템은 출력 결과를 입력으로 되돌려주는 시스템이라고 할수 있는데요. 난로의 불을 제어하는 예제로 한번 배워보겠습니다. 간단한 그림은 아래와 같아요.

 

 여러분들이 일정 온도를 유지하고 싶으면, 센서는 매 시간마다 온도를 측정해주고, 이 측정한 온도가 희망 기준 온도에서 증가하거나 감소했을탠대 이 차이를 오차로 피드백하게 해줍니다.

 

 

 

 

 

 

1.1 비례 제어 Proportional Control

 비례 제어는 에러를 얼마나 많이 비례해서 제어할수 있는지를 말하고 있습니다. 예를들자면 위 난로에서 연료를 조절하는 전기 밸브가 있다고 합시다. 오차가 작다면, 설정 값과 측정 값이 일치하도록 밸브는 작은 양의 연료를 줄것이고, 오차가 크다면 벨브로 더 많은 연료를 줄겁니다.

=> 현재 상태에서 오차 값 크기에 비례하여 제어(원하는 값에 빨리 도달)

 

-  좌측은 제어이전, 우측은 P 제어 이후

=> 제어 이전에는 출력이 목표 값(1)에 도달하지 못함

=> P 제어 이후 오차 값(목표 값 - 현재 값)만큼 비례해서 신호를 증폭한다.

 

 

 

 

 

 

 1.2 적분 제어 Integral Control

 비례제어가 요란을 제거해 주었다면, 적분 제어는 이 오프셋 오차를 제거해서 에러를 0으로 만들어줍니다. 제어기는 시간에 대해 오차가 누적되므로 적분 제어기 없이는 오차에 제대로 대응할수 없습니다.

 

 이전의 예시 계속 보면 연료 출력이 증가하거나 감소한 이후에도 초기 위치가 아닌 지점에서 가만히 있게 됩니다. 적분 제어는 이를 감지해서 연료 밸브를 기존의 자리로 돌려주는 역활을 하겠습니다.

=> 정상상태 오차를 제거(누적된 오차로 인해 원하는 값에 수렴하지 못하는 부분을 제거)

 

 

- 좌측은 비례제어만 한 결과, 우측은 PI 제어 결과

=> 비례제어만 한 경우 존재하는 정상상태 오차를 적분 제어를 통해 제거함

=> 하지만 오버슛이 심각해짐

 

 

 

 

 

 

1.3 미분 제어 Derivative Control

 마지막으로 미분 졔어는 오차의 변화율을 조절시킵니다. 만약 적분 제어에 누적 오차가 보이는 경우에 미분 제어가 이 오차를 예측하여 얼마나 오차가 빠르게 변하는지를 보고 얼마나 고쳐야 할지 찾아냅다. 비례 제어와 적분 제어가 대처하지 못하는 동역학적 에러에 대해서 최적의 동작을 한다고 할수 있겠습니다.

 

 위 난로 예제에서 120도를 설정했지만 130도에서 140도로 올라가는 상황이라고 해봅시다. 비례적분 제어기는 오차의 크기에 대응해서 동작하고는 있지만, 오차가 빠르게 발생하는 경우에서는 대처하기가 어려우나 미분 제어기는 오치의 변화율을 보고 이에 맞게 조절할수가 있습니다.

 

 

- 좌측은 PI 제어기, 우측은 PID 제어기

=> 기존의 출력갑이 크게 변하는데 미분 제어를 통해 오버슛을 줄이고 안정하게 만든다

 

 

 

- PID는 위와 같은 형태로 사용하기도 되지만 P 제어기, PI 제어기, PD 제어기만 사용하는 경우도 있음

- PID 제어시 발생가능한 문제

 1) 계산된 제어값이 구동기가 동작할수 있는 한계 보다 커 구동기 포화(sturation)이 발생하는 경우

 2) 오차 적분값이 크게 누적되어 출력이 설정에 가까워지면 제어가 작아져야하나 큰 값을 출력하여

  설정값에 도달하는데 많은 시간이 걸리는 경우

 -> 위 문제를 적분기의 와이드업이라 함 => 안티 와이드업 기법으로 PID 제어기를 보완해주어야함

- 제어 파라미터 K_p, K_i, K_d를 제어 이득, 게인이라 부름. 적절한 이득값을 얻는 과정을 튜닝(tunning)이라고 함.

 

 

 

https://ko.m.wikipedia.org/wiki/PID_%EC%A0%9C%EC%96%B4%EA%B8%B0

 

 

 

 

 

 

 

 다시 돌아와서

 

 

 

 설정 입력값 r(t)가 있고, 출력으로 y(t), 제어 입력 u(t). 오차 e(t)가 있겠습니다. 위 난로 예제에서 보면 r(t)는 희망 온도, y(t)는 실제 온도라 할수 있습니다. e(t)는 실제 온도와 희망 온도의 차이라할수있고, u(t)는 PID 제어기로 교정한 신호의 총합이라 할수 있겠습니다.

 

 원하는  성능을 얻을수 있또록 PID 제어기의 값들을 고치는 작업을 튜닝이라 부르며, 위 그림에서 K 상수들을 잘 조절해주어야 합니다.

 

 

 

 

 

 

 

 

 

코드로 PID 제어하기

 아두이노 스캐치에서 PID 제어기를 구현하려면 5개의 파라미터가 필요합니다

-> 비례, 적분, 미분 상수와 입력값과 기준 설정 값

 

 PID 계산은 반드시 내부 루프 함수에 있어야하며, 함수 시작시에는 수행 시간 (elapsed time)을 설정해주어야 합니다. 현재 시간은 millis()로 얻겠습니다.

currentTime = millis();
elapsedTime = currentTime - previousTime;

 

 

오차는 설정 지점과 입력의 차이로 얻겠습니다.

error = setPoint - input;

 

 

적분 오차는 시간에 대한 누적 오차라 하였으니 아두이노로 구현하려면 다음과 같이 경과시간 * 오차를 해주면 되겠습니다.

cumError += error * elapsedTime;

 

 미분 오차는 에러의 변화율이므로 다음과 같이 하겠습니다.

rateError = (error - lastError)/elapsedTime;

 

이제 제어 입력 u(t)를 정리하면 아래와 같겠습니다. 여기서 Kp, Ki, Kd는 이전에 설정한 상수가 됩니다.

output = Kp * error + Ki * cumError + Kd * rateError;

 

마지막으로 다음 반복회차를 위해서 변수들을 아래와 같이 지정해줍시다.

lastError = error;
previousTime = currentTime;

 

 

 

 

 

이제 조금 더 제대로 해보면, 다음과같은 휠이 달린 모터가 있다고 해봅시다. 우리는 휠이 저 위치에 있기를 바라고 있습니다. 바퀴에 로터리 엔코더가 재 바퀴 각도에 대한 정보를 알려주므로 우리가 바라는 지점에서의 각도를 0이라 합시다.

 

 

 

 휠이 위치를 벗어날떄마다 조정을 해주어야 하는데, 보통 모터는 PWM 펄스 폭 변조를 통해 제어됩니다. 펄스가 넓을수록 모터 회전이 더 빨라집니다.

 

 이제 아두이노에서 다음과 같이 간단한 제어 예시를 구현해봅시다.

 

//PID constants
double kp = 2
double ki = 5
double kd = 1
 
unsigned long currentTime, previousTime;
double elapsedTime;
double error;
double lastError;
double input, output, setPoint;
double cumError, rateError;
 
void setup(){
        setPoint = 0;                          //set point at zero degrees
}    
 
void loop(){
        input = analogRead(A0);                //read from rotary encoder connected to A0
        output = computePID(input);
        delay(100);
        analogWrite(3, output);                //control the motor based on PID value
 
}
 
double computePID(double inp){     
        currentTime = millis();                //get current time
        elapsedTime = (double)(currentTime - previousTime);        //compute time elapsed from previous computation
        
        error = Setpoint - inp;                                // determine error
        cumError += error * elapsedTime;                // compute integral
        rateError = (error - lastError)/elapsedTime;   // compute derivative
 
        double out = kp*error + ki*cumError + kd*rateError;                //PID output               
 
        lastError = error;                                //remember current error
        previousTime = currentTime;                        //remember current time
 
        return out;                                        //have function return the PID output
}

 위 루프 함수에서는 로터리 엔코더가 휠의 현재 위치를 주고, 그 값이 commputePID()함수의 파라미터로 사용됩니다. 이 함수는 PWM으로 모터 제어에 사용할 값을 반환해 줍니다.

 

 

 

300x250
728x90

기존의 제어 시스템을 다룬다고 한다면

 

MATLAB만 생각하고 있었다

 

 

 

그러다가 프로토타이핑 과제 떄문에 자료를 찾던 중 GEKKO라는 라이브러리를 알게되었는데

 

이 개코 라이브러리가 미분 방정식과 동역학 식같은걸 최적화해서 푸는 파이썬라이브러라리라고한다.

 

MATLAB을 쓰자니 불편하고

 

 

PID 제어기 같은걸 해보고 싶은데 파이썬으로 제공한다니 올커니 하고 영상 목록들을 봤는데

 

뭐가 많긴 많더라

 

 

 

 

이 중에서 내가 관심있는건

 

동역학 최적화와 제어를 위한 파이썬

 

제어를 위한 파이썬 플레이 리스트에서 아까본 역 도립진자 시뮬레이션을 찾았다.

 

https://www.youtube.com/playlist?list=PLLBUgWXdTBDhrs5FuoJXni-cIeNYEyxw1

 

 

일단 이걸 얼마만큼 공부해볼지 한번 생각해보자

 

여기보니 아두이노로  PID 기온 제어하는 예제도 있다.

 

https://www.youtube.com/watch?v=DQWE4SKsTQc&list=PLLBUgWXdTBDhrs5FuoJXni-cIeNYEyxw1&index=12&t=0s

300x250
728x90

일단 GEKKO란 라이브러리는 처음 들어보는 거지만

 

아까 본 영상에서 파이썬에서 GEKKO라이브러리로 역 도립진자 시뮬레이션 하는 모습을 봤었다.

 

일단 코드를 가져와서 시뮬레이션 돌려보긴 했는데 결과는 이렇다.

 

 

 

http://apmonitor.com/do/index.php/Main/InvertedPendulum

 

이 자료에서는 역 도립진자시스템을 위한 제어기 모델을 설계하고 있다.

위 시연에서는 y = -1.0에서 y = 0으로 이동을 보여주고 있으며, 다른 변수 v, theta, q는 조종 전이나 조종후나 0이된다.

 

 

여기서는 역 도립진자에 대한 동역학 방정식을 정리하고 코드가 제공되고 있다.

 

# Contributed by Everton Colling
import matplotlib.animation as animation
import numpy as np
from gekko import GEKKO

#Defining a model
m = GEKKO()

#################################
#Weight of item
m2 = 1
#################################

#Defining the time, we will go beyond the 6.2s
#to check if the objective was achieved
m.time = np.linspace(0,8,100)
end_loc = int(100.0*6.2/8.0)

#Parameters
m1a = m.Param(value=10)
m2a = m.Param(value=m2)
final = np.zeros(len(m.time))
for i in range(len(m.time)):
    if m.time[i] < 6.2:
        final[i] = 0
    else:
        final[i] = 1
final = m.Param(value=final)

#MV
ua = m.Var(value=0)

#State Variables
theta_a = m.Var(value=0)
qa = m.Var(value=0)
ya = m.Var(value=-1)
va = m.Var(value=0)

#Intermediates
epsilon = m.Intermediate(m2a/(m1a+m2a))

#Defining the State Space Model
m.Equation(ya.dt() == va)
m.Equation(va.dt() == -epsilon*theta_a + ua)
m.Equation(theta_a.dt() == qa)
m.Equation(qa.dt() == theta_a -ua)

#Definine the Objectives
#Make all the state variables be zero at time >= 6.2
m.Obj(final*ya**2)
m.Obj(final*va**2)
m.Obj(final*theta_a**2)
m.Obj(final*qa**2)

m.fix(ya,pos=end_loc,val=0.0)
m.fix(va,pos=end_loc,val=0.0)
m.fix(theta_a,pos=end_loc,val=0.0)
m.fix(qa,pos=end_loc,val=0.0)
#Try to minimize change of MV over all horizon
m.Obj(0.001*ua**2)

m.options.IMODE = 6 #MPC
m.solve() #(disp=False)

#Plotting the results
import matplotlib.pyplot as plt
plt.figure(figsize=(12,10))

plt.subplot(221)
plt.plot(m.time,ua.value,'m',lw=2)
plt.legend([r'$u$'],loc=1)
plt.ylabel('Force')
plt.xlabel('Time')
plt.xlim(m.time[0],m.time[-1])

plt.subplot(222)
plt.plot(m.time,va.value,'g',lw=2)
plt.legend([r'$v$'],loc=1)
plt.ylabel('Velocity')
plt.xlabel('Time')
plt.xlim(m.time[0],m.time[-1])

plt.subplot(223)
plt.plot(m.time,ya.value,'r',lw=2)
plt.legend([r'$y$'],loc=1)
plt.ylabel('Position')
plt.xlabel('Time')
plt.xlim(m.time[0],m.time[-1])

plt.subplot(224)
plt.plot(m.time,theta_a.value,'y',lw=2)
plt.plot(m.time,qa.value,'c',lw=2)
plt.legend([r'$\theta$',r'$q$'],loc=1)
plt.ylabel('Angle')
plt.xlabel('Time')
plt.xlim(m.time[0],m.time[-1])

plt.rcParams['animation.html'] = 'html5'

x1 = ya.value
y1 = np.zeros(len(m.time))

#suppose that l = 1
x2 = 1*np.sin(theta_a.value)+x1
x2b = 1.05*np.sin(theta_a.value)+x1
y2 = 1*np.cos(theta_a.value)-y1
y2b = 1.05*np.cos(theta_a.value)-y1

fig = plt.figure(figsize=(8,6.4))
ax = fig.add_subplot(111,autoscale_on=False,\
                     xlim=(-1.5,0.5),ylim=(-0.4,1.2))
ax.set_xlabel('position')
ax.get_yaxis().set_visible(False)

crane_rail, = ax.plot([-1.5,0.5],[-0.2,-0.2],'k-',lw=4)
start, = ax.plot([-1,-1],[-1.5,1.5],'k:',lw=2)
objective, = ax.plot([0,0],[-0.5,1.5],'k:',lw=2)
mass1, = ax.plot([],[],linestyle='None',marker='s',\
                 markersize=40,markeredgecolor='k',\
                 color='orange',markeredgewidth=2)
mass2, = ax.plot([],[],linestyle='None',marker='o',\
                 markersize=20,markeredgecolor='k',\
                 color='orange',markeredgewidth=2)
line, = ax.plot([],[],'o-',color='orange',lw=4,\
                markersize=6,markeredgecolor='k',\
                markerfacecolor='k')
time_template = 'time = %.1fs'
time_text = ax.text(0.05,0.9,'',transform=ax.transAxes)
start_text = ax.text(-1.06,-0.3,'start',ha='right')
end_text = ax.text(0.06,-0.3,'objective',ha='left')

def init():
    mass1.set_data([],[])
    mass2.set_data([],[])
    line.set_data([],[])
    time_text.set_text('')
    return line, mass1, mass2, time_text

def animate(i):
    mass1.set_data([x1[i]],[y1[i]-0.1])
    mass2.set_data([x2b[i]],[y2b[i]])
    line.set_data([x1[i],x2[i]],[y1[i],y2[i]])
    time_text.set_text(time_template % m.time[i])
    return line, mass1, mass2, time_text

ani_a = animation.FuncAnimation(fig, animate, \
         np.arange(1,len(m.time)), \
         interval=40,blit=False,init_func=init)

# requires ffmpeg to save mp4 file
#  available from https://ffmpeg.zeranoe.com/builds/
#  add ffmpeg.exe to path such as C:\ffmpeg\bin\ in
#  environment variables

#ani_a.save('Pendulum_Control.mp4',fps=30)

plt.show()

코드는 위와 같다.

애니메이션 부분은 그렇다 치더라도 GEKKO가 뭔지 모르는 상태에선 이해하기 힘들듯 하다

 

 

개코의 소개 사이트에 들어왔다.

https://gekko.readthedocs.io/en/latest/overview.html

 

 

 개코는 최대 정수, 미분 대수 방정식을 위한 최적화 소프트웨어로 선형, 이차, 비선형 그리고 최대 정수가 혼합된 프로그래밍 등 많은 범위에서 사용할수 있는 도구로, 실시간 최적화, 동역학 시뮬레이션, 비선형 예측 제어 등 모드를 제공한다고 한다.

 

 

 

 

=> 여기까지 내용을 봐서는 개코는 최적화 연산 도구로 아무래도 우리 예제에선 동역학 식을 만들어서 사용하니 이 라이브러리로 최적 계산을 수행해서 플로팅 시켜준듯하다.

 

 일단 게코 라이브러리는 여기까지만 보자

 

 

 

 

300x250
728x90

1. 코코아팹 - 밸런싱 로봇

 

https://kocoafab.cc/make/view/719

 

PID 제어와 밸런싱 로봇에 대해서 소개하고있고

소스코드도 공개되어있다.

곧 분석해보자

 

 

 

 

 

 

2. 이륜 역진자 로봇의 밸런싱 제어시스템구현

- 기존의 PD 제어기에선 직접 파라미터를 실험하면서 조정했다면, 기존의 실험과 딥러닝 신경망에서 학습한 결과를 비교해보는 내용이다.

http://www.ndsl.kr/ndsl/search/detail/article/articleSearchResultDetail.do?cn=JAKO201211559435983

 

 

 

 

3. 아두이노 PID 제어 튜토리얼

- 아두이노를 이용해서 어떻게 PID제어를 하는지 코드와 설명이 같이되어있다. 나중에 한번 봐야겠다.

https://www.teachmemicro.com/arduino-pid-control-tutorial

 

 

 

4. 밸런싱 로봇 키트 제작 설명

세그웨이 같은 밸런싱 로봇 키트를 조립하고 소스코드에 대한 간단한 설명 제공

http://scipia.co.kr/cms/blog/227

 

SBOT1 아두이노 세그웨이 밸런싱로봇 제작(Feat. MPU6050, PID제어) | 싸이피아SCIPIA

여기서는 세그웨이(Segway)와 같이 두 바퀴로 균형을 유지하여 넘어지지 않는 로봇을 제작합니다. 이 로봇은 Self-balancing robot 또는 평행자동차, 밸런싱로봇, 세그웨이 로봇으로 불리우며 여기서 실

scipia.co.kr

 

 

 

 

 

 

5. 아두이노와 시뮬링크를 이용한 시스템 구현

kr.mathworks.com/videos/arduino-support-in-simulink-117736.html

 

 

 

 

 

6.  아두이노와 매트랩을 이용한 모터 제어

https://kr.mathworks.com/videos/using-matlab-and-arduino-for-motor-control-100737.html

- 아두이노 처럼 모터 실험하는 간단한 내용 크게 도움은 안될듯

 

 

 

 

 

7. 매트랩 시뮬링크를 이용한 DC 모터 제어

https://www.youtube.com/watch?v=25dU_Aq49m4

- 유용해 보이긴하나 수학적 모델링을 한 결과물을 시뮬레이션에 하는데 사용하는데 참고하면 될듯하다

 

 

 

 

 

8. 역 도립진자 프로젝트

http://mercury.hau.ac.kr/sjkwon/Lecture/2010-1%ED%95%99%EA%B8%B0%20%EC%9E%90%EB%8F%99%EC%A0%9C%EC%96%B4%EC%84%A4%EA%B3%84%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8.pdf

- 이거는 밸런싱 로봇은 아니지만 제어 시스템 설계 과정에 대해서 잘 정리해주고 있어서 많이 도움이 될것같은 마음에 가져왔다

- 이 자료에서는 opengl에서 역도립진자를 시뮬레이션했더라 이걸보고 매트랩이나 opengl 말고 파이썬에서 할수있지않을까해서 찾아봣다.

 

 

 

 

 

9. 상태 공간 모델을 이용한 역 도립진자

- 나는 기존에 제어시스템은 matlab에서만 할수있는건줄 알았으나 opengl을 이용해서 c++로 시뮬레이션 한 글을 보았다. 그러다보니 python에서 할수있지 않을까 고민해보다가 찾은 자료

https://www.youtube.com/watch?v=egPRF5PHwOo&list=UU2GuY-AxnNxIJFAVfEW0QFA&index=3

http://apmonitor.com/do/index.php/Main/InvertedPendulum

소스도 공개해 주고 계시다.

 

진짜 나도 잘하게되면 이런 자료들 실컷 만들어서 뿌려야지

맨날 남의거 주위 공부하기도 좀 그렇다 ..

 

 

 

 

 

10. 균형 잡는 로봇

https://swiz23.github.io/Portfolio/inverted_pen.html

- 당장 내가 하는 프로토타이핑이랑  크게 관련있다고 할수는 없지만 이전에 본 로봇이 공 균형을 잡는게 신기해서 캡처

 

 

 

지금까지 참 정보가 많긴 한데

 

뭐가 내가 워하는 정보고 나한태 알맞을지 참 판단하기 힘들다.....

 

 

 

 

내가 원래 생각했던건 크게 2가지 과정이 될듯했느넫

 

1. 기존의 자료를 가지고 밸런싱 로봇 완성

 

2. 제어공학적 측면에서 구성

 - 수학적 모델링

 - 보드 선도 등 방법으로 적합한 파라미터 구하기

 

자료 조사하다보니

밸런싱 로봇 조립 및 실험, 수학적 모델링 및 파라미터 구하기 뿐만아니라

 

시뮬레이션을 구현해보는 방법도 있겠다

 

 

 

300x250
728x90

지금 정리하고 있는 내용들은

블로그 시작하기전에 다 배웠던 것들이다

 

다만 지금만큼 이해하지도 못했지만

대강 개념은 알고있던 것들이다.

 

 

이렇게 공부하다보면 드는 생각은

내가 뭔가 만들고 싶은데 언제까지 이렇게 이론 공부만 해야할까 싶더라

 

생각해보니 이론 공부가 부족해서 계속 이론 공부만 할 생각을 했지

무언가 제대로 구현해볼 생각은 없었다.

 

지금 당장만 해도 IOT 프로토타이핑을 하고

밸런싱 로봇을 만든다고 목표를 설정한 정도였지

 

밸런싱 로봇을 만드는 중간 사이에 무엇을 할지 제대로 정의하지 못하고

부족한 공부를 더하면 할수있을거라 생각하고 하고있었다.

 

하지만 이대로 하면 계속 이론공부만 할것같더라

 

 

 

그런데 내가 잘못 생각한것 같다.

대강 개념 아는 내용들을 한번더 되짚는것도 필요하지만

이제는 뭔가 만들어가야하는 시점인데

 

 

지난번에 놓친부분들을 보고만 있자니

한 학문의 내용정리를 할때까지 미루자니 너무 답답하다

 

 

원래 오늘 opencv-python을 마무리 할생각이었으나

어제 생각보다 많이 하다보니 지금 계속 하기에는 질려버렸다.

 

 

나중에 더 진도 나가고 싶을때 하기로하고

아두이노로 할수있는 제어 시스템을 만들어봐야겟다

 

 

지금 너무 글양을 늘리는데만 급급하느라 방향을 잘못설정하고 있는것 같다.

 

되도록이면 오늘은 관련 자료들을 정리하는데 집중하자.

300x250

'그외 > 로그' 카테고리의 다른 글

시험 준비와 근황  (0) 2020.11.09
공부해나간 과정  (0) 2020.11.01
가끔 보는 유튜브 - 커넥팅닷  (0) 2020.08.16
프로젝트가 우선이냐 이론이 우션이냐 ojtube  (0) 2020.08.16
휴대용 오실로스코프 구매  (0) 2020.08.15
728x90

 

 ORB SLAM은 실시간으로 동작하고, 내부외부 작거나 넓은 공간 상관없이 사용가능한 특징 기반 SLAM 시스템으로, 심한 동작 버벅임에도 강인하여 넓은 공간에서의 루프 폐쇄와 재 위치 추정이 가능하고, 완전 자동화된 초기화도 수행한다.

 

 최근 몇년동안 좋은 알고리즘을 만들기 위해서 밑바닥에서 부터 SLAM의 모든 동작(추적, 지도작성, 재위치추정, 루프클로징)을 수행하는 새로운 시스템을 만들었습니다.

 

 올바른 점들을 선택하기 위한 방법과 키프레임 복원을 위한 노력 덕에 강인해졌으며, 소형화가 되었고 추적이 가능한 지도를 만들게 되었습니다.

 

 가장 유명한 데이터셋의 27시퀀스로 평가 결과를 정리했으며 ORB SLAM은 최신 단안 SLAM 방법들 중에서 전래없는 성능을 보이고 있습니다. 

 

 

 

 

ORB SLAM

- 내부, 외부 상관없이 실시간으로 사용가능한 특징기반 SLAM 알고리즘

- 동작 버벅임에도 강인. 넓은 공간에서 루프 폐쇄와 위치 추정 가능, 초기화도 자동화

 

 

 

 

 

 번들 조정 방법은 정밀한 카메라의 위치 추정치와 희소 기하 복원을 하는데 사용되고 있습니다.  오랜 시간 동안 이방법은 비주얼 슬램 같은 실시간 분야에서는 부적합하다고 생각되어 왔습니다.

 

 비주얼 슬램의 목표는 주위 환경을 복원하고 카메라의 궤적을 추정하는것인데,  이제 계산 비용 문제 없이 좋은 결과를 얻게 되었고, 실시간 슬램 알고리즘을 하려면 번들 조정시 다음 사항들을 따르면 됩니다.

 

 1) 선택된 키프레임 하부집합 사이에서 장면 특징 관측의 대응

 2) 키프레임의 수 증가와함께 복잡도가 커질때, 선택하여 불필요한 것들을 없에야 합니다.

 3) 키프레임과 점들의 강한 결합으로 좋은 결과를 얻었으며, 즉 키프레임들이 잘 흩어져있다고 할수 있겠습니다.

 4) 비선형 최적화를 위한 키프레임과 점 위치의 초기 추정치

 5) 지역 지도들은 확장성을 얻기 위해 최적화에 집중합니다.

 6) 빠르고 전역적인 최적화(자세 그래프)를 하기위해서 실시간으로 루프 클로져를 해야합니다.

 

=> 번들 조정을 실시간으로 하기위한 조건?

 

 

 관련 연구들을 살펴보면 

- 첫 번들 조정을 이용한 실시간 어플리케이션 -> 비주얼 오도메트리(Mouragon)

- 평행 추적 및 지도작성(PTAM) 등

 

 

 

PTAM Parallel Tracking and Mapping

- 작은 스케일의 연산으로 제한

- 키포인트 선택, 특징 매칭, 점 삼각화, 카메라 위치 추정, 위치 추적 실패후 재위치추정 등을 위한 효과적인 방법들 제공

- 단점 : 루프 클로징과 예외 상횡시 적절한 대응 부족, 재위치 추정시 관점의 저불변성(관점이 잘 바뀌지 않는다?), 맵 부트스트랩에 사람이 필요

 

 

 

ORB SLAM의 경우

- PTAM의 매인 아이디어인 장소 인식 부분을 참고, 스프클로징시 스케일 인지, 큰 스케일 연산시 공동 가시성 정보 등이 사용됨. 그 결과 단안 ORB SLAM은 다음을 따름

 

1. 모든 동작(추적, 지도작성, 재위치추적, 루프클로징) 에 같은 특징 사용

 -> 더 효율적이고, 단순하고, 신뢰성있어짐.

 - ORB 특징을 사용했는데, GPU 없이도 실시간으로 수행하기 위함이고, 관점과 조도 변화에서도 불변함

 

2. 넓은 공간에서도 실시간 연산이 가능함. 공동 가시성 그래프를 사용한 덕분에 추적과 지도작성이 지역적 공동 가시성 영역에 집중되어 전역 크기의 맵에는 독립적으로 됨

 

3. 자세 그래프 최적화 방법에 기반하여 실시간 루프 폐쇄가 수행됨. 이 시스템은 생성 트리로 만들어지고, 루프 클로저 링크와 강한 에지는 공동 가시성 그래프에서 만듬.

 

4. 지도를 재사용하거나 추적을 실패시에도 불변하게 실시간 카메라 재위치 추정이 가능

 

5. 평면과 비평면 공간의 지도를 만들도록 하는 모델 선택 기반으로 새로운 자동, 강인한 초기화 과정이 수행됨.

 

 

 이 방법이 단안 SLAM에 있어서 완전하고 신뢰할수있는 최선의 결과물이라 할수 있음.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

300x250
728x90

orb slam에서 검색해보니 가장 먼저 open slam 사이트가 나온다

https://openslam-org.github.io/

 

orb slam 봐선 다 공개되어있는듯한데

 

여기서 부터 시작해보자

 

 

 

http://webdiis.unizar.es/~raulmur/orbslam/

 

ORB SLAM의 개요에 대한 사이트다

 

여기서보면 ORB SLAM이 단안 카메라 뿐만아니라

 

스테레오 카메라

 

RGBD 카메라에 적용되서 사용되는걸 보여준다.

 

 

 

 

일단 ORBSLAM에서 맨 앞 내용을 정리해보면

 

 

ORB-SLAM은 다양하게 쓸수있고 정밀한 SLAM 방법으로 단안, 스테레오, RGBD 카메라에서 사용가능하다. 카메라 궤적을 실시간으로 추정하고, 주위 환경 장면을 3차원으로 복원 가능하다. 그리고 넓은 루프를 클로즈할수 있고, 실시간으로 그리고 넓은 공간에서 전역적인 재위치조정을 수행한다. 이 기술에는평면과 평면이 아닌 장면에 대해 자동, 강인한 초기회를 할수 있으며 이에 대한 자료들은 아래에서 볼수 있겠다.

 

 

 

소스코드

- ORB SLAM

github.com/raulmur/ORB_SLAM

 

- ORB SLAM2

github.com/raulmur/ORB_SLAM2

 

 

 

 

 

 

단안, 스테레오, RGBD 카메라를 이용한 ORB SLAM 2

- 논문

https://128.84.21.199/abs/1610.06475

 

 

 

 

 

 

단안 카메라 ORB SLAM

- KITTI 데이터셋을 이용한 ORB SLAM

dx.doi.org/10.1109/TRO.2015.2463671

IEEE 로봇 공학 분야 최고 논문상 수상!!

 

 

 

 

 

 

 

 

 

 

 

 

 

300x250
728x90

매번 논문 정리를 해야지 하면서 생각만해놓고 

 

그날 할 과제만 하느라 논문 정리는 계속 뒷전으로 미루고 있다.

 

 

하긴 해야된느데

 

 

이렇게 글 대충이라도 조금씩 남기고자한다.

 

 

내가 당장 컴퓨터 비전분야에서 비주얼 슬램을 다뤄보고싶으니

 

 

 

대표적인 비주얼 슬램 알고리즘인 ORB SLAM에서 시작하여

 

필요한것들을 전개해나갈까 싶다.

 

 

300x250
728x90

일단 opencv-python을 하면서

 

opencv로 컴퓨터 비전을 어떻게 활용할수 있는지 개념을 파악하고 실습도 진행해보고 있다.

 

일단 내가 생각하는 컴퓨터 비전 분야에서 목표는 네 가지로 정리할수 있을것같다.

 

1. opencv-python 예제 정리

 

2. 스테레오 비전을 통한 거리 측정

 

3. 단일 카메라 시각 궤적 추정

 

4. Visual SLAM

 

일단 1번은 거의 따 끝나가고 있고

 

내일 중으로 스테레오 비전 일부분을 조금 진행할수 있을것같다.

 

아쉽게도 스테레오 지그가 없다보니 기존의 데이터셋이 아닌이상 제대로 해보기는 힘들듯하다.

 

 

또 채스보드도 없다보니

 

카메라 캘리브레이션을 한번 해보긴 해야하는데

 

아이패드에 채스판을 띄워서 가능하다면 오늘 중으로

 

1. 카메라 캘리브레이션

2. 에피폴라 기하학

3. 깊이 맵 구하기

 

정도 해보고자한다.

 

 

 

 

이렇게 스테레오 비전을 통한 거리 측정까지 빨리 끝나면

 

시각 궤적도 조금 찾아보고

 

어렵다면 프로토타이핑 관련 내용들에 집중하고자한다..

300x250
728x90

 

드디여 특징 검출 부분을 마무리하고 비디오 해석으로 넘어왔다.

 

이번에는 비디오에서 물체를 찾고 추적하는 알고리즘인 민시프트와 캠시프트 알고리즘을 배워보자

 

 

민시프트

- 민시프트의 개념은 간단합니다. 점들의 집합이 존재하는데(히스토그램 역전파 같은 픽셀 분포가 있다고 합시다), 여기다가 작은 원형 윈도우를 주고, 이 윈도우가 픽셀 밀도가 최대인 방향으로 이동시킵니다(점들의 개수가 최대인 지점). 이를 나타내면 아래와 같습니다.

 

 

 초기 윈도우는 파란색 원으로 여기서 c1이라고 하겠습니다. 이 원의 중심은 파란색 사각형으로 c1_o라 하겠습니다. 이 윈도우 안에서 중심점을 찾는다면 c1_r로 작은 원으로 그리겠고, 실제 윈도우의 중심이라 할수 있습니다.

 

 원의 중심과 점들의 중심이 맞지 않으면 윈도우는 이동하고, 새로운 윈도우의 중심은 이전의 센트로이드와 동일해질겁니다(c1_r이 새로운 중심점이 됨). 다시 새로운 센트로이드를 찾고 이동하는게 반복됩니다.

 

 아마 매치가 되지않는다면 다시 이동하윈도우의 중심이 반복되는 결과 같은 지점으로 수렴하게 됩니다. 결과적으로 픽셀 분포가 최대가 되는 지점에 윈도우는 존재하게 됩니다. 이를 녹색선으로 그리고 c2라 하겠습니다. 위에서 보시다시피 이 곳이 점들이 최대가 되는 지점이라 할수 있습니다. 전체적인 과정은 아래의 이미지에서 볼수 있겠습니다.

 

 

 

 

 히스토그램 역투영 영상과 초기 목표 위치를 통과할거고, 물체가 움직인다면 히스토그램 역투영 영상에서 반영될겁니다. 그 결과 민시프트 알고리즘은 윈도우를 이동시키고 결과적으로 최대 밀도가되는 지점에 도착하게 됩니다.

 

 

opencv meanshift

- opencv에서 민시프트를 하려면 우선 타겟을 설정해야합니다. 그리고 그 타겟의 히스토그램을 구해야 타갯의 역투영을 할수 있고 민시프트 계산이 가능해집니다. 그리고 초기 윈도우의 위치가 필요합니다. 히스토그램에서는 hue만 고려할수 있으니 저조도에 의한 거짓 값을 피하기 위해서 cv2.inRange()함수로 저조도 값들을 제거하겠습니다.

 

 

 

 

 

 

 

캠시프트

 

 조금전 결과를 자세히 보셧나요? 여기선 문제가 있는데 윈도우가 항상 차가 밖에 나갈때까지도 같은 크기로 되어 카메라 가까이 까지 따라옵니다. 이건 좋지 않으니 윈도우 크기를 타겟의 크기와 회전에 따라 조절해주어야 합니다. 그래서 opencv 연구실에서 CAMshift (continuosly adaptive meanshift)라는 방법을 제안하였습니다.

 

 처음에는 민시프트를 적용합니다. 민시프트가 수렴하고나면, 윈도우 크기를 아래와 같이 조절해줍니다. 이것은 최적의 타원 방향을 계산해 줍니다.

 

 다시 새로운 스케일된 탐색 윈도우와 이전 윈도우 위치로 민시프트를 적용하고고 이를 반복하면 아래와 같이 정밀한 결과를 얻을수 있습니다.

 

 

 

 이제 민시프트랑 동일하게 캠시프트를 적용해보겠습니다. 하지만 여기서는 회전된 사각형과 박스 파라미터(다음 반복에 사용할)를 반환해 줍니다.

 

import numpy as np
import cv2

cap = cv2.VideoCapture('./res/slow.mp4')

# take first frame of the video
ret,frame = cap.read()

# setup initial location of window
r,h,c,w = 135,90,270,125  # simply hardcoded the values
track_window = (c,r,w,h)

# set up the ROI for tracking
roi = frame[r:r+h, c:c+w]
hsv_roi =  cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
roi_hist = cv2.calcHist([hsv_roi],[0],mask,[180],[0,180])
cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)

# Setup the termination criteria, either 10 iteration or move by atleast 1 pt
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )

while(1):
    ret ,frame = cap.read()

    if ret == True:
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        dst = cv2.calcBackProject([hsv],[0],roi_hist,[0,180],1)

        # apply meanshift to get the new location
        ret, track_window = cv2.CamShift(dst, track_window, term_crit)

        # Draw it on image
        pts = cv2.boxPoints(ret)
        pts = np.int0(pts)
        img2 = cv2.polylines(frame,[pts],True, 255,2)
        cv2.imshow('img2',img2)
        cv2.imshow('dst',dst)

        k = cv2.waitKey(60) & 0xff
        if k == 27:
            break
        else:
            cv2.imwrite(chr(k)+".jpg",img2)

    else:
        break

cv2.destroyAllWindows()
cap.release()

 

 다음 이미지는 캠시프트 한 결과를 보여주는데 아래는 히스토그램 역투영 영상 위는 캠시프트 결과를 보여주고 있습니다.

 

 

300x250

+ Recent posts