본문 바로가기

LAB/지능 제어

지능제어(2-1) Homework code1 - Truck Backer-Upper Control

728x90
반응형

 

 

1. 문제

 

Backing up a truck to a loading dock is a nonlinear control problem. Using conventional control approach.

We can first develop a mathematical model of the system and then design a controller based on nonlinear control theory. 

(1) The simulated truck and loading zone are shown in Fig. 12.4. The truck position  is determined by three state variables 𝜙, x and y, where 𝜙 is the angle of the truck with respect to the horizontal line. Control to the truck is the steeling angle 𝜃.

(2) Membership functions for the truck backer - upper control problem. 

(3) The final fuzzy rule base for the truck backer - upper control problem. 

(Question) 다음 membership function, Rule이 주어졌을 때, 결과는? 

 

 

2. 코드

 

<main.py>

import numpy as np
import skfuzzy as fuzz
from matplotlib.pyplot import *
import matplotlib.pyplot as plt
import math
from fuzzy_theta import fuzzy_theta

X = [0]
Y = [0]
Phi = [0.1]
Theta = np.zeros(100)

for t in range(np.size(Theta)):
    Theta[t] = fuzzy_theta(X[t], Phi[t])
    X.append(X[t] + math.cos(Phi[t]+Theta[t])+math.sin(Theta[t])*math.sin(Phi[t]))
    Y.append(Y[t] + math.sin(Phi[t]+Theta[t])-math.sin(Theta[t])*math.cos(Phi[t]))
    Phi.append(Phi[t] - math.asin(2*math.sin(Theta[t])/4))

figure()
plot(X,Y)
plt.show()

 

<fuzzy_theta.py>

import numpy as np
import skfuzzy as fuzz
from matplotlib.pyplot import *
import matplotlib.pyplot as plt

def fuzzy_theta(x_value, pi_value):

#범위 설정
x = np.arange(0, 20, 1)
#pi = np.arange(-90, 271, 1)
pi = np.arange(-2, 6.1, 0.1)
#theta = np.arange(-40, 41, 1)
theta = np.arange(-0.9, 0.9, 0.1)

# 입출력 설정 - 숫자 바꿔야 함.
pi_S3 = fuzz.trimf(pi, [-2, -1, 0])
pi_S2 = fuzz.trimf(pi, [-1, 0, 1])
pi_S1 = fuzz.trimf(pi, [0, 1, 2])
pi_CE = fuzz.trimf(pi, [1, 2, 3])
pi_B1 = fuzz.trimf(pi, [2, 3, 4])
pi_B2 = fuzz.trimf(pi, [3, 4, 5])
pi_B3 = fuzz.trimf(pi, [4, 5, 6])

x_S2= fuzz.trimf(x, [-5, 2, 6])
x_S1 = fuzz.trimf(x, [2, 6, 10])
x_CE = fuzz.trimf(x, [6, 10, 14])
x_B1 = fuzz.trimf(x, [10, 14, 18])
x_B2 = fuzz.trimf(x, [14, 18, 20])

'''theta_S3 = fuzz.trimf(theta, [-40, -40, -27])
theta_S2 = fuzz.trimf(theta, [-40, -27, -14])
theta_S1 = fuzz.trimf(theta, [-27, -14, 0])
theta_CE = fuzz.trimf(theta, [-14, 0, 14])
theta_B1 = fuzz.trimf(theta, [0, 14, 27])
theta_B2 = fuzz.trimf(theta, [14, 27, 40])
theta_B3 = fuzz.trimf(theta, [27, 40, 40])''' #이것은 틀린 코드다 !!

theta_S3 = fuzz.trimf(theta, [-0.9, -0.9, -0.6])
theta_S2 = fuzz.trimf(theta, [-0.9, -0.6, -0.3])
theta_S1 = fuzz.trimf(theta, [-0.6, -0.3, 0])
theta_CE = fuzz.trimf(theta, [-0.3, 0, 0.3])
theta_B1 = fuzz.trimf(theta, [0, 0.3, 0.6])
theta_B2 = fuzz.trimf(theta, [0.3, 0.6, 0.9])
theta_B3 = fuzz.trimf(theta, [0.6, 0.9, 0.9])

'''#입출력 그림으로 출력
fig, (ax0, ax1, ax2) = plt.subplots(nrows=3, figsize=(8,9))

ax0.plot(pi, pi_S3, 'b', linewidth=1.5, label='S3')
ax0.plot(pi, pi_S2, 'b', linewidth=1.5, label='S2')
ax0.plot(pi, pi_S1, 'b', linewidth=1.5, label='S1')
ax0.plot(pi, pi_CE, 'b', linewidth=1.5, label='CE')
ax0.plot(pi, pi_B1, 'b', linewidth=1.5, label='B1')
ax0.plot(pi, pi_B2, 'b', linewidth=1.5, label='B2')
ax0.plot(pi, pi_B3, 'b', linewidth=1.5, label='B3')
ax0.set_title('pi')
ax0.legend()

ax1.plot(x, x_S2, 'b', linewidth=1.5, label='S2')
ax1.plot(x, x_S1, 'b', linewidth=1.5, label='S1')
ax1.plot(x, x_CE, 'b', linewidth=1.5, label='CE')
ax1.plot(x, x_B1, 'b', linewidth=1.5, label='B1')
ax1.plot(x, x_B2, 'b', linewidth=1.5, label='B2')
ax1.set_title('x')
ax1.legend()

ax2.plot(theta, theta_S3, 'b', linewidth=1.5, label='S3')
ax2.plot(theta, theta_S2, 'b', linewidth=1.5, label='S2')
ax2.plot(theta, theta_S1, 'b', linewidth=1.5, label='S1')
ax2.plot(theta, theta_CE, 'b', linewidth=1.5, label='CE')
ax2.plot(theta, theta_B1, 'b', linewidth=1.5, label='B1')
ax2.plot(theta, theta_B2, 'b', linewidth=1.5, label='B2')
ax2.plot(theta, theta_B3, 'b', linewidth=1.5, label='B3')
ax2.set_title('theta')
ax2.legend()'''

# Rule application
pi_level_S3 = fuzz.interp_membership(pi, pi_S3, pi_value)
pi_level_S2 = fuzz.interp_membership(pi, pi_S2, pi_value)
pi_level_S1 = fuzz.interp_membership(pi, pi_S1, pi_value)
pi_level_CE = fuzz.interp_membership(pi, pi_CE, pi_value)
pi_level_B1 = fuzz.interp_membership(pi, pi_B1, pi_value)
pi_level_B2 = fuzz.interp_membership(pi, pi_B2, pi_value)
pi_level_B3 = fuzz.interp_membership(pi, pi_B3, pi_value)

x_level_S2 = fuzz.interp_membership(x, x_S2, x_value)
x_level_S1 = fuzz.interp_membership(x, x_S1, x_value)
x_level_CE = fuzz.interp_membership(x, x_CE, x_value)
x_level_B1 = fuzz.interp_membership(x, x_B1, x_value)
x_level_B2 = fuzz.interp_membership(x, x_B2, x_value)

# Rules (27), 가로로 rule 생성
active_theta = []
active_rule1 = np.fmin(pi_level_S3, x_level_S2)
active_rule2 = np.fmin(pi_level_S3, x_level_S1)
active_rule3 = np.fmin(pi_level_S2, x_level_S2)
active_rule4 = np.fmin(pi_level_S2, x_level_S1)
active_rule5 = np.fmin(pi_level_S2, x_level_CE)
active_rule6 = np.fmin(pi_level_S2, x_level_B1)
active_rule7 = np.fmin(pi_level_S1, x_level_S2)
active_rule8 = np.fmin(pi_level_S1, x_level_S1)
active_rule9 = np.fmin(pi_level_S1, x_level_CE)
active_rule10 = np.fmin(pi_level_S1, x_level_B1)
active_rule11 = np.fmin(pi_level_S1, x_level_B2)
active_rule12 = np.fmin(pi_level_CE, x_level_S2)
active_rule13 = np.fmin(pi_level_CE, x_level_S1)
active_rule14 = np.fmin(pi_level_CE, x_level_CE)
active_rule15 = np.fmin(pi_level_CE, x_level_B1)
active_rule16 = np.fmin(pi_level_CE, x_level_B2)
active_rule17 = np.fmin(pi_level_B1, x_level_S2)
active_rule18 = np.fmin(pi_level_B1, x_level_S1)
active_rule19 = np.fmin(pi_level_B1, x_level_CE)
active_rule20 = np.fmin(pi_level_B1, x_level_B1)
active_rule21 = np.fmin(pi_level_B1, x_level_B2)
active_rule22 = np.fmin(pi_level_B2, x_level_S1)
active_rule23 = np.fmin(pi_level_B2, x_level_CE)
active_rule24 = np.fmin(pi_level_B2, x_level_B1)
active_rule25 = np.fmin(pi_level_B2, x_level_B2)
active_rule26 = np.fmin(pi_level_B3, x_level_B1)
active_rule27 = np.fmin(pi_level_B3, x_level_B2)


active_theta.append(np.fmin(active_rule1, theta_S2))
active_theta.append(np.fmin(active_rule2, theta_S3))
active_theta.append(np.fmin(active_rule3, theta_S2))
active_theta.append(np.fmin(active_rule4, theta_S3))
active_theta.append(np.fmin(active_rule5, theta_S3))
active_theta.append(np.fmin(active_rule6, theta_S3))
active_theta.append(np.fmin(active_rule7, theta_B1))
active_theta.append(np.fmin(active_rule8, theta_S1))
active_theta.append(np.fmin(active_rule9, theta_S2))
active_theta.append(np.fmin(active_rule10, theta_S3))
active_theta.append(np.fmin(active_rule11, theta_S2))
active_theta.append(np.fmin(active_rule12, theta_B2))
active_theta.append(np.fmin(active_rule13, theta_B2))
active_theta.append(np.fmin(active_rule14, theta_CE))
active_theta.append(np.fmin(active_rule15, theta_S2))
active_theta.append(np.fmin(active_rule16, theta_S2))
active_theta.append(np.fmin(active_rule17, theta_B2))
active_theta.append(np.fmin(active_rule18, theta_B3))
active_theta.append(np.fmin(active_rule19, theta_B2))
active_theta.append(np.fmin(active_rule20, theta_B1))
active_theta.append(np.fmin(active_rule21, theta_S1))
active_theta.append(np.fmin(active_rule22, theta_B3))
active_theta.append(np.fmin(active_rule23, theta_B3))
active_theta.append(np.fmin(active_rule24, theta_B3))
active_theta.append(np.fmin(active_rule25, theta_B2))
active_theta.append(np.fmin(active_rule26, theta_B3))
active_theta.append(np.fmin(active_rule27, theta_B2))

active_theta = np.array(active_theta)
aggregated_mf = []

for i in range(np.size(theta)):
    aggregated_mf.append(np.max(active_theta[:, i]))

aggregated_mf = np.array(aggregated_mf)
activated_theta = fuzz.defuzz(theta, aggregated_mf, 'centroid')

#plt.close()
return activated_theta

 

(1) main.py는 제공된 함수입니다. 이를 보고, fuzzy_theta.py를 작성하는 것이 숙제입니다. 

(2) fuzz_trimf 

(3) fuzz.interp_membership(x, xmf, x0) 

   퍼지 집합의 멤버십 함수를 보간(interpolation)하여 주어진 값에 대한 멤버십 값을 계산하는 함수. x는 변수의 입력을 나타내는 1차원 배열, xmf는 변수의 멤버십 함수 값을 나타내는 1차원 배열, x0는 멤버십 값의 보간(interpolation)이 필요한 입력 값(스칼라 or 1차원 배열)

(4) 참고 사항 : np.array 함수란? list에서 ','와 같은 구분 기호를 없애준다. 

관련 예시

(5) active_rule은 벡터값이다.(1차원 배열인 벡터, 전체 코드에서 모두 27개의 다른 벡터 구성)

(6) active_theta도 벡터값이다. 15 by 27이 된다 !!! 이 15 by 27에서 max 값인 1 by 27을 찾으면 됨. 

(7) np.fmin함수

   전건부의 멤버십 값과, 후건부의 멤버십 값 등을 조합하여 퍼지 규칙의 결과 계산할 때 사용된다. 전건부, 후건부 값 중 작은 멤버십 값을 선택하여 계산한다. 예를 들어 x1이 [0.2, 0.5, 0.6]이고 x2가 [0.4, 0.3, 0.7]인 경우 np.fmin(x1, x2)의 결과는 [0.2, 0.3, 0.6]이다. 작은 값을 선택하여, 새로운 배열을 만든다. 

   두번째 예를 들어, x1은 [1,3,5]이고 x2는 2일 경우 np.fmin(x1, x2)의 결과는 [1,2,2]이다. 스칼라값인 x2를 broadcasting하여 [2,2,2]로 확장하여 두 배열의 크기를 자동으로 맞춰준다. 그런 다음, 원소별 최솟값을 계산하자. 

(8) append 함수를 사용하려면, 빈 리스트로 변수를 정의해야 한다. active_theta, aggregated_mf를 []로 정의.

(9) aggregated_mf.append(np.max(active_theta[:, i])).. theta 값이 바뀔 때마다 max선택하여.. 처리.. 

-> (9) 좀 더 제대로 이해하자. 

-> active_theta는 2차원 배열로, 첫 번째 차원은 각 규칙에 대응하는 정보를 담고 있다. 두 번째 차원은 해당 규칙에 대응하는 값들을 담고 있다. active_theta[:, i]는 각 규칙에 대응하는 특정 theta 값들만 선택할 수 있게 된다. i는 0부터 theta 배열의 크기에 해당하는 범위 내에서 사용된다. 

 

(?) 덜 풀리는 점 : 제공된 fuzzy rule을 완벽히 이해하는가 ?

 

 

3. 실행 화면

 

결과 화면

잘 따라가는 것을 알 수 있다. 

 

 

4. 오류 해결 과정

 

(1) 범위 오류 : 왜 theta의 범위가 (-40, 41,1)일 땐 안되고, (-0.9, 0.9, 0.1)로 바꿨을 땐 될까?

 

 

(2) 범위 오류 : 왜 pi의 범위가 (-90, 270, 1)일 땐 안되고, (-2, 5, 0.1)로 바꿨을 땐 될까?

 

(3) 변수 지정 오류 : active_theta를 어떻게 지정해야 하나?

append 함수를 쓰기 위해선, 빈 리스트 형태로 지정해야 한다. 

 

(4) 코드 분석

앞부분에선 변수 정의, pi x에 대해 각각 triangular 형태의 퍼지 멤버십 함수를 정의. 

그다음, level 변수는 특정한 triangular 형태의 퍼지 멤버십 함수를 정의한 것.

끝부분을 상세 설명해보자. 

규칙 적용(1) : 주어진 입력 값 x_value, pi_value에 대해 규칙을 적용하여 퍼지 멤버식 정도를 계산한다. 

규칙 적용(2) : 위에서 계산한 퍼지 멤버십 정도를 기반으로 규칙을 적용하여 theta에 대한 퍼지멤버십 함수를 계산한다. 

activated_theta : 퍼지 멤버십 함수 aggregated_mf를 디펀즈화하여, activated_theta에 대한 결과값을 저장한다. 'centroid'방식으로 디펀즈화 방법을 사용하였다 .

반환값 : 함수의 결과값으로 디펀즈화된 'theta' 값을 반환한다. 

 

 

 

728x90
반응형

'LAB > 지능 제어' 카테고리의 다른 글

지능제어(1) Introduction  (0) 2023.08.02
지능제어(2) 임시  (0) 2023.07.26
지능제어(1-1) Example code  (0) 2023.07.25