Last active
June 10, 2019 12:44
-
-
Save dropmeaword/e4c81b8aa5dacc4bee7411736670c593 to your computer and use it in GitHub Desktop.
Serial input to Wekinator, supporting both micro:bit and Arduino inputs, made for Deborah's wekinator project.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (c) 2019 DATA Design, Art and Technology Arnhem | |
// for and by Deborah Mora | |
// BASED ON: | |
// Sends BBC micro:bit to OSC | |
// By Rebecca Fiebrink: January 2016 | |
// Sends to port 6448 using OSC message /wek/inputs | |
// Number of features varies according to feature selection in user drop-down (more info on screen) | |
// @NOTE communication with external devices is expected at 115200 | |
import processing.serial.*; | |
import controlP5.*; | |
import java.util.*; | |
import oscP5.*; | |
import netP5.*; | |
// @NOTE this is the number that you have to put in the | |
// Serial.begin of your Arduino sketch | |
final int SERIAL_BAUD_RATE = 115200; | |
// @NOTE change to the correct port names for each of the devices | |
// connected to your computer, if you use a USB hub these might change | |
// so watch out!!! | |
final String PORT_MICROBIT = "/dev/tty.SLAB_USBtoUART"; //= "/dev/tty.usbmodem14202"; | |
final String PORT_ARDUINO = "/dev/tty.wchusbserial1410"; //= "/dev/tty.usbmodem14101"; | |
// GUI stuff | |
ControlP5 cp5; | |
PFont fBig; | |
CColor defaultColor; | |
float []sample; | |
// Serial port info: | |
int numPorts = 0; | |
Serial portMbit; // The serial port | |
Serial portArduino; // The serial port | |
int b1 = 0, | |
b2 = 0, | |
previousB1 = 0, | |
previousB2 = 0; | |
String serial; // declare a new string called 'serial' . A string is a sequence of characters (data type know as "char") | |
int numFeatures = 0; | |
String featureString = ""; | |
//Objects for sending OSC | |
OscP5 oscP5; | |
NetAddress dest; | |
void setup() { | |
size(300, 400); | |
sample = new float[7]; | |
cp5 = new ControlP5(this); | |
textAlign(LEFT, CENTER); | |
fBig = createFont("Arial", 12); | |
// list all available serial ports | |
List l = Arrays.asList(Serial.list()); | |
if(null == PORT_MICROBIT) { | |
//Populate serial port options: | |
numPorts = l.size(); | |
cp5.addScrollableList("Microbit") //Create drop-down menu | |
.setPosition(10, 75) | |
.setSize(200, 100) | |
.setBarHeight(20) | |
.setItemHeight(20) | |
.addItems(l) | |
; | |
} else { | |
if( open_device_mbit() ) { | |
println("Opened micro:bit on port " + PORT_MICROBIT); | |
} | |
} | |
defaultColor = cp5.getColor(); | |
if(null == PORT_ARDUINO) { | |
cp5.addScrollableList("Arduino") //Create drop-down menu | |
.setPosition(10, 200) | |
.setSize(200, 100) | |
.setBarHeight(20) | |
.setItemHeight(20) | |
.addItems(l) | |
; | |
} else { | |
if( open_device_arduino() ) { | |
println("Opened Arduino on port " + PORT_ARDUINO); | |
} | |
} | |
// Set up OSC: | |
oscP5 = new OscP5(this, 9000); | |
dest = new NetAddress("127.0.0.1", 6448); | |
} // setup() | |
boolean open_device_mbit() { | |
portMbit = new Serial(this, PORT_MICROBIT, SERIAL_BAUD_RATE); | |
return (portMbit != null); | |
} | |
boolean open_device_arduino() { | |
portArduino = new Serial(this, PORT_ARDUINO, SERIAL_BAUD_RATE); | |
return (portArduino != null); | |
} | |
//Called in a loop at frame rate (100 Hz) | |
void draw() { | |
background(240); | |
textFont(fBig); | |
frameRate(20); | |
fill(0); | |
text("multi-hardware to OSC\nbased on work by Rebecca Fiebrink", 10, 15); | |
text("micro:bit on port " + PORT_MICROBIT, 10, 60); | |
text("Arduino on port " + PORT_ARDUINO, 10, 80); | |
text("Accelerometers: " + sample[3], 10, 120); | |
text(sample[4], 150, 120); | |
text(sample[5], 200, 120); | |
text("Buttons: " + sample[1] + " " + sample[2], 10, 140); | |
serial_pump(); | |
text("Sending" + numFeatures + " values to port 6448, message /wek/inputs", 10, 320); | |
} | |
String[] parse_serial(Serial port, char separator) { | |
String[] retval = null; | |
String reading = null; | |
if(null == port) { println("port isn't valid"); return null; } | |
while (port.available() > 0 ) { | |
reading = port.readStringUntil('\n'); | |
reading = trim(reading); | |
} | |
println("reading: " + reading); | |
if (reading != null) { // if the string is not empty, print the following | |
retval = split(reading, separator); | |
} | |
return retval; | |
} // arduino_parse_serial | |
void serial_pump() { | |
int features = 0; | |
// read incoming strings from serial | |
String []mvalues = parse_serial(portMbit, '\t'); | |
String []avalues = parse_serial(portArduino, ','); | |
StringBuilder sb = new StringBuilder(); | |
if(null != mvalues) { | |
// convert m:bit incoming to foating point features | |
try { | |
for (int i = 1; i < mvalues.length; i++) { | |
int reading = Integer.parseInt(mvalues[i]); | |
sample[i-1] = float(reading); | |
sb.append(String.format("%.2f", sample[i-1])).append(" "); | |
features++; | |
// if button A | |
if(i == 1) { | |
b1 = reading; | |
} else if (i == 2) { // button B | |
b2 = reading; | |
} | |
} // for | |
} catch (Exception ex) { | |
println("Encountered exception parsing m:bit serial input: " + ex); | |
} | |
} | |
if(null != avalues) { | |
// convert arduino incoming to foating point features | |
try { | |
int offset = 5; // how far into the samples array are the arduino samples? | |
for (int i = 0; i < avalues.length; i++) { | |
sample[i+offset] = Float.parseFloat(avalues[i]); | |
sb.append(String.format("%.2f", sample[i+offset])).append(" "); | |
features++; | |
} | |
} catch (Exception ex) { | |
println("Encountered exception parsing arduino serial input: " + ex); | |
} | |
} else { println("Didn't read anything from Arduino"); } | |
featureString = sb.toString(); | |
println("features: " + featureString); | |
if( features > 0 ) { | |
osc_send_features( sample ); | |
} | |
} | |
void osc_send_features(float []features) { | |
int cntfeatures = 0; | |
// PREPARE INPUT FEATURES FOR WEKINATOR | |
// ////////////////////////////////////////////////////////////////////////////////// | |
// @NOTE for deborah, added this to send to wekinator the data we just read from the micro:bit | |
OscMessage msg = new OscMessage("/wek/inputs"); | |
// add params | |
for(int i = 0; i < features.length; i++) { | |
msg.add(features[i]); | |
cntfeatures++; | |
} | |
// dispatch osc message | |
println("Sending /wek/inputs with " + cntfeatures + " features"); | |
oscP5.send(msg, dest); | |
// PREPARE TO SEND CONTROL MESSAGES TO WEKINATOR (like recording features, training, etc.) | |
// /////////////////////////////////////////////////////////////////////////////////////// | |
// @NOTE this bit was written for Deborah's work | |
if( (b2 == 1) && (previousB2 == 0) ) { // if button B is pressed (1) and the previous state was 0 -> we want to do this only once | |
OscMessage msg2 = new OscMessage("/wekinator/control/startRecording"); // then we start the recording | |
oscP5.send(msg2, dest); | |
previousB2 = 1; | |
println("Learning from examples began"); | |
} | |
if( (previousB2 == 1) && (b2 == 0) ) { // if button B was pressed and now it is released (0) -> we want to do this only once | |
OscMessage msg2 = new OscMessage("/wekinator/control/stopRecording"); // then we stop the recording | |
oscP5.send(msg2, dest); | |
previousB2 = 0; | |
println("Learning from examples ended"); | |
OscMessage msg3 = new OscMessage("/wekinator/control/train"); // then we stop the recording | |
oscP5.send(msg3, dest); | |
println("Command to train sent"); | |
} | |
} // osc_send_features |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment