티스토리 뷰
프로세싱에서 PID 매개변수 설정하기
목표
프로세싱에서 매개변수를 설정해주고 설정 한 값들을 시리얼 포트를 이용해서 아두이노로 값을 전달한다
(여기서는 매개변수 설정만 해주고 아두이노로 전달하지는 않는다.)
소스코드
import processing.serial.*; //Library to Serial
import controlP5.*; //Library to ControlP5
ControlP5 cp5;
Chart rollChart, pitchChart, yawChart;
Serial Comport;
void setup()
{
size(700, 440);
noStroke();
cp5 = new ControlP5(this); //creative Objecy GUI
cp5.addTextlabel("","Dron PID Output")
.setPosition(200, 10)
.setColorValue(0xffffff00)
.setFont(createFont("Lucida Sans", 30));
rollChart =
cp5.addChart("roll_output")
.setPosition(20, 60)
.setSize(200, 100)
.setRange(0, 255)
.setView(Chart.LINE)
.setStrokeWeight(1.5)
;
rollChart.addDataSet("incoming");
rollChart.setData("incoming", new float[100]);
pitchChart =
cp5.addChart("pitch_output")
.setPosition(240, 60)
.setSize(200, 100)
.setRange(0, 255)
.setView(Chart.LINE)
.setStrokeWeight(1.5)
;
pitchChart.addDataSet("incoming");
pitchChart.setData("incoming", new float[100]);
yawChart =
cp5.addChart("yaw_output")
.setPosition(460, 60)
.setSize(200, 100)
.setRange(0, 255)
.setView(Chart.LINE)
.setStrokeWeight(1.5)
;
yawChart.addDataSet("incoming");
yawChart.setData("incoming", new float[100]);
cp5.addSlider("roll_kp")
.setRange(0, 10)
.setScrollSensitivity(0.2 * 10 / 10)
.setPosition(20, 200)
.setSize(600, 19)
.setValue(1)
;
cp5.addSlider("roll_ki")
.setRange(0, 0.25)
.setScrollSensitivity(0.005 * 10 / 0.25)
.setPosition(20, 220)
.setSize(600, 19)
.setValue(0.0)
;
cp5.addSlider("roll_kd")
.setRange(0, 0.6)
.setScrollSensitivity(0.1 * 10 / 0.6)
.setPosition(20, 240)
.setSize(600, 19)
.setValue(0)
;
cp5.addSlider("pitch_kp")
.setRange(0, 10)
.setScrollSensitivity(0.2*10/10)
.setPosition(20, 280)
.setSize(600, 19)
.setValue(1)
;
cp5.addSlider("pitch_ki")
.setRange(0, 0.25)
.setScrollSensitivity(0.005*10/0.25)
.setPosition(20, 300)
.setSize(600, 19)
.setValue(0.0)
;
cp5.addSlider("pitch_kd")
.setRange(0, 0.6)
.setScrollSensitivity(0.1*10/0.6)
.setPosition(20, 320)
.setSize(600, 19)
.setValue(0)
;
cp5.addSlider("yaw_kp")
.setRange(0, 10)
.setScrollSensitivity(0.2*10/10)
.setPosition(20, 360)
.setSize(600, 19)
.setValue(1)
;
cp5.addSlider("yaw_ki")
.setRange(0, 0.25)
.setScrollSensitivity(0.005*10/0.25)
.setPosition(20, 380)
.setSize(600, 19)
.setValue(0.0)
;
cp5.addSlider("yaw_kd")
.setRange(0, 0.6)
.setScrollSensitivity(0.1*10/0.6)
.setPosition(20, 400)
.setSize(600, 19)
.setValue(0)
;
println((Object[])Serial.list());
String portName = Serial.list()[0];
Comport = new Serial(this, portName, 115200);
}
int roll_output;
int pitch_output;
int yaw_output;
void draw()
{
background(0);
rollChart.push("incoming", roll_output);
pitchChart.push("incoming", pitch_output);
yawChart.push("incoming", yaw_output);
}
final byte
IDLE = 'I',
ROLL_OUTPUT = 'a',
PITCH_OUTPUT = 'b',
YAW_OUTPUT = 'c';
int inputState = IDLE;
void SerialEvent(Serial port)
{
int inputData = port.read();
if(inputState == IDLE)
{
switch(inputData)
{
case ROLL_OUTPUT:
inputState = ROLL_OUTPUT;
break;
case PITCH_OUTPUT:
inputState = PITCH_OUTPUT;
break;
case YAW_OUTPUT:
inputState = YAW_OUTPUT;
break;
default:
break;
}
}
else
{
switch(inputState)
{
case ROLL_OUTPUT:
roll_output = inputData;
break;
case PITCH_OUTPUT:
pitch_output = inputData;
break;
case YAW_OUTPUT:
yaw_output = inputData;
break;
}
inputState = IDLE;
}
}
public void roll_kp(float kp)
{
println("roll kp : " + kp);
Comport.write('a');
Comport.write((int)((kp + 0.01) / 0.2));
}
public void roll_ki(float ki)
{
println("roll ki : " + ki);
Comport.write('b');
Comport.write((int)(ki/0.005));
}
public void roll_kd(float kd)
{
println("roll kd : " + kd);
Comport.write('c');
Comport.write((int)((kd+0.01)/0.1));
}
public void pitch_kp(float kp)
{
println("pitch kp : " + kp);
Comport.write('d');
Comport.write((int)((kp+0.01)/0.2));
}
public void pitch_ki(float ki)
{
println("pitch ki : " + ki);
Comport.write('e');
Comport.write((int)(ki/0.005));
}
public void pitch_kd(float kd)
{
println("pitch kd : " + kd);
Comport.write('f');
Comport.write((int)((kd+0.01)/0.1));
}
public void yaw_kp(float kp)
{
println("yaw kp : " + kp);
Comport.write('g');
Comport.write((int)((kp+0.01)/0.2));
}
public void yaw_ki(float ki)
{
println("yaw ki : " + ki);
Comport.write('h');
Comport.write((int)(ki/0.005));
}
public void yaw_kd(float kd)
{
println("yaw kd : " + kd);
Comport.write('i');
Comport.write((int)((kd+0.01)/0.1));
}
다운로드 파일
P_15ypr2stdpid02.pde설명#1 매개변수 슬라이더 구현하기
cp5.addSlider("roll_kp")
.setRange(0, 10)
.setScrollSensitivity(0.2 * 10 / 10)
.setPosition(20, 200)
.setSize(600, 19)
.setValue(1)
;
cp5.addSlider("roll_ki")
.setRange(0, 0.25)
.setScrollSensitivity(0.005 * 10 / 0.25)
.setPosition(20, 220)
.setSize(600, 19)
.setValue(0.0)
;
cp5.addSlider("roll_kd")
.setRange(0, 0.6)
.setScrollSensitivity(0.1 * 10 / 0.6)
.setPosition(20, 240)
.setSize(600, 19)
.setValue(0)
;
cp5.addSlider("pitch_kp")
.setRange(0, 10)
.setScrollSensitivity(0.2*10/10)
.setPosition(20, 280)
.setSize(600, 19)
.setValue(1)
;
cp5.addSlider("pitch_ki")
.setRange(0, 0.25)
.setScrollSensitivity(0.005*10/0.25)
.setPosition(20, 300)
.setSize(600, 19)
.setValue(0.0)
;
cp5.addSlider("pitch_kd")
.setRange(0, 0.6)
.setScrollSensitivity(0.1*10/0.6)
.setPosition(20, 320)
.setSize(600, 19)
.setValue(0)
;
cp5.addSlider("yaw_kp")
.setRange(0, 10)
.setScrollSensitivity(0.2*10/10)
.setPosition(20, 360)
.setSize(600, 19)
.setValue(1)
;
cp5.addSlider("yaw_ki")
.setRange(0, 0.25)
.setScrollSensitivity(0.005*10/0.25)
.setPosition(20, 380)
.setSize(600, 19)
.setValue(0.0)
;
cp5.addSlider("yaw_kd")
.setRange(0, 0.6)
.setScrollSensitivity(0.1*10/0.6)
.setPosition(20, 400)
.setSize(600, 19)
.setValue(0)
;
이 루틴을 구현하고자 하는 목표는 GUI 상에서 마우스 휠로 슬라인더를 스크롤 하므로서 매개변수 값을 설정을 할려고 합니다.
출처 : wikipedia 매개변수들을 변경경을 하면 이렇게 변하겠죠?
Roll, Pitch, Yaw에 각각 Kp, Ki, Kd 라는 매개변수(Gain)이 존재합니다. 그래서 총 9개의 매개변수를 설정할 수 있는 구현을 추가하면 됩니다.
※여기서 주의!!!!
이번에 추가하는 루틴은 Serial 객체를 생성하기 전에 추가를 시켜주어야 합니다. 만약 그러지 않는다면 Serial Port가 정상적으로 작동을 하지 않게 됩니다.
cp5.addSlider("roll_kp")
.setRange(0, 10)
.setScrollSensitivity(0.2 * 10 / 10)
.setPosition(20, 200)
.setSize(600, 19)
.setValue(1)
;
여기서 사용이 되는 addSlider 함수는 GUI로 슬라인더를 추가하는 함수입니다. 위에 코드를 보시게 되면 "roll_kp" 이렇게 적혀있는데 이것은 나중에 콜백함수가 사용되는 원인이 됩니다.
setScrollSensitivity(스크롤 감도를 설정)은 0.2씩 증가 또는 감소하며 그 값의 범위는 0 ~ 10이여서 그럽니다. 그러면 총 50단계로 매개변수 설정이 가능해 지게 됩니다.
그리고 초기 슬라이더 값을 1로 설정을 해주고 있습니다.
그 이하의 문장도 동일합니다^^
설명#2 매개변수의 콜백함수 설정
public void roll_kp(float kp)
{
println("roll kp : " + kp);
Comport.write('a');
Comport.write((int)((kp + 0.01) / 0.2));
}
public void roll_ki(float ki)
{
println("roll ki : " + ki);
Comport.write('b');
Comport.write((int)(ki/0.005));
}
public void roll_kd(float kd)
{
println("roll kd : " + kd);
Comport.write('c');
Comport.write((int)((kd+0.01)/0.1));
}
public void pitch_kp(float kp)
{
println("pitch kp : " + kp);
Comport.write('d');
Comport.write((int)((kp+0.01)/0.2));
}
public void pitch_ki(float ki)
{
println("pitch ki : " + ki);
Comport.write('e');
Comport.write((int)(ki/0.005));
}
public void pitch_kd(float kd)
{
println("pitch kd : " + kd);
Comport.write('f');
Comport.write((int)((kd+0.01)/0.1));
}
public void yaw_kp(float kp)
{
println("yaw kp : " + kp);
Comport.write('g');
Comport.write((int)((kp+0.01)/0.2));
}
public void yaw_ki(float ki)
{
println("yaw ki : " + ki);
Comport.write('h');
Comport.write((int)(ki/0.005));
}
public void yaw_kd(float kd)
{
println("yaw kd : " + kd);
Comport.write('i');
Comport.write((int)((kd+0.01)/0.1));
}
설명#1에서 언급을 했었습니다.
설명#1에서 언급한 내용
"roll_kp"라는 변수를 기억하시고 다음 코드를 확인해 보시죠
public void roll_kp(float kp)
{
println("roll kp : " + kp);
Comport.write('a');
Comport.write((int)((kp + 0.01) / 0.2));
}
public으로 roll_kp 라는 함수를 정의해주고 있습니다. roll_kp는 콜백 함수이며 addSlider 함수에서 사용된 roll_kp가 여기서 정의된 함수 이름입니다. 따라서 우리가 GUI 상에서 roll_kp 슬라이더를 스크롤 하게 된다면 이벤트가 발생하게 되어서 roll_kp 함수가 호출되는 것입니다. 따라서 매개변수 kp에 슬라이더의 현재 위치값이 넘어오게 되며 write 함수를 호출해서 아두이노 드론으로 'a'라는 값과 (kp + 0.01) / 0.2 값을 차례대로 보내주고 있습니다.
Q. 그러면 여기서 왜 그냥 0.2로 나누어 주면 되는것을 0.01를 왜 더해주는건가??
→ 만약에 Kp 값이 1.999라고 치면 Kp 변수가 실수라서 0.2 간격으로 정확하게 값을 표하시는 경우가 발생 됩니다. 따라서 0.01을 더해서 2.009를 만들어 0.2로 나누게 되면 10.045가 됩니다. 이 값을 정수화를 시켜주면 Kp 매개변수는 10이 되게 됩니다.
'드론' 카테고리의 다른 글
| [드론] PID 출력값에 따라 드론 모터속도 계산하기 (2) | 2016.09.12 |
|---|---|
| [드론] 프로세싱에서 받은 매개변수를 아두이노 드론에 적용하기 (2) | 2016.09.08 |
| [드론] 프로세싱으로 PID 출력 보여지게 하기 (2) | 2016.09.07 |
| [드론] 아두이노에서 PID출력을 프로세싱으로 보내기 (1) | 2016.09.06 |
| [드론] 아두파일럿(아두이노 드론) 공부 순서 (3) | 2016.09.06 |