Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dropmeaword/e4c81b8aa5dacc4bee7411736670c593 to your computer and use it in GitHub Desktop.
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.
// (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