Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Physical Computing
Serial To OSC Template for Processing
Commits
7257fe19
Commit
7257fe19
authored
Feb 06, 2019
by
Evan Raskob
Browse files
added fleshed out serial call and response API for analogue ports with bug fixes
parent
e00a8c10
Changes
7
Hide whitespace changes
Inline
Side-by-side
AnalogSerialAPI/AnalogSerialAPI.ino
0 → 100644
View file @
7257fe19
/*
An example showing how to define a simple call and response serial API
between Arduino and Processing.
*/
void
setup
()
{
Serial
.
begin
(
57600
);
while
(
!
Serial
);
}
const
unsigned
int
bufferSize
=
256
;
// number of bytes we can read
char
buffer
[
bufferSize
];
int
charsRead
=
0
;
// amount of bytes we've read
void
loop
()
{
// we need this while loop to fully empty the serial buffer
while
(
Serial
.
available
())
{
char
charRead
=
(
char
)
Serial
.
read
();
// be careful not to go over the buffer size (with room
// for string terminator character)!
// note that this doesn't stop the loop - we ignore
// extra bytes
if
(
charsRead
<
bufferSize
)
{
if
(
charRead
!=
'\n'
)
{
buffer
[
charsRead
]
=
charRead
;
charsRead
=
charsRead
+
1
;
// for testing:
// Serial.print(charsRead);
}
else
{
//Serial.println("process command[");
//Serial.print(charsRead);
//Serial.print("]\n");
buffer
[
charsRead
]
=
'\0'
;
// terminate string
// process results
//Serial.print(':');
//Serial.print(buffer);
//Serial.println(':');
// now handle bytes read
// NXXX means note
// sscanf reads the values and stores them in variables we just declared. %d represents a number of digits to read
// the "n" returned by this function is the number of matches. Whitespace is ignored, by default.
// our protocol - 1 character (means an 'action' we perform)
// followed by up to 3 int numbers separated by ,'s
// we do NOT expect to get negative numbers
// we do not expect a cmd character of '-'
const
int
INVALID
=
-
1
;
char
cmd
=
'-'
;
// the command character: don't expect to read
int
a
=
INVALID
;
// number 1
int
b
=
INVALID
;
// number 2
int
c
=
INVALID
;
// number 3
// define a protocol: call and response for analogue values
// cmd character 'a' means read an analogue port,
// then we expect a port number for variable a
// for example, "a0" means read and return port A0
// that also means "a0,1,2" because we ignore everything after the 1st argument
int
n
=
sscanf
(
buffer
,
"/%c,%d,%d,%d"
,
&
cmd
,
&
a
,
&
b
,
&
c
);
const
int
ANALOGUE_PORTS
=
6
;
const
int
portMappings
[]
=
{
A0
,
A1
,
A2
,
A3
,
A4
,
A5
};
int
port
=
INVALID
;
if
(
cmd
==
'a'
)
{
if
(
a
!=
INVALID
&&
a
<
ANALOGUE_PORTS
&&
a
>=
0
)
{
port
=
portMappings
[
a
];
int
sensorValue
=
analogRead
(
port
);
// echo back command in same format
Serial
.
print
(
'/'
);
Serial
.
print
(
cmd
);
Serial
.
print
(
","
);
Serial
.
print
(
a
);
Serial
.
print
(
","
);
Serial
.
println
(
sensorValue
);
// send value, end command
}
else
{
Serial
.
println
(
"ERROR MESSAGE HERE"
);
}
}
charsRead
=
0
;
// go back to beginning of buffer for next command
}
}
// otherwise too many bytes!
else
{
//Serial.print("looped");
// loop back around, so we drain all serial data waiting
charsRead
=
0
;
}
}
}
P5OscApp/P5OscApp.pde
0 → 100644
View file @
7257fe19
/**
* VisualiseWekinatorOSC by Evan Raskob
* For visualising OSC messages from Arduino to Wekinator
*
* TODO: pause button
*/
import
oscP5
.
*
;
import
netP5
.
*
;
import
controlP5
.
*
;
import
java
.
util
.
List
;
import
java
.
util
.
Collections
;
/**
* this is the list of commands that we've received via serial.
* will be handled in draw() call at the current framerate.
*/
List
<
OscMessage
>
oscMessagesReceived
=
Collections
.
synchronizedList
(
new
ArrayList
<
OscMessage
>
());
int
inPort
=
6969
;
//6449; // udp input, if needed (not used right now)
int
outPort
=
6161
;
//6448; // wekinator port or unity3d osc port, depending
String
ipAddress
=
"127.0.0.1"
;
// our computer
NetAddress
myRemoteLocation
;
OscP5
oscP5
;
ControlP5
gui
;
void
setup
()
{
size
(
800
,
600
);
frameRate
(
10
);
// start oscP5, listening for incoming messages at wekinator port
oscP5
=
new
OscP5
(
this
,
inPort
);
myRemoteLocation
=
new
NetAddress
(
ipAddress
,
outPort
);
gui
=
new
ControlP5
(
this
);
}
void
draw
()
{
background
(
0
);
for
(
int
i
=
0
;
i
<
6
;
i
++
)
{
// get analog value - send this to trigger Arduino to send back analogue read of A0
OscMessage
oscMsg
=
new
OscMessage
(
"/a"
);
oscMsg
.
add
(
i
);
// port A0 to A5
oscP5
.
send
(
oscMsg
,
myRemoteLocation
);
}
//this next line is because things might happen out of order
synchronized
(
oscMessagesReceived
)
{
// handle incoming messages from oscEvent()
for
(
int
i
=
0
;
i
<
oscMessagesReceived
.
size
();
i
++
)
{
OscMessage
msg
=
oscMessagesReceived
.
remove
(
0
);
String
command
=
msg
.
addrPattern
();
//print(command + ": ");
String
types
=
msg
.
typetag
();
//println(types);
// draw all analogue inputs as rainbow rectangles
if
(
command
.
equals
(
"/a"
)
&&
types
.
equals
(
"ii"
))
{
// draw a corresponding rectangle
float
x
=
width
/
6.0
*
msg
.
get
(
0
).
intValue
();
float
y
=
map
(
msg
.
get
(
1
).
intValue
(),
0
,
1023
,
0
,
height
-
10
);
colorMode
(
HSB
,
360
);
fill
(
msg
.
get
(
0
).
intValue
()
*
60
,
320
,
300
);
rect
(
x
,
0
,
width
/
6.0
,
10
);
rect
(
x
,
0
,
width
/
6.0
,
y
);
}
}
}
}
//
// this triggers whenever OSC messages are received and adds to the list of received messages
// you can ignore it and modify draw() above
//
void
oscEvent
(
OscMessage
theOscMessage
)
{
// add to synchronised list
synchronized
(
oscMessagesReceived
)
{
oscMessagesReceived
.
add
(
theOscMessage
);
}
}
P5SerialSendReceive/GUI.pde
View file @
7257fe19
...
...
@@ -84,11 +84,11 @@ void setupGUI() {
baudddl
.
getCaptionLabel
().
getStyle
().
marginLeft
=
3
;
baudddl
.
getValueLabel
().
getStyle
().
marginTop
=
3
;
//the baud options
for
(
int
i
=
0
;
i
<
serialRateStrings
.
length
;
i
++
)
{
for
(
int
i
=
serialRateStrings
.
length
-
1
;
i
>=
0
;
i
--
)
{
String
baudString
=
serialRateStrings
[
i
];
baudddl
.
addItem
(
baudString
,
i
);
}
baudddl
.
setValue
(
serialRateStrings
.
length
-
1
);
baudddl
.
setValue
(
0
);
//udp IP/port
ipAddressField
=
cp5
.
addTextfield
(
"IP address"
)
...
...
P5SerialSendReceive/OSC_Functions.pde
View file @
7257fe19
int
inPort
=
6449
;
// udp input, if needed (not used right now)
int
outPort
=
6448
;
// wekinator port
int
inPort
=
6161
;
//
6449; // udp input, if needed (not used right now)
//<>//
int
outPort
=
6969
;
//
6448; // wekinator port
or unity3d osc port, depending
String
ipAddress
=
"127.0.0.1"
;
// our computer
OscP5
oscP5
;
...
...
@@ -12,40 +12,119 @@ void setupOSC() {
ipAddress
=
ipAddressField
.
getText
();
outPort
=
Integer
.
parseInt
(
outgoingPortField
.
getText
());
myRemoteLocation
=
new
NetAddress
(
ipAddress
,
outPort
);
}
void
stopOSC
()
{
oscP5
.
stop
();
oscP5
.
stop
();
}
/**
* Look at the list of commands received and relay them
* via OSC properly.
*/
void
handleSerialCommands
()
{
synchronized
(
commandsReceived
)
{
// handle all commands in buffer
while
(
commandsReceived
.
size
()
>
0
)
{
String
command
[]
=
commandsReceived
.
remove
(
0
);
// remove first command
String
cmd
=
command
[
0
];
// There are a few ways to do this - you could look at the command and then
// create a cutsom OSC message based on it, for example:
/*
// handle analogue read
if (cmd.equals("/a")) {
float position = float(command[1]); // should be a number between 0 an 1023
position = map(position, 0, 1023, -4, 4);
// consume an "a" (analogue read) command
OscMessage myMessageX = new OscMessage("/CubeX");
myMessageX.add(position);
// send the message
oscP5.send(myMessageX, myRemoteLocation);
}
*/
// OR, you could just route it to OSC without touching it:
OscMessage
oscMsg
=
new
OscMessage
(
cmd
);
print
(
cmd
+
" "
);
for
(
int
i
=
1
;
i
<
command
.
length
;
i
++
)
{
int
arg
=
int
(
command
[
i
]);
// parse as number
// check it's valid!
if
(
arg
!=
INVALID
)
{
print
(
arg
+
" "
);
oscMsg
.
add
(
arg
);
// add as integer
}
}
println
();
// send the message
oscP5
.
send
(
oscMsg
,
myRemoteLocation
);
}
}
// done with all received commands
}
/**
* Handle incoming osc messages.
* Handle
s
incoming osc messages.
Just echoes them to the serial port.
*/
void
oscEvent
(
OscMessage
theOscMessage
)
{
drawIncomingOSC
();
/* print the address pattern and the typetag of the received OscMessage */
print
(
"### received an osc message."
);
print
(
" addrpattern: "
+
theOscMessage
.
addrPattern
());
print
(
" typetag: "
+
theOscMessage
.
typetag
());
print
(
" timetag: "
+
theOscMessage
.
timetag
());
if
(
theOscMessage
.
checkAddrPattern
(
"/tc"
)
==
true
)
{
/* check if the typetag is the right one. */
print
(
" TOTAL: "
+
theOscMessage
);
if
(
theOscMessage
.
checkTypetag
(
"sfiis"
))
{
/* parse theOscMessage and extract the values from the osc message arguments. */
String
textValue
=
theOscMessage
.
get
(
0
).
stringValue
();
float
sizeValue
=
theOscMessage
.
get
(
1
).
floatValue
();
int
thirdValue
=
theOscMessage
.
get
(
2
).
intValue
();
print
(
"### received an osc message /test with typetag sfiis."
);
println
(
" values: "
+
textValue
+
", "
+
sizeValue
+
", "
+
thirdValue
);
return
;
}
drawIncomingOSC
();
// give some visual feedback that something happened
/// print the address pattern and the typetag of the received OscMessage
//print("### received an osc message.");
//print(" addrpattern: "+theOscMessage.addrPattern());
//print(" typetag: "+theOscMessage.typetag());
//print(" timetag: "+theOscMessage.timetag());
String
command
=
theOscMessage
.
addrPattern
();
// hopefully something 1 character, like "/c"
String
types
=
theOscMessage
.
typetag
();
// this lets us know what data we received -- like "sfff"
// we'll put all arguments into an array of text (strings)
String
[]
args
=
new
String
[
types
.
length
()];
// go through all arguments for this message and appen to serial command.
for
(
int
i
=
0
;
i
<
types
.
length
();
i
++
)
{
char
type
=
types
.
charAt
(
i
);
switch
(
type
)
{
case
'f'
:
{
args
[
i
]
=
""
+
theOscMessage
.
get
(
i
).
floatValue
();
}
break
;
case
's'
:
{
args
[
i
]
=
""
+
theOscMessage
.
get
(
i
).
stringValue
();
}
break
;
case
'i'
:
{
args
[
i
]
=
""
+
theOscMessage
.
get
(
i
).
intValue
();
}
break
;
default:
println
(
"ERR: bad OSC type:"
+
type
);
}
// end switch
// finally, send the serial. Should be the command character followed by list of args separated by ,'s
String
cmdOut
=
command
+
","
+
String
.
join
(
","
,
args
);
//println(cmdOut);
serial
.
write
(
cmdOut
+
stopChar
);
}
}
P5SerialSendReceive/P5SerialSendReceive.pde
View file @
7257fe19
...
...
@@ -59,10 +59,13 @@ public void TEST_ON()
// Whatever is in here gets run when the TEST_ON button is pressed.
// the following works with the SerialSendReceiveTest sketch for Arduino to turn the LEDs on and off
serial
.
write
(
"ledon"
+
stopChar
);
//
serial.write("ledon" + stopChar);
// this one works with the SerialParseTest Arduino sketch:
// serial.write("n 1,0,0" + stopChar);
// AnalogSerialAPI trigger read of analogue port A0
serial
.
write
(
"a"
+
0
+
stopChar
);
}
println
(
"finished"
);
}
...
...
@@ -97,14 +100,21 @@ public void ERROR()
void
setup
()
{
// configure the screen size and frame rate
size
(
550
,
250
,
P3D
);
frameRate
(
30
);
setupGUI
();
frameRate
(
30
);
// sometimes this works better here!
}
void
draw
()
{
background
(
128
);
// first, only do something if we're connected to serial and running (START pushed)
if
(
applicationRunning
)
{
drawIncomingPackets
();
drawIncomingPackets
();
// update GUI with data received/sent
handleSerialCommands
();
//<>//
}
}
...
...
P5SerialSendReceive/Serial_functions.pde
View file @
7257fe19
...
...
@@ -3,6 +3,11 @@
SERIAL
************************************************************************************/
import
java
.
util
.
List
;
import
java
.
util
.
LinkedList
;
// for serial commands list
import
java
.
util
.
Collections
;
//the Serial communcation to the Arduino
Serial
serial
;
...
...
@@ -21,26 +26,86 @@ int serialListNumber = 2;
// we will store the incoming serial values in here
ArrayList
<
Byte
>
serialBuffer
=
new
ArrayList
<
Byte
>
();
/**
* this is the list of commands that we've received via serial.
* will be handled in handleSerialCommands() (OSC_Functions tab)
* which is run every draw() call at the current framerate.
*/
List
<
String
[]
>
commandsReceived
=
Collections
.
synchronizedList
(
new
LinkedList
<
String
[]
>
());
final
int
INVALID
=
-
1
;
// a bad command characer
// FYI: (from https://github.com/processing/processing/blob/master/java/libraries/serial/src/processing/serial/Serial.java)
// serialEvent() is invoked in the context of the current (serial) thread
// which means that serialization and atomic variables need to be used to
// guarantee reliable operation (and better not draw() etc..)
// serialAvailable() does not provide any real benefits over using
// available() and read() inside draw - but this function has no
// thread-safety issues since it's being invoked during pre in the context
// of the Processing applet
/**
* This handles the receiving of serial.
* @param {Serial} serial The serial port object
*/
void
serialEvent
(
Serial
serial
)
{
String
input
=
serial
.
readString
();
println
(
"serial received: "
+
input
);
String
[]
msgs
=
split
(
input
,
','
);
// "c,2,3,4" --> ["c", "2", "3", "4"]
// TODO: handle message here!
//void serialEvent(Serial serial) {
//}
/**
* This handles the receiving of serial and runs before draw() ( in pre() )
* whenever serial data is available. This copies all the serial port data
* into a list for later reading inside draw(). The advanage over using serialEvent()
* for processing data is that this way is thread safe.
*
* @param {Serial} serial The java serial port object
*/
void
serialAvailable
(
Serial
serial
)
{
// read input until we hit stop character (newline) and remove all leading and trailing special characters
// unfortunately, due to threading issues, this crashes the serial port when called
// too quickly!
//String input = trim( serial.readStringUntil(stopChar) );
String
serialIn
=
serial
.
readString
();
println
(
"serial received: "
+
serialIn
);
String
serialLines
[]
=
split
(
serialIn
,
stopChar
);
// we might have received a few lines of serial so we
// split them by the stop character (newline)
// for each line, parse it for commands
for
(
String
line
:
serialLines
)
{
String
input
=
trim
(
line
);
// trim away space characters and extra newlines etc.
// ex: splits a serial line of "a 324\n" to ["a", "324"]
String
[]
msgs
=
split
(
input
,
","
);
// check that we've got valid data
if
(
msgs
.
length
>
0
&&
msgs
[
0
]
!=
"-"
)
{
synchronized
(
commandsReceived
)
{
commandsReceived
.
add
(
msgs
);
}
}
}
// another way of doing this:
//ex: "c,2,3,4" --> ["c", "2", "3", "4"]
//String[] msgs = split(trim(input), ',');
}
/**
* Start the serial port reading based on the GUI
*/
void
setupSerial
()
{
// clear list of received serial
synchronized
(
commandsReceived
)
{
commandsReceived
.
clear
();
}
if
(
baud
<
1
)
{
// choose highest rate if none was selected
...
...
@@ -54,6 +119,14 @@ void setupSerial() {
}
}
/**
* Stop the serial port reading
*/
void
stopSerial
()
{
serial
.
stop
();
// clear list of received serial
synchronized
(
commandsReceived
)
{
commandsReceived
.
clear
();
}
}
oscSendReceiveUnity/oscSendReceiveUnity.pde
0 → 100644
View file @
7257fe19
/**
* oscP5sendreceive by andreas schlegel
* example shows how to send and receive osc messages.
* oscP5 website at http://www.sojamo.de/oscP5
*/
import
oscP5
.
*
;
import
netP5
.
*
;
OscP5
oscP5
;
NetAddress
myRemoteLocation
;
float
xPosition
=
0
;
// received x position of cube from Unity
float
zPosition
=
0
;
float
yPosition
=
0
;
void
setup
()
{
size
(
400
,
400
,
P3D
);
frameRate
(
40
);
// change this if unity gets overwhelmed
/* start oscP5, listening for incoming messages at port 6161 */
oscP5
=
new
OscP5
(
this
,
6161
);
// Unity out port from Unity object
/* myRemoteLocation is a NetAddress. a NetAddress takes 2 parameters,
* an ip address and a port number. myRemoteLocation is used as parameter in
* oscP5.send() when sending osc packets to another computer, device,
* application. usage see below. for testing purposes the listening port
* and the port of the remote location address are the same, hence you will
* send messages back to this sketch.
*/
myRemoteLocation
=
new
NetAddress
(
"127.0.0.1"
,
6969
);
//127.0.0.1 is a special address for this computer
}
void
draw
()
{
background
(
0
);
OscMessage
myMessageX
=
new
OscMessage
(
"/CubeX"
);
myMessageX
.
add
(
sin
(
millis
()
/
1000.0
));
/* send the message */
oscP5
.
send
(
myMessageX
,
myRemoteLocation
);
OscMessage
myMessageY
=
new
OscMessage
(
"/CubeY"
);
myMessageY
.
add
(
cos
(
millis
()
/
1000.0
));
/* send the message */
oscP5
.
send
(
myMessageY
,
myRemoteLocation
);
fill
(
255
);
// xPosition goes from 0-1
// startX,startY, endX, endY
//println(xPosition);
pushMatrix
();
translate
(
width
/
2
,
height
/
2
);
rotate
(
PI
);
translate
(
-
width
/
2
,
-
height
/
2
);
translate
(
xPosition
,
yPosition
,
zPosition
);
rect
(
0
,
50
,
width
/
8
,
100
);
popMatrix
();
}
void
mousePressed
()
{
/* in the following different ways of creating osc messages are shown by example */
OscMessage
myMessage
=
new
OscMessage
(
"/test"
);
myMessage
.
add
(
123
);
/* add an int to the osc message */
/* send the message */
oscP5
.
send
(
myMessage
,
myRemoteLocation
);
}
//
// HERE IS WHERE WE RECEIVE OSC
//
void
oscEvent
(
OscMessage
theOscMessage
)
{
// print the address pattern and the typetag of the received OscMessage
//print("### received an osc message.");