Mechanical Playback Device, solving small problems.

Hey everyone. I’m currently building a relatively simple playback device with an arduino and processing. I have the arduino hooked to a rotary encoder which is hooked to a hand crank. You turn the crank and then the encoder records the movement and sends it to processing and then it loops through a series of images, forwards or backwards. At the moment, it more or less works.

Problems I’m having at the moment:

*I think its too fast. If I turn the crank very slowly then the images tick one by one, which is nice. But If I turn the crank at a comfortable rate, and then stop. Then the program continues to cycle through several more images. My guess that this lag is because even just a single turn of the crank cycles through the encoder several times and the program is just struggling to catch up. Is there a way to slow this thing down? So that a turn of the hand crank doesnt cycle through the image sequence so fast? Either by changing the arduino code or the processing code?

*Also, is there a way to progressively rotate the images each time they appear? Like say, image appears with 0 rotation, next with 12 degree rotation, next with 24 degree rotation, etc. The image sequence is actually a wheel so I want to spin it a little bit as it cycles through the animations.

Thanks a bunch guys: here’s my code and a link to my encoder for reference:

Arduino code:

#include <QuadEncoder.h>

byte qe1Move=0;
QuadEncoder qe(8,9);

byte count = 0;

void setup() {
    Serial.begin(9600);
}

void loop() {
  qe1Move=qe.hb();
  if (qe1Move=='>')
  {
  count = count + 1;
  Serial.write(count);
  if (count>46)
  {
    count = 0;
  }
  }
  if (qe1Move=='<')
  {
  count = count - 1;
  Serial.write(count);
  if (count<2)
  {
    count = 48;
  }
  }
    //Serial.print(char(qe1Move));
  //else if (qe1Move=='<')
    
    //Serial.print(char(qe1Move));
    //delay(100);
}

Processing code:

import fullscreen.*; //Imports the Fullscreen library
import processing.serial.*;

 Serial myPort;  // The serial port
 FullScreen fs; //Creates an object called fs from the FullScreen class

 int numFrames = 48; //Total number of frames including the 0 
 int frame = 0;//Declares frame number
 int val; // Data received from the serial port
 PImage[] images;//Creates and object called images from PImage class

 void setup() 
 {
   images = new PImage[numFrames];//Assignes and array to the images object that will hold 48 images 
   size(1280, 720);
   frameRate(24);
   
   for ( int i = 0; i<numFrames; i++ )//A loop increments from 0 to 47
   {
     images[i] = loadImage("FriendlyFire_"+ i + ".png");//Assignes and exaxt name to each member of the array
   }
   //Note that this loop is an setup which means it will run only once when the program starts.

   fs = new FullScreen(this); //Declares the fs object as new fullscreen
  
   fs.enter(); //runs the fullscreen
   
   String portName = Serial.list()[0];
   myPort = new Serial(this, Serial.list()[0], 9600);

 } 

  
 void draw() 
 { 
   background(0);
   frame = ((frame+1) % numFrames);//Frame number increments until 48
   image(images[frame], 0, 0);//Displays the image
   if ( myPort.available() > 0) {  // If data is available,
    val = myPort.read();         // read it and store it in val
    }
   frame = val;
 }

Encoder:
http://www.sgbotic.com/index.php?dispatch=products.view&product_id=1093

Thanks a bunch guys. I’m new to this and to coding in general so I apologize ahead of time if I’m slow or confused with your responses.

I’m very appreciative, I really gotta try to get this thing working by the end of the weekend. Thanks again!

My guess that this lag is because even just a single turn of the crank cycles through the encoder several times and the program is just struggling to catch up.

No. It is because each change in encoder value is sent. If you turn the crank fast, a lot of data is sent. That data gets buffered, and Processing takes a while to catch up.

What I think you want to do is send data every few milliseconds, ignoring some encoder values. For instance, if the encoder is turned rapidly, and in the space of 100 milliseconds, the value goes from 0 to 100, you are sending 0,1, 2, 3, ... 98, 99, 100. If you sent the value every 10 milliseconds, instead, you might only send 0, 12, 25, 30, 41, 56, 67, 72, 81, 90, and 93. A lot less data, and Processing would empty the buffer quicker.

Also, how Processing handles draw() is a little different from how Arduino handles loop(). On the Arduino, loop() is called again as soon as it ends. In Processing, draw() is NOT called immediately after it ends. It is called often enough to maintain a constant (as best it can) frame rate. You are not telling Processing yo use anything other than the default frame rate, which is relatively low. You might want to do that. Not that that necessarily will make the application faster, if what you are doing in draw() takes longer, now, that the default frame rate can support.

Also, is there a way to progressively rotate the images each time they appear? Like say, image appears with 0 rotation, next with 12 degree rotation, next with 24 degree rotation, etc. The image sequence is actually a wheel so I want to spin it a little bit as it cycles through the animations.

Yes. There are translate() and rotate() functions that can be applied to the whole scene or just part of it.

Ah, thanks for the response. The thing is, I need to play the images in order, because its a short animation. In processing I have it set up so that the every tick of the encoder that gets sent to processing goes into FriendlyFire + i + .png, doesnt it depend on those numbers being in sequence?

Is there anyway, maybe in Arduino, where I can just make it so that every 10 ticks of the encoder or so results in the number 1 being written to the serial port? And then the next 10 ticks result in a 2, and so on up until 48, and then it snaps back to 0? Or am I thinking about this wrong?

How would I go about getting the whole scene to rotate with every number being sent to processing?

Thanks again.

I'd suggest that you determine if the encoder ticks are in the + order, not happening, or in the - order. Then, send a value only when the order changes, +1, 0, or -1.

Then, Processing simply keeps incrementing or decrementing, or holding still, the next image to play, at whatever rate.

Perhaps you could send +1, +2, or +3, for slow, medium, and fast, rather than absolute values. Obviously, -1, -2, -3 for the reverse order.