We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hello,
I am try to control image fade and pixel sorting with a MaxBotix sensor using an Arduino. The readings are correct in the Serial Monitor, but I am getting wildly inaccurate numbers in Processing. Code Below:
Arduino:
//Feel free to use this code.
//Please be respectful by acknowledging the author in the code if you use or modify it.
//Author: Bruce Allen
//Date: 23/07/09
const int anPin = 1;
//variables needed to store values
long anVolt, inches, cm;
int sum = 0; //Create sum variable so it can be averaged
int avgrange = 60; //Quantity of values to average (sample size)
void setup()
{
Serial.begin(9600);
}
void loop()
{
for (int i = 0; i < avgrange ; i++)
{
anVolt = analogRead(anPin) / 2;
sum += anVolt;
delay(10);
}
inches = sum / avgrange;
cm = inches * 2.54;
Serial.write(inches);
Serial.print(inches);
Serial.print("in, ");
Serial.print(cm);
Serial.print("cm");
Serial.println();
//reset sample total
sum = 0;
delay(500);
}
Processing
import processing.video.*;
import processing.sound.*;
import processing.serial.*;
//Media variables
Movie YW;
SoundFile DS1, DS2;
PImage bg, mom, sorted, sonja, test;
//Port
Serial port;
//Sound/Image
float picAlpha = 0;
float vol = 0;
//Glitch
int passes = 64;
int square = 8;
boolean select = false;
int selX = 0;
int selY = 0;
int glitchX = 0;
int glitchY = 0;
boolean vertical = false;
boolean fullSort = false;
//Sensor
int val;
void setup() {
size(1050, 700);
//image
bg = loadImage("Sonja.jpg");
sonja = loadImage("Sonja.png");
mom = loadImage("Mom.png");
sorted = mom;
//video
YW = new Movie(this, "YW_1sm.mp4");
YW.loop();
//sound
DS1 = new SoundFile(this, "DigitalStorge_1.mp3");
DS1.loop();
DS1.amp(.75);
DS2 = new SoundFile(this, "DigitalStorge_2.mp3");
DS2.loop();
//sensor
String portName = Serial.list()[1];
port = new Serial(this, portName, 9600);
}
void draw() {
noCursor();
//sensor
if (port.available() > 0) {
//val = port.readStringUntil('\n');
val = port.read();
}
print(val);
print("in");
println();
//background
blendMode(BLEND);
tint(255, 255);
image(bg, 0, 0);
//video
blendMode(SUBTRACT);
tint(255, 255);
image(YW, 0, 0, 1050, 700);
//Sonja
blendMode(BLEND);
tint(255, 255);
image(sonja, 0, 0);
//Interaction
picAlpha = map(val, 48, 0, 0, 225);
vol = map(val, 48, 0, 0, 1.0);
glitchX = round(map(val, 24, 0, 300, 650));
glitchY = round(map(val, 24, 0, 100, 550));
//Mom
blendMode(HARD_LIGHT);
tint(255, picAlpha);
image(mom, 0, 0, 1050, 700);
image(sorted, 0, 0);
//Glitch
if (val < 24) {
if (select) {
sorted = mom;
if (vertical) {
if (fullSort) {
fullSortV(selX, selY, glitchX, glitchY);
} else {
sortV(selX, selY, glitchX, glitchY);
}
} else {
if (fullSort) {
fullSortH(selX, selY, glitchX, glitchY);
} else {
sortH(selX, selY, glitchX, glitchY);
}
}
select = false;
} else {
select=true;
selX = glitchX;
selY = glitchY;
}
}
DS2.amp(vol);
}
void movieEvent(Movie m) {
m.read();
}
//Glitch
void sortH(int startx, int starty, int endx, int endy) {
int index;
int index2;
int swap;
for (int y = starty; y<endy; y++) {
for (int i =0; i<passes; i++) {
for (int x = startx+1; x<endx; x++) {
index = x+y*mom.width;
index2 = index-1;
if (mom.pixels[index] < mom.pixels[index2]) {
swap = mom.pixels[index];
mom.pixels[index] = mom.pixels[index2];
mom.pixels[index2] = swap;
}
}
}
}
}
void fullSortH(int startx, int starty, int endx, int endy) {
int index;
int index2;
int swap;
boolean swapped = false;
for (int y = starty; y<endy; y++) {
do {
swapped=false;
for (int x = startx+1; x<endx; x++) {
index = x+y*mom.width;
index2 = index-1;
if (mom.pixels[index] < mom.pixels[index2]) {
swap = mom.pixels[index];
mom.pixels[index] = mom.pixels[index2];
mom.pixels[index2] = swap;
swapped = true;
}
}
} while (swapped);
}
}
void sortV(int startx, int starty, int endx, int endy) {
int index;
int index2;
int swap;
for (int x = startx; x<endx; x++) {
for (int i =0; i<passes; i++) {
for (int y = starty+1; y<endy; y++) {
index = x+y*mom.width;
index2 = index-mom.width;
if (mom.pixels[index] < mom.pixels[index2]) {
swap = mom.pixels[index];
mom.pixels[index] = mom.pixels[index2];
mom.pixels[index2] = swap;
}
}
}
}
}
void fullSortV(int startx, int starty, int endx, int endy) {
int index;
int index2;
int swap;
boolean swapped = false;
for (int x = startx; x<endx; x++) {
do {
swapped=false;
for (int y = starty+1; y<endy; y++) {
index = x+y*mom.width;
index2 = index-mom.width;
if (mom.pixels[index] < mom.pixels[index2]) {
swap = mom.pixels[index];
mom.pixels[index] = mom.pixels[index2];
mom.pixels[index2] = swap;
swapped = true;
}
}
} while (swapped);
}
}
Answers
https://forum.Processing.org/two/discussion/16618/processing-with-arduino-void-serialevent#Item_1
I incorporated the suggested changes, but now it doesn't map. Error message: "The method map(float, float, float, float, float) in the type PApplet is not applicable for the arguments (int[], int, int, int, int)."
1st argument
int[]
means you're passing a whole array.You need to access them 1 by 1 via the operator
[]
:https://Processing.org/reference/arrayaccess.html
https://www.arduino.cc/en/Serial/Print
https://www.arduino.cc/en/Serial/write
In your arduino code:
Do you intend to do this? You are sending a byte value (truncated if inches is out of the byte range) followed by the ascii representation of your number (plus other string info). I will suggest you remove the write reference as you won't need it.
Now your Processing code. You have two issues:
#1: You have this in your code:
The draw() function in processing works like this: https://processing.org/reference/draw_.html
The point to keep in mind in your case is that draw executes 60 fps (or it tries to). You are applying these operation on the image 60fps. Why not to do it once in setup and accumulate all these operation is a second image buffer and use it in draw() instead of performing these operations 60fps?
#2: What GoToLoop mention in his last post. If you check your arduino code, you are doing this (I am assuming you are not using the write() function:
So your data stream looks like this:
##in, ##cm\n....
However, when you read the data in Processing, you are reading one byte at the time:
You should be using your commented out code instead:
val = port.readStringUntil('\n');
Then, it is here where you follow GoToLoop's post:
int[] input = int(split(val));
and your line 64 above should look like this instead:This mix of numbers and letters is undesirable. Check the following code by itself (you can run it in Processing in a new separate window):
As you see, neither int() nor Integer.parseInt() will succeed in this operation. This can be solved by doing this in your arduino code:
This might not solve all your issues, but it should make your code operational for the next debugging phase if you encounter any other problems.
Kf
Can you clarify what you mean you state: "Why not to do it once in setup and accumulate all these operation is a second image buffer and use it in draw() instead of performing these operations 60fps?" Specifically, how do I create the second image buffer?
@kinesthtiaSonja --
Use
PGraphics pg
andcreateGraphics()
to make the image buffer. Then in setup act on the PGraphics object rather than the canvas with your with your commands:pg.blendMode()
pg.image()
etc. Finally, display your buffer in draw w egimage(pg, 0, 0)
https://processing.org/reference/PGraphics.html
The PGraphics implementation should improve performance but it is not mandatory. I believe applying blendingModes is expensive and your sketch can easily be optimized. However, if you don't have any issues related to lagging, then you can leave it as it is and focus in the arduino part for now.
Using a second PGraphics is not difficult. If you check jeremydouglass'es post you can see an example of its usage. If you have problems implementing it, just ask.
Kf
I changed the code as follows to connect with Arduino using Firmata, and it is working now.
However, the volume of one of the soundtracks is supposed to change in relation to movement sensor (DS2), but instead it just plays at the same volume the whole time. Also, I receive this message: "ERROR: /node/free: Cannot free root node 0." I changed the files from stereo to mono, but I still receive this message.
Are you calling DS2.stop() in your code by any chance?
Kf
I am not calling DS2.stop(). I added an if, else statement that resolved the issues with volume.
At the moment, when I leave the images as is, it works fine. However, if I want to set it up so the images fit the resolution of the screen, it lags. The blending modes are needed because the images are layered a particular way, and if I remove them they don't appear properly. I am trying to figure out the PGraphics method to create a buffer, but I am not clear on how to go about this: do I create one for each image or just one overarching buffer?
@kinesthtiaSonja
Can you explain your code, what it suppose to do? Base on functionality, one could come up with an optimized code. Notice that doing resizing and applying blending (or any image operations) in draw could create program overloading aka. lagging issues as you might know by now. You could experience some improvement in your results if you use P2D renderer and if your computers supports accessing Video card resources. However, the key point is to optimize your code but reducing unnecessary operations in draw. If you provide this info, you will get more feedback about how to use PGraphics to alleviate overloading. Notice the suggestion of PGraphics was an idea based on a quick review of your code but without fully understanding it. Also I notice you are working with an arduino so it will limit the number of responses you get. People could always provide extra details to your application but without to be able to run the code, one cannot easily test the layer added by the arduino data. My suggestion: Create a second sketch that does not use arduino. Work on this sketch to get the effect you want (apply proper optimizations) and then migrate it to use your Arduino data.
Kf