How to sequence or switch case automatically?

Hi,
I made a lot of cases to trigger them with the keyboard. Now, I wish I could sequence the cases in a special order and manage their duration.

For example with the Arduino IDE, I made case ‘0’ and case ‘4’’

In void loop, i manage the sequence and the duration like this :

void loop() { 

static uint8_t ETAT = 0; // begin with the case '0'
static float reftempsGENERAL = millis(); // time in the loop is in milliseconds
switch (ETAT) {

case 0:

yoyo45to75 (45, 16);  // do yoyo45to75--> speed 45 to 75   for 16s 
yoyo75to60 (75, 16*2); // do yoyo75to60 --> speed 75 to 60 for 32s
yoyo60to45 (45, 16*2); // 

if(millis() - reftempsGENERAL > 16000*5) { // if time is upper than 16000 millisecond*5 --> switch on CASE 4
      reftempsGENERAL = millis();
     ETAT=4;

     /*  TEST IF MOTOR STOP AT THE GOOD POSITION
 
       for(uint8_t i = 0; i < 5; i++) { 
       setMoteur(i, 0); 
      } 
     while(1);
*/ 
      }

      break;

case 4:

recallage2to60 (60,8); // MOVE MOTOR TO THE SECOND ONE

if(millis() - reftempsGENERAL > 8000) { // IF time > 8 sec go back to case 0
      reftempsGENERAL = millis();
       ETAT=0;
      
 /*
       for(uint8_t i = 0; i < 5; i++) { 
       setMoteur(i, 0); 
      } 
     while(1);

*/      
      }
break;
 }

And later, would it be possible to directly select my cases with the keyboard and have a program record the keys and the duration between them. So that this program will sequence the cases as it recorded it?
This second question is less important than the first for now but maybe it’s simpler to program.
So I’ll every option you propose to me!!
Thank you for your help and your kind lights.

You can see below the way I coded my case.

void keyPressed() {//**** faire position de base à l'arret avec ecrart equidistant qui s'incrementent entre G et le chiffre
 
 // SET POSITION
 if (keyCode == CONTROL) { println(" GO to NEXT POSITION "); // Faire control -
   for (int i = 0; i < net.networkSize; i++) {
   // net.phase[i] += net.phase[i]+2*PI/net.networkSize;// (incremente ecrat des dernieres phases --> si nul elles n'evoluent pas
    net.phase[i] = net.phase[i]+2*PI/net.networkSize; // (faire un nouvel ecart à corrélé selon l'ecart precedent )
   //    net.phase[i] += 2*i*PI/net.networkSize; // positionne avec un ecart qui s'increment et se supperposent les uns sur les autres
    print ("phase "); print (i);  print (" ");
    print (net.phase[i]); print (" ");
    print ("frequency "); print (i); print (" ");
    println (net.naturalFrequency[i]);  
     }
}
// SET POSITION
 if (keyCode == ALT) { println(" SHIFT POSITION "); // Faire ALT -
   for (int i = 0; i < net.networkSize; i++) {
    net.phase[i] += net.phase[i]+2*PI/net.networkSize;// (incremente ecrat des dernieres phases --> si nul elles n'evoluent pas
  //  net.phase[i] = net.phase[i]+2*PI/net.networkSize; // (faire un nouvel ecart à corrélé selon l'ecart precedent )
   //    net.phase[i] += 2*i*PI/net.networkSize; // positionne avec un ecart qui s'increment et se supperposent les uns sur les autres
    print ("phase "); print (i);  print (" ");
    print (net.phase[i]); print (" ");
    print ("frequency "); print (i); print (" ");
    println (net.naturalFrequency[i]);  
     }
}

 
 
 //***********************  ADDING "LIVE" in the hole movement
   if (key == 'Q') {println ("Noise in Phases");
    background (0);
       for (int i = 0; i < net.networkSize; i++) {
         //  net.phase[i] = TWO_PI *   noise(i*0.1); 
            net.phase[i] =  net.phase[i]  +  noise(i*0.1); // Add noise in former 
           
    print ("phase "); print (i);  print (" ");
    print (net.phase[i]); print (" ");
    print ("frequency "); print (i); print (" ");
    println (net.naturalFrequency[i]);
     }
  } 
  if (key == 'q') {println ("Noise in Frequencies");
  background (0); 
       for (int i = 0; i < net.networkSize; i++) {
           net.naturalFrequency[i] = TWO_PI *   noise(i*0.1); //p0.01 to begin slower
    print ("phase "); print (i);  print (" ");
    print (net.phase[i]); print (" ");
    print ("frequency "); print (i); print (" ");
    println (net.naturalFrequency[i]);    
     }
} 
1 Like

maybe there is a library for this

read this : Short film created solely on Processing

and Album cover for Floating Spectrum

1 Like

Thanks Chrisir.

But I have red your two links and the guy has sequenced his program with Blender not with Processing (if I have well understood).

maybe there is a library for this

I hope so.

I have seen this " to deal with data" but it seem very complicated.
https://processing.org/tutorials/data/.

1 Like

Did you check the library website?

Here an example of a program that records keys and timing:

// press number keys between 0 and 9, ESC to end
PrintWriter output;

void setup() {
  size(200, 200);
  output = createWriter("data.txt");
  output.println("0:0");
  textSize(100);
}

void draw() {
  background(0);
  text(key, 20, height - 20);
}

void keyPressed() {
  if (key == ESC) {
    output.flush();
    output.close();
    exit();
  } else {
    output.println(frameCount + ":" + key);
  }
}

And a program that plays the recording back:

String[] lines;
int index = 0, nextFrame = 0, theKey = 0; 

void setup() {
  size(200, 200);
  lines = loadStrings("data.txt");
  readOneLine();
  textSize(100);
}
void draw() {
  background(0);
  text(theKey, 20, height - 20);
  if(frameCount == nextFrame) {
    readOneLine();
  }
}
void readOneLine() {
    theKey =  int(split(lines[index], ':')[1]);
    if(++index == lines.length - 1) {
      exit();
    }
    nextFrame = int(split(lines[index], ':')[0]);
}

Possible improvements:

  • record times based on millis() instead of frameCount. But that requires more logic, you can’t compare times using == as a specific time in milliseconds may happen between two animation frames.
  • Allow recording any keys. Then you can’t store the variables as int.
  • Maybe don’t crash with invalid data?
2 Likes

Here is an example without recording.

It reads a csv file and uses the millis from it


/*
expects a csv file named "planer1.csv" like (without spaces before each line). The millis is the absolute time since the sketch has started; this is when the line starts
 millis,command,param1,param2
 0,11,45,16
 1222,20,75,32
 2444,30,45,32
 4566,40,12,
 7000,50,12,
 */

// data for show
Table planer; 

// example 
EllipseMy[] ellipseMy = new EllipseMy[6];   

// ------------------------------------------------------------------------------

void setup() {
  size(900, 400); 

  // load
  planer = loadTable("planer1.csv", "header");

  //prepare example 
  for (int i=0; i < ellipseMy.length; i++) {
    ellipseMy[i]=new EllipseMy(66+i*100);
  }//for
}//func 

void draw() {
  background(0);

  // show row number 
  int rowNumber = findRowNumberToExecute();  
  text(rowNumber, 100, 100);

  //run commands 
  if (rowNumber>-1) {
    doCommand(rowNumber);
  }//if

  //example 
  fill (255, 1, 1); // RED 
  for (int i=0; i < ellipseMy.length; i++) {
    ellipseMy[i].display();
  }//for
}//func 

// ------------------------------------------------------------------------------

void doCommand(int rowNumber) {
  TableRow row = planer.getRow(rowNumber);
  int commandFromTable = int(row.getString("command"));
  int param1FromTable = int(row.getString("param1"));
  int param2FromTable = int(row.getString("param2"));

  text(str(commandFromTable) + " -> with " 
    + param1FromTable
    + " and "
    + param2FromTable, 
    width/2, 111); 

  switch(commandFromTable) {
  case 11:
    ellipseMy[0].y+=-1;
    break;
  case 20:
    ellipseMy[1].y+=-1;
    break;
  case 30:
    ellipseMy[2].y+=-1;
    break;
  case 40:
    ellipseMy[3].y+=-1;
    break;
  case 50:
    ellipseMy[4].y+=-1;
    break;
  default:
    // ignore 
    break;
  }//switch
}//func 

int findRowNumberToExecute() {
  boolean prevRow=false;
  int result = -1; 

  for (int i = 0; i < planer.getRowCount(); i++) {

    TableRow row = planer.getRow(i);
    int millisFromTable = int(row.getString("millis"));

    if (millisFromTable>millis()) {
      // found 
      prevRow=true;
      result=i-1; 
      break;
    }//if
  }// for

  // found 
  if (prevRow) {
    return result;
  }//if

  // no found 
  return -1;
}//func 

// ============================================================================

class EllipseMy {
  int x, y=height-66; 

  EllipseMy(int x_) {
    x=x_;
  }//constr

  void display() {
    ellipse(x, y, 17, 17);
  }//method
  //
}//class
//
1 Like

It relies on the order of millis. Each Line has a milliseconds value that tells the line when to start (or the previous line to end).

There is only one active line at any given moment.

Improvement could be to have a start and a stop time (in millis) and use this. Then you could have multiple tasks at once.

Each line has a command number that can be evaluated and executed in function doCommand(). It has also 2 parameters you could pass to your function yoyo75to60().

There are things to discuss though. For example when you load a lot of images in setup() the assumption that the millis() are 0 at start of draw() is wrong. Therefore we could set a timer at the end of setup() and define it as 0.

Also when we have processes we don’t know how long they take (ball flies to target) the program could wait until the event happens. Only then the next task would be started.
But then the following millis values would have to be relative to this event and not absolute (from the start of the sketch) anymore.

Chrisir

Hi,

I have tested yours programs. But the second one have a bug here
theKey = int(split(lines[index], ‘:’)[1]);
Processing says:
ArrayIndexOutOfBoundsException: 0

May be I have to mix your 2 program to record a sequence ( with the good time between case) but I m not be able to do that.

Actually I would like to trig event one after one. I have several motors turning at different speed with only one case.
I would like the simulation of speeds to be close to reality. Maybe recorded time with FrameCount will be the same as millis() :thinking:

Here you can see a simulation (in French sorry).

When motors change speed or way of rotation that’s mean I have changed cases.

So now I have to test your programs.
Could you mix them for me?

Thank you very much

1 Like

You have to copy the result of the first sketch into the file data.txt that gets loaded into the second sketch. /// copy the file

I wouldn’t merge the 2 sketches because one is for recording the other for playback

2 Likes

Great!

It works perfectly.
:smiling_face_with_three_hearts: :innocent:

1 Like

Yes thanks for mentioning that.

You either copy the file produced by program 1 into program 2, or you use an absolute path in both cases like /tmp/data.txt or C:/some/folder/data.txt. I’m not on Windows so not sure how you make absolute paths in Processing on Windows.

I think you can also drag and drop the data.txt file into the second sketch.

2 Likes

You are absolutely right.
But, for the moment, I will try to motorize the above simulation hoping that the motors react in “real time”. I will get back to you after a few tests. Thank you.
Sincerly

2 Likes

Hello !
Yours programs to record and play the key pressed work perfectly.
But I would like to be able to use letter and the others keys like , ; / *.
Is it possible to you?
Please.

Sure. Only small changes required :slight_smile:

In the saving program (the first), you only need to change the line that saves the pressed key:

void keyPressed() {
  if (key == ESC) {
    output.flush();
    output.close();
    exit();
  } else {
    if(key != CODED) { // this `if` to ignore keys like shift, ctrl, alt
      output.println(frameCount + ":" + (int)key);
    }
  }
}

This will make it save the ascii code that represents the pressed key.

In the second program you need to change the variable called theKey so it is char instead of int. At the top:

int index = 0, nextFrame = 0; // these stay the same
char theKey; // this becomes a char

and when setting the value we cast to char:

    theKey = (char)int(split(lines[index], ':')[1]);

With these changes it will no longer save the pressed character, but a number that represents that key. When loading, it will convert that number to a character.

2 Likes

Waaa! Thank you so much. As the solution looks simple for you. :star_struck:

And to finish ( I have forgotten what I need), could you adapt yours programs in the manner it could record and play CONTRL, ALT and the ARROW?
Please.

1 Like

Ok, then you could just save both key and keyCode, and you do whatever you want with them afterwards.

Saver program
PrintWriter output;

void setup() {
  size(200, 200);
  output = createWriter("/tmp/data.txt");
  output.println("0:0:0");
  textSize(100);
}

void draw() {
  background(0);
  text(key, 20, height - 20);
}

void keyPressed() {
  if (key == ESC) {
    output.flush();
    output.close();
    exit();
  } else {
    output.println(frameCount + ":" + (int)key + ":" + (int)keyCode);
  }
}
Playback program
String[] lines;
int index = 0, nextFrame = 0; // these stay the same
char theKey; 
int theKeyCode;

void setup() {
  size(200, 200);
  lines = loadStrings("/tmp/data.txt");
  readOneLine();
  textSize(20);
}
void draw() {
  background(0);
  text(theKey, 20, height - 20);
  text(theKeyCode, 20, height - 40);
  if (frameCount == nextFrame) {
    readOneLine();
  }
}
void readOneLine() {
  String[] current = split(lines[index], ':');
  theKey = (char)int(current[1]);
  theKeyCode = int(current[2]);
  if (++index == lines.length - 1) {
    exit();
  }
  nextFrame = int(split(lines[index], ':')[0]);
}

It’s your task then to do something with theKey and theKeyCode, same way you would do with key and keyCode (see https://processing.org/reference/keyCode.html).

Hello,

I have just tried to use the last saver program but it doesn’t seem to work. There is no data recorded in the sketch folder, whereas I worked very well in the program recording key and letter.

I put it below

PrintWriter output;

void setup() {
  size(200, 200);
  output = createWriter("data.txt");
  output.println("0:0");
  textSize(100);
}

void draw() {
  background(0);
  text(key, 20, height - 20);
}

void keyPressed() {
  if (key == ESC) {
    output.flush();
    output.close();
    exit();
  } else {
    if(key != CODED) { // this `if` to ignore keys like shift, ctrl, alt
      output.println(frameCount + ":" + (int)key);
    }
  }
}

Thanks Mister.

Hi! Please change the path to suit your needs. In my latest example I was using /tmp/data.txt because that’s what works best for me for a temporary file. That’s a path in the root of my drive, not in the sketch folder.

1 Like

Thanks again.
I can see all ascii code now .:kissing_heart:
But I can’t manage to play event (here it’s just printing something) from the key and/or from the key code recorded, in order the playback program play them as a real keys pressed() .
I have tried to split my void keyPressed() in two part but it doesn’t work because this function is waiting a KeyEvent.
It’s the last part of my program, i really need you.
Special thank :cold_face:

I show you what I have tried in the playback program

String[] lines;
int index = 0, nextFrame = 0; // these stay the same
char theKey; 
int theKeyCode;

void setup() {
  size(200, 200);
  lines = loadStrings("data.txt");
  readOneLine();
  textSize(20);
}
void draw() {
  background(0);
  text(theKey, 20, height - 20);
  text(theKeyCode, 20, height - 40);
  if (frameCount == nextFrame) {
    readOneLine();
    
  }
  
   keyPressed (theKeyCode );
//   keyPressed (theKey );
}

void readOneLine() {
  String[] current = split(lines[index], ':');
  theKey = (char)int(current[1]);
  theKeyCode = int(current[2]);
  if (++index == lines.length - 1) {
    exit();
  }
  nextFrame = int(split(lines[index], ':')[0]);
}

void keyPressed (theKeyCode )  {
  
  if (keyCode == DOWN) {
    println("DOWN= DECREASE SPEED "); // 
  } 
  
  if (keyCode == UP) { 
    println("UP= INCREASZe SPEED "); // 
  }
  
 }

/*
void keyPressed (theKey )  {
  
   if (key =='é') {
      println(" ééééééé ");    
        
 }
  
}
*/

1 Like

Hi! Sorry for replying so slow, I’ve been offline a bit…

Issues I see in the last program:

  1. there is void keyPressed(theKeyCode) but then you check if(keyCode == DOWN) instead of using if(theKeyCode == DOWN). I guess it’s also missing int before theKeyCode right? Otherwise it would not compile…
  2. As it stands, keyPressed would be called for every animation frame. Maybe you should move keyPressed(theKeyCode) inside the previous if statement, right after readOneLine() so it is only called at the right time when the key was pressed?