티스토리 뷰
프로세싱에서 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 |