record data from potentiometer & playback to servo

Hello everyone. First of all, I'm new at this and this is an amazing technology and supporting community! :slight_smile:
For the last month I've been reading stuff and working on my 1st project and the amount of info given here is great.

Now for my question (I've looked around but wasn't able to find answers):
Using the Knob sketch I'm building a Follow Focus for my camera.
what I'm trying to figure out is how be able to add a "Record" function to the code.
What I mean is to have the ability to to push a button telling to Arduino to record my potentiometer data
(as I move it, the servo of course moves and changes the focus on my camera),
than "stop" the recording and play it back causing the servo to repeat (once)
the movement and timing of my "focus pulling".

I would appreciate any advice, or if someone could point me to a relevant link.

Look at arrays. As a precursor, write a sketch with an array initialized with some potentiometer values. Iterate through them to make the servo move to different positions. Don't forget to allow some time between each or the servo will appear to immediately go to the last value.

Then you need to adapt that code to take potentiometer values and store them in the array when you set a switch to tell it to. Be careful - it will be easy to overflow the bounds of the Arduino's memory if you don't check your array bounds.

Does the playback have to be at the same speed that you did it? If so, it's going to be a little more complicated.

Hey wildbill, thanks for the reply.
Indeed I want the playback to be at the same speed as the real event...
This seems too complicated for my stage at this :blush:

As for the first part of your answer, is there a sample of a sketch that utilizes the technique you mentioned?
I'm a real noob at this...

Here's the knob sketch so adjusted:

#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
 
int potpin = 0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin 
int potvalues[10]={100,900,200,800,1000,50,900,500,0,1023};

void setup() 
{ 
myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
} 
 
void loop() 
{ 
//  val = analogRead(potpin);                 // reads the value of the potentiometer (value between 0 and 1023) - left in so you can see what replaced it 
for(int i=0;i<10;i++)
  {
  val = map(potvalues[i], 0, 1023, 0, 179);  // scale it to use it with the servo (value between 0 and 180) 
  myservo.write(val);                        // sets the servo position according to the scaled value 
  delay(200);                                // wait for the servo to get there
  }
delay(3000);                                 // wait before starting the sequence again 
}

Compiled, not tested. It illustrates the principle, but it isn't very good code. The use of all those manifest constants, particularly 10, is a sin. The use of delay too, is handy here, but not recommended generally.

wildbill thanks a lot!
Will read, understand, try and reply!
:wink:

My project is slowly progressing (actually I should say I'M slowly progressing...) and my 3 questions are:

  1. Is it possible to store the pot data into an array while at the same time send it over to the servo? This way I can both see what I'm doing and "record" the info for later retrieval.
  2. In this project I'm expanding on the Knob sketch, adding the array in order to record. I want to be able to begin , stop and playback this recording using buttons. This means putting some "If" structures into the main loop of the sketch. Will this make my reading from the pot and writing to the servo slower (because the code will check to see if the button is pressed)? Should I use another structure? Is Interrupt better suited for this?
  3. By other structure I mean maybe 2 loops that can be switched between by a button. Is that even possible?

Thanks

update:

  1. Yes I can.
    2&3 - would still appreciate a pointer or two.

:slight_smile:

  1. Not appreciably. The Arduino is lightning fast compared to any actions you're taking, so it'll take finite time to execute the extra steps, but you won't notice. Interrupts? No.

  2. Not sure what you mean. You can have multiple different functions called from loop & vary which are called based on button presses. You can't have multiple functions called loop though.

Hey. I guess phase 1 is done. I'm able to control, record, play in reverse and play in original order.
Now it's controlled through serial monitor and my next phase is to control it with 4 switches.

I'm attaching the code and would appreciate remarks. Remember - I'm a complete noob, so please don't be too hard on me..
Edit - code attached as should be in my next post...

Can you modify your post to use [code] tags, instead of [quote]. It looks like you aren't using array indexing to store the servo position, but that could well be because the [i] is being converted to an italic tag.

whoops, let me try again...
:blush:

// Controlling a servo position using a potentiometer (variable resistor) 
// with the option of recording the movement, playing it in reverse and in original order.
// Adi Soffer 19.3.12

#include <Servo.h> 
 
   Servo myservo;               // create servo object to control a servo 
   char buffer [5];              //variable to hold keystrokes
   int potpin = 0;                // analog pin used to connect the potentiometer
   int val;                          // variable to read the value from the analog pin 
   int servoPos[300];           //create array 300 values for servo position
   int incomingByte;            //declare variable to hold incoming letter

 
  void setup() 
{
     Serial.begin(9600);
     Serial.flush();
     myservo.attach(3);           // attaches the servo on pin 3 to the servo object 
 }


  void loop ()
{
   if (Serial.available( ) > 0) 
 {
       incomingByte = Serial.read ( );
       if (incomingByte == 'F') 
  {
          Serial.println ("Free mode");
          while (incomingByte == 'F') 
    {
          val = analogRead (potpin);
          val = map(val, 0, 1023, 0, 179);
          myservo.write (val);
          delay (10);
          if (Serial.available ( ) > 0)
      {
            incomingByte = Serial.read ( );
            if (incomingByte == 'R') 
         {
              Serial.println ("Record inside");                  // if so - prints record inside for checkup
              delay(15);
              for (int i=0;i<299;i++)                              //for loop to store 300 values of pot  
           {
              val = analogRead(potpin);                         // reads the value of the potentiometer (value between 0 and 1023) 
              val = map(val, 0, 1023, 0, 179);                // scale it to use it with the servo (value between 0 and 180) 
              myservo.write(val);                                 // sets the servo position according to the scaled value 
              servoPos [i]=val;                                     // stores val in array "servoPos
              delay(15);                                              // waits for the servo to get there
              Serial.println(val);                                   // print values for checking
           }    
         } 
           else if (incomingByte == 'H') 
       {
            Serial.println ("Home inside");
            //delay(15);
            for (int i=299;i>0;i--) 
         {
              myservo.write (servoPos[i]);           //reads values from array in reverse to servo
              delay(15);
              Serial.println (servoPos[i]);
         }
        }   
           else if (incomingByte = 'P') 
        {
             Serial.println ("Playback inside");       // if so prints for checkup
             //delay(15);
             for (int i=0;i<299;i++) 
          {
               myservo.write (servoPos[i]);          //reads values from array in original order to servo
               delay (15);
               Serial.println (servoPos[i]);
           } 
         }    
       }  
     }
   }  
          else if (incomingByte == 'R')                // checks if input was capital R
        {                       
            Serial.println ("Record");                   // if so - prints record
            delay(15);
            for (int i=0;i<299;i++)                      //for loop to store 300 values of pot  
         {
              val = analogRead(potpin);               // reads the value of the potentiometer (value between 0 and 1023) 
              val = map(val, 0, 1023, 0, 179);      // scale it to use it with the servo (value between 0 and 180) 
              myservo.write(val);                       // sets the servo position according to the scaled value 
              servoPos [i]=val;                           // stores val in array "servoPos
              delay(15);                                    // waits for the servo to get there
              Serial.println(val);                         // print values for checking
         }  
        }
 
          else if (incomingByte == 'H') 
       {
            Serial.println ("Home");
            //delay(15);
            for (int i=299;i>0;i--) 
         {
              myservo.write (servoPos[i]);           //reads values from array in reverse to servo
              delay(15);
              Serial.println (servoPos[i]);
         }
        }
       
          else if (incomingByte = 'P') 
        {
             Serial.println ("Playback");
             //delay(15);
             for (int i=0;i<299;i++) 
          {
               myservo.write (servoPos[i]);          //reads values from array in original order to servo
               delay (15);
               Serial.println (servoPos[i]);
           } 
         }
 }
}

I have a similar problem. I'm trying to get the data from 3-D animation software into the Sketch to move the servos. I have the output movement working, but the process of loading it is tedious. Maybe I should try pots? I want the movement to look natural like a human body moving.

sbright33, that sounds extremely interesting, and quite close to my field of interest :slight_smile:
Are you using arrays to store the values from the software?

And here again is the code, more organised, using functions...

// Controlling a servo position using a potentiometer (variable resistor) 
// with the option of recording the movement, playing it in reverse and in original order.
// Adi Soffer 19.3.12

#include <Servo.h> 
 
   Servo myservo;               // create servo object to control a servo 
   char buffer [5];               //variable to hold keystrokes
   int potpin = 0;                // analog pin used to connect the potentiometer
   int val;                             // variable to read the value from the analog pin 
   int servoPos[300];          //create array 300 values for servo position
   int incomingByte;        //declare variable to hold incoming letter

 
  void setup() 
{
     Serial.begin(9600);
     Serial.flush();
     myservo.attach(3);      // attaches the servo on pin 3 to the servo object 
 }


  void loop ()
{
   if (Serial.available( ) > 0) 
 {
       incomingByte = Serial.read ( );
       if (incomingByte == 'F') 
  {
          Serial.println ("Free mode");
          while (incomingByte == 'F') 
    {
          val = analogRead (potpin);
          val = map(val, 0, 1023, 0, 179);
          myservo.write (val);
          delay (10);
          if (Serial.available ( ) > 0)
      {
            incomingByte = Serial.read ( );
            if (incomingByte == 'R') 
         {
             recordFunction ( );    
         } 
           else if (incomingByte == 'H') 
       {
           reverseFunction ( );
        }   
           else if (incomingByte = 'P') 
        {
             playBackFunction ( ); 
         }    
       }  
     }
   }  
          else if (incomingByte == 'R')                   // checks if input was capital R
        {                       
           recordFunction ( );
        }
           else if (incomingByte == 'H') 
       {
           reverseFunction ( );
        }
                 else if (incomingByte = 'P') 
        {
           playBackFunction ( );
           } 
        }
      }

void playBackFunction ( ) 
       {
          Serial.println ("Playback Function");
            for (int i=0;i<299;i++) 
          {
             myservo.write (servoPos[i]);          //reads values from array in original order to servo
             delay (15);
             Serial.println (servoPos[i]);
          }   
       }

 void reverseFunction ( ) 
      {
          Serial.println ("Home function");
            for (int i=299;i>0;i--) 
          {
             myservo.write (servoPos[i]);                //reads values from array in reverse to servo
             delay(15);
             Serial.println (servoPos[i]);
          }
       }
     
void recordFunction ( ) 
{
   Serial.println ("Record function");                    // if so - prints record
            delay(15);
            for (int i=0;i<299;i++)                            //for loop to store 300 values of pot  
        {
              val = analogRead(potpin);                  // reads the value of the potentiometer (value between 0 and 1023) 
              val = map(val, 0, 1023, 0, 179);                  // scale it to use it with the servo (value between 0 and 180) 
              myservo.write(val);                              // sets the servo position according to the scaled value 
              servoPos [i]=val;                                  // stores val in array "servoPos
              delay(15);                                                  // waits for the servo to get there
              Serial.println(val);                          // print values for checking
         }  
}

@Soffer- Yes, but we have not determined which software to use for motion easing. Is there one you like best? Can it export these values to a text file?

OK - things are looking good and I've even written code for using my LEDs as a countdown till record and so forth... :smiley:
Now here's a question I can't seem to find an answer to, probably since it's too simple, and I would very much appreciate an insight...

I'm rewriting the code so that instead of key strokes, switches will operate the different functions, and I'm constantly reading about the Debounce thing - BUT - if I simply with to use my switches not as toggles, just when I press one a function goes on, do I still need this debouncing trick? just to make it clear I'm attaching my updated code, still with keystrokes. Except for the "free mode" all other function are self terminating and for them I need to use the switch simply as a trigger.
Thank you.

// Controlling a servo position using a potentiometer (variable resistor) 
// with the option of recording the movement, playing it in reverse and in original order.
// Adi Soffer 19.3.12

#include <Servo.h> 
 
   Servo myservo;                                         // create servo object to control a servo 
   char buffer [5];                                         //variable to hold keystrokes
   int potpin = 0;                                          // analog pin used to connect the potentiometer
   int val;                                                       // variable to read the value from the analog pin 
   const int valNumber = 500;                   //variable to contain number of array members
   int incomingByte;                                  //declare variable to hold incoming letter
   int servoPos[valNumber];                    //create array of values for servo position
   const int waitForServo = 15;               //delay time to let servo get to position 
   int recordModeLed = 3;                              // defining pins for ui leds
   int homeModeLed = 4;
   int playModeLed = 5;
   int freeModeLed = 6;
   int freeSwitch = 7;                                 //defining pins for switches
   int recSwitch = 8;
   int homeSwitch = 9;
   int playSwitch = 10;
   

 
  void setup() 
{
     Serial.begin(9600);
     Serial.flush();
     myservo.attach(2);                                                   // attaches the servo on pin 2 to the servo object 
     pinMode (freeModeLed, OUTPUT);                         //defining LED pins as output
     pinMode (recordModeLed, OUTPUT);
     pinMode (homeModeLed, OUTPUT);
     pinMode (playModeLed, OUTPUT);
     pinMode (freeSwitch, INPUT);                              //defining switch pins as input
     pinMode (recSwitch, INPUT);
     pinMode (homeSwitch, INPUT);
     pinMode (playSwitch, INPUT);
     
 }


  void loop ()
{
   
  digitalWrite (freeModeLed, LOW);
  digitalWrite (recordModeLed, LOW);
  digitalWrite (homeModeLed, LOW);
  digitalWrite (playModeLed, LOW);
  
  if (Serial.available( ) > 0) 
 {
       incomingByte = Serial.read ( );
       if (incomingByte == 'f') 
  {
          Serial.println ("Free mode");
          while (incomingByte == 'f') 
    {
          digitalWrite (freeModeLed, HIGH);
          val = analogRead (potpin);
          val = map(val, 0, 1023, 0, 179);
          myservo.write (val);
          delay (waitForServo);
          if (Serial.available ( ) > 0)
      {
            incomingByte = Serial.read ( );
            if (incomingByte == 'r') 
         {
             recordFunction ( );    
         } 
           else if (incomingByte == 'h') 
       {
           reverseFunction ( );
        }   
           else if (incomingByte = 'p') 
        {
             playBackFunction ( ); 
         }    
       }  
     }
   }  
          else if (incomingByte == 'r')                   // checks if input was r
        {                       
           recordFunction ( );
        }
           else if (incomingByte == 'h') 
       {
           reverseFunction ( );
        }
                 else if (incomingByte = 'p') 
        {
           playBackFunction ( );
           } 
        }
      }

void playBackFunction ( ) 
       {
         digitalWrite (freeModeLed, LOW);
          digitalWrite (playModeLed, HIGH);
          Serial.println ("Playback Function");
            for (int i=0;i<(valNumber - 1);i++) 
          {
             myservo.write (servoPos[i]);                    //reads values from array in original order to servo
             delay (waitForServo);
             Serial.println (servoPos[i]);
          }
           digitalWrite (playModeLed, LOW);   
       }

 void reverseFunction ( ) 
      {
            digitalWrite (freeModeLed, LOW);
            digitalWrite (homeModeLed, HIGH);
            Serial.println ("Home function");
            for (int i=(valNumber - 1);i>0;i--) 
          {
             myservo.write (servoPos[i]);                   //reads values from array in reverse to servo
             delay(waitForServo);
             Serial.println (servoPos[i]);
          }
          digitalWrite (homeModeLed, LOW);
       }
     
void recordFunction ( ) 
{
           for (int c=6;c>3;c --)                                     // three sec countdown to recording
           {
             digitalWrite (recordModeLed, HIGH);
             digitalWrite (c, HIGH);
             delay (700);
             digitalWrite (recordModeLed, LOW);
             digitalWrite (c, LOW);
             delay(300);
           }
           digitalWrite (recordModeLed, HIGH);
           Serial.println ("Record function");            // if so - prints record
           for (int i=0;i<(valNumber - 1) ;i++)                //for loop to store declared values of pot  
        {
              val = analogRead(potpin);                             // reads the value of the potentiometer (value between 0 and 1023) 
              val = map(val, 0, 1023, 0, 179);                             // scale it to use it with the servo (value between 0 and 180) 
              myservo.write(val);                                         // sets the servo position according to the scaled value 
              servoPos [i]=val;                                              // stores val in array "servoPos
              delay(waitForServo);                                      // waits for the servo to get there
              Serial.println(val);                                       // print values for checking
         }  
         digitalWrite (recordModeLed, LOW);
}

@ sbright33 - I'm afraid you misunderstood me... I'm simply a director building my own camera rigs for fun, not a motion control specialist... :wink:
What I can say is that from what I'm reading people are coding the arduino to smooth the arrays of data - thus smoothing the motion. HOp that helps :smiley:

My goal is to make canned predefined movements where the motion is already smoothed or eased on the PC before it is loaded unto Arduino. There are many PC apps that do this. I have written a Sketch to make the steppers/servos move. It's the in between part that I'm struggling with. How to export the data into an array for the Sketch to use. So far Excel is my friend. Looking for an improvement...

Aha! Now I got your meaning. you're looking for an interfacing "something" to grab you data and spit it into the arduino... interesting.

Each PC app is different. First they should export. Then I can use Processing to translate that text file to array syntax. Then cut and paste into IDE, compile, run.

Alternatively I could write a Sketch to take data from serial port and put it into array. Still need Processing to translate exported file to Serial data. I haven't found an app that exports to serial port yet. Then I could skip the middle man?