0%

使用controlP5為Processing建立UI

上一篇使用了Processing透過OSC控制NodeMCU,而控制的方法是使用鍵盤,並沒有使用任何的UI來控制,這一篇會為Processing的控制程式建立UI,並使用UI透過OSC來控制NodeMCU。

Arduino:

在arduino這邊,我們修改了上次的程式碼,新增了兩個外部的LED,一個為數位控制,另一個為類比控制,然後在OSC的部分,我們新增了一個新的函式led2來將從Processing端收到要類比控制的變數存進inputAnalog中,再進而去控制LED的亮暗程度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <OSCBundle.h>

char ssid[] = "your_SSID";
char pass[] = "your_Password";

WiFiUDP Udp; // A UDP instance to let us send and receive packets over UDP
const unsigned int localPort = 8000; // local port to listen for UDP packets at the NodeMCU (another device must send OSC messages to this port)
const unsigned int destPort = 9000; // remote port of the target device where the NodeMCU sends OSC to

int digitalLed = D4;
int ledState = 0;

int inputAnalog = 0;
int analogLed = D8;

void setup() {

pinMode(digitalLed, OUTPUT);
pinMode(analogLed,OUTPUT);

Serial.begin(115200);
//Set static IP
//WiFi.config(IPAddress(192, 168, 0, 11), IPAddress(192, 168, 0, 1), IPAddress(255, 255, 255, 0));
// Connect to WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid,pass);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(Udp.localPort());
}

void OSC() {
OSCMessage msgIN;
int size;
if ((size = Udp.parsePacket()) > 0) {
while (size--)
msgIN.fill(Udp.read());
if (!msgIN.hasError()) {
msgIN.route("/led", led); //if message is come from "/led",it will run function led
msgIN.route("/analogLed", led2); //if message is come from "/led",it will run function led
}
}
}

void led(OSCMessage &msg, int addrOffset) {
ledState = msg.getInt(0); //save recivied data to ledState
}

void led2(OSCMessage &msg, int addrOffset) {
inputAnalog = msg.getInt(0); //save recivied data to ledState
}


void loop() {
OSC();
digitalWrite(digitalLed,ledState);//if led State is 0,led will be light(nodemcu's LED_BUILTIN is reversed logic)
analogWrite(analogLed,inputAnalog);
}

Processing:

Processing的程式碼中,可以看到我們這次匯入了controlP5的library,如果沒有這個library請先去下載,這個library是方便我們用來建立UI的,在宣告變數的時候,先宣告slider與preSlider來存入UI中slider的變化與之前一次的變化,toggle與preToggle則是用來存入UI中toggle的變化與前一次的變化。

在setup中的這一段則是用來建立我們的UI,可以看到我們在addToggle與addSlider後面填入的是剛剛宣告過的toggleslider,這樣程式會自動將數值存入剛剛的變數中,再來下面就是設定位置、大小、數值、類型等等。

在draw中,會去判斷之前toggle與slider的狀態有沒有變化,有變化才會傳送資料出去,避免造成系統資源無謂的浪費。

1
2
3
4
5
6
7
8
9
10
11
12
cp5 = new ControlP5(this);
cp5.addToggle("toggle")
.setPosition(100, 100)
.setSize(50, 20)
.setValue(false)
.setMode(ControlP5.SWITCH)
;
cp5.addSlider("slider")
.setPosition(50, 50)
.setRange(0, 255)
.setSize(20, 100)
;
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import oscP5.*;
import netP5.*;
import controlP5.*;

// OSC
OscP5 oscP5;
ControlP5 cp5;
NetAddress NodeMCULocation;
String HOST = "nodemcu's IP"; //nodemcu's IP
int HOST_PORT = 8000; //port for Ground_Control Computer
int LOCAL_PORT = 9000; //port for my incoming port

int slider = 0;
int preSlider;
boolean toggle = false;
boolean preToggle;

void setup() {
size(200, 200);
cp5 = new ControlP5(this);
cp5.addToggle("toggle")
.setPosition(100, 100)
.setSize(50, 20)
.setValue(false)
.setMode(ControlP5.SWITCH)
;
cp5.addSlider("slider")
.setPosition(50, 50)
.setRange(0, 255)
.setSize(20, 100)
;
// OSC SETUP
oscP5 = new OscP5(this, LOCAL_PORT);
NodeMCULocation = new NetAddress(HOST, HOST_PORT);
}

void draw() {
background(0);
if (preToggle!=toggle) {
if (toggle == true) {
sendControlInt("/led", 1);
} else {
sendControlInt("/led", 0);
}
}
if (preSlider!=slider) {
sendControlInt("/analogLed", slider);
}
preSlider = slider;
preToggle = toggle;
}

void sendControlInt(String tag, int val) {
OscMessage myOscMessage = new OscMessage(tag);
myOscMessage.add(val);
oscP5.send(myOscMessage, NodeMCULocation);
print(tag+",");
println(val);
}

運行結果:

20624662_1632743040071884_27309609_n