This is my first post so I apologize in advance if anything is unclear and I will try to learn quickly. I am also a newbie when it comes to programming. Using Arduino Uno, Ultrasonic Sensor HC-SR04, Processing3.5.3
In the processing and Arduino sketches I have provided I am able to play an image sequence, and when the ultrasonic sensor picks up the distance of an object a "1" is printed in the processing console.
I am wondering if I can use this "1" to make an if statement. If the console prints a number larger than 0, then have the image sequence play--else, only one image will be drawn (The gif will pause). I have tried a couple versions of this, but I don't want to pretend like I know what I am doing.
Any leads for me to follow would be wonderful! Or tutorials online!
I feel like there is something incredibly simple that I am just missing... I guess nothing is ever that simple. Thank you for your time :))
ARDUINO CODE:
#define trigPin 9
#define echoPin 10
void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
long distance;
digitalWrite(trigPin, LOW);
delayMicroseconds(2); //CHANGE THIS??
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
distance = pulseIn(echoPin, HIGH);
if (distance <= 2000) { //raise this number to raise the distance to wave hand
Serial.print("1");
} else {
Serial.print("0");
}
delay(500);
}
PROCESSING
import processing.serial.*;
int numFrames = 22; //number of frames in animation
int currentFrame = 0;
PImage[] image = new PImage[22];
Serial myPort;
String instring = "";
void setup() {
myPort = new Serial(this, Serial.list()[1], 9600);
myPort.bufferUntil('\n');
size(1600, 900);
frameRate(30);
background(0);
//Load images below
for(int i = 0; i<image.length; i++) {
image[i] = loadImage("PatMovingFace" + i + ".png");
}
}
void draw() {
//ALL BELOW connects to arduino sensor
while (myPort.available () > 0) {
instring = myPort.readString();
println(instring);
int sensorAct = Integer.parseInt(instring, 10);
}
playGif();
}
// ALL BELOW will make the pic array animate! Image moves!
void playGif() {
currentFrame = (currentFrame+1) % numFrames; //use % to cycle through frames!
int offset = 0;
for (int i = 0; i < image.length; i++) {
//image(image[i] % numFrames), 0, 0);
image(image[(currentFrame + offset) % numFrames], 0, 0);
offset += 0;
image(image[(currentFrame + offset) % numFrames], 0, 0);
offset+= 0;
}
}
You could simpify / cleanup playGif()
first:
offset
doesn't seem to do anything at the moment (it "increments" from 0 to 0)image()
is called twice with the same coordinates overdrawing the same content on top of itself. once image()
call should docurrentFrame
is increment to the next frame and loops back to the start at the start of playGif()
, however, when rendering the image, the array index is incremented by offset
(0) again. it's unclear what the intention is. you can do withoutcurrentFrame
can control play/pause: if it increments it plays, otherwise it's paused. it's good to have a separation between updating data (currentFrame
) and rendering with updated data (image(image[currentFrame],0,0)
)image
array to images
so it's more representative of what it is and it's harder to get confused between that and the image()
functionFor example playGif()
could turn to:
void playGif(){
currentFrame = (currentFrame+1) % numFrames; //use % to cycle through frames!
image(image[currentFrame], 0, 0);
}
Regarding control using Arduino, as mentioned above, simply check if you get a "1" to update currentFrame
(otherwise it will stay(paused) at the same value):
void playGif(){
if(instring.equals("1")){
currentFrame = (currentFrame+1) % numFrames; //use % to cycle through frames!
}
image(image[currentFrame], 0, 0);
}
I'm using equals()
above, because it's a String
, even though you are sending a single character. (alternatively comparing the first character would've worked if(instring.charAt(0) == '1')
)
I have a few notes on that as well:
print()
, not println()
, which means no \n
will be sent, hence no need for myPort.bufferUntil('\n');
nor instring = myPort.readString();
myPort.read();
(which you can by the way compare with ==
(instead of String's equals()
) (e.g. if(myPort.read() == '1'){...
)while
is blocking and I recommend not using it. It won't make a huge difference in your case since you're sending a single byte, but on more complex programs that send more bytes this will block Processing from rendering a single frame until it's received all the dataHere's an example:
import processing.serial.*;
int numFrames = 22; //number of frames in animation
int currentFrame = 0;
PImage[] images = new PImage[numFrames];
Serial myPort;
void setup() {
myPort = new Serial(this, Serial.list()[1], 9600);
size(1600, 900);
frameRate(30);
background(0);
//Load images below
for (int i = 0; i < numFrames; i++)
{
images[i] = loadImage("PatMovingFace" + i + ".png");
}
}
void draw() {
// if there's at least one byte to read and it's '1'
if(myPort.available() > 0 && myPort.read() == '1'){
// increment frame, looping to the start
currentFrame = (currentFrame+1) % numFrames; //use % to cycle through frames!
}
// render current frame
image(images[currentFrame], 0, 0);
}
A more cautious version, checking for what coould go wrong (serial connection, data loading) would look like this:
import processing.serial.*;
int numFrames = 22; //number of frames in animation
int currentFrame = 0;
PImage[] images = new PImage[numFrames];
Serial myPort;
void setup() {
String[] ports = Serial.list();
int portIndex = 1;
if(ports.length <= portIndex){
println("serial ports index " + portIndex + " not found! check cable connection to Arduino");
println("total ports: " + ports.length);
printArray(ports);
exit();
}
try{
myPort = new Serial(this, ports[portIndex], 9600);
}catch(Exception e){
println("error connecting to serial port: double check the cable is connected and no other program (e.g. Serial Monitor) uses this port");
e.printStackTrace();
}
size(1600, 900);
frameRate(30);
background(0);
//Load images below
try{
for (int i = 0; i < numFrames; i++)
{
images[i] = loadImage("PatMovingFace" + i + ".png");
}
}catch(Exception e){
println("image loading error");
e.printStackTrace();
}
}
void draw() {
// if Arduino connection was successfull
if(myPort != null){
// if there's at least one byte to read and it's '1'
if(myPort.available() > 0 && myPort.read() == '1'){
// increment frame, looping to the start
currentFrame = (currentFrame+1) % numFrames; //use % to cycle through frames!
}
}else{
text("serial port not initialised", 10, 15);
}
if(images[currentFrame] != null){
// render current frame
image(images[currentFrame], 0, 0);
}else{
text("serial port not loaded", 10, 15);
}
}
or with the same thing in grouped using functions:
import processing.serial.*;
int numFrames = 22; //number of frames in animation
int currentFrame = 0;
PImage[] images = new PImage[numFrames];
final int SERIAL_PORT_INDEX = 1;
final int SERIAL_BAUD_RATE = 9600;
Serial myPort;
void setup() {
size(1600, 900);
frameRate(30);
background(0);
setupArduino();
//Load images below
loadImages();
}
void setupArduino(){
String[] ports = Serial.list();
int numSerialPorts = ports.length;
// optional debug prints: useful to double check serial connection
println("total ports: " + numSerialPorts);
printArray(ports);
// exit if requested port is not found
if(numSerialPorts <= SERIAL_PORT_INDEX){
println("serial ports index " + SERIAL_PORT_INDEX + " not found! check cable connection to Arduino");
//exit();
}
// try to open port, exit otherwise
try{
myPort = new Serial(this, ports[SERIAL_PORT_INDEX], SERIAL_BAUD_RATE);
}catch(Exception e){
println("error connecting to serial port: double check the cable is connected and no other program (e.g. Serial Monitor) uses this port");
e.printStackTrace();
//exit();
}
}
void loadImages(){
try{
for (int i = 0; i < numFrames; i++)
{
images[i] = loadImage("PatMovingFace" + i + ".png");
}
}catch(Exception e){
println("image loading error");
e.printStackTrace();
//exit();
}
}
void serialUpdateImage(){
// if Arduino connection was successfull
if(myPort != null){
// if there's at least one byte to read and it's '1'
if(myPort.available() > 0 && myPort.read() == '1'){
// increment frame, looping to the start
currentFrame = (currentFrame+1) % numFrames; //use % to cycle through frames!
}
}else{
text("serial port not initialised", 10, 15);
}
}
void displayCurrentImage(){
if(images[currentFrame] != null){
// render current frame
image(images[currentFrame], 0, 0);
}else{
text("image " + currentFrame + " not loaded", 10, 25);
}
}
void draw() {
serialUpdateImage();
displayCurrentImage();
}