Controling servo with potentiometers via SD card

Hello, I have a problem with my program. I want to control my servo motors with potentiometers and then save that movements on SD card and read it afterwards. That works perfectly when I have only one servo but when I try to do this with two I cant open second file on SD card. Here is the code. Please help if you spot what’s the problem here.

#include <SPI.h>
#include <SD.h>
#include <Servo.h>

// CS pin for SD Card Module
const int chipSelect = 4;
// Analog pin for potentiometer
int analogPin = A0;
int analogPin1 = A3;
// Integer to hold potentiometer value
int val = 0;
int val1 = 0;

// Create a Servo object
String buffer;
String buffer1;

// Create a Servo object
Servo myservo;
Servo myservo1;

int pin_Button = 2;
int pin_Button_State = 0;
int pin_Button_State_Last = 0;
int recording = 0;

void setup()
{

Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

Serial.print(“Initializing SD card…”);

// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println(“Card failed, or not present”);
// don’t do anything more:
while (1);
}
Serial.println(“card initialized.”);
SD.remove(“servopos.txt”);
SD.remove(“servoposa.txt”);
// Attach servo on pin 9 to the servo object
myservo.attach(9);
myservo1.attach(6);

}

void loop()
{
pin_Button_State = digitalRead(pin_Button);
if (pin_Button_State != pin_Button_State_Last) {
if (pin_Button_State == HIGH) {
recording++;
Serial.println();
Serial.print(" Buttonpress: ");
Serial.println(recording);
}
else {
}
delay(50);
}

if ( recording == 1) {
Record();
}

else if (recording > 1){
Play();
}
}

void Record()
{
String dataString = “”;

val = map(analogRead(analogPin), 0, 1023, 0, 180);
dataString += String(val);

myservo.write(val);
delay(15);

String dataString1 = “”;

val1 = map(analogRead(analogPin1), 0, 1023, 0, 180);
dataString1 += String(val1);

myservo1.write(val1);
delay(15);

File dataFile = SD.open(“servopos.txt”, FILE_WRITE);

if (dataFile) {
dataFile.println(dataString);
Serial.println(dataString);
}

File dataFile1 = SD.open(“servoposa.txt”, FILE_WRITE);

if (dataFile1) {
dataFile1.println(dataString1);
}
else
Serial.println(“error”);

dataFile.close();
dataFile1.close();

}

void Play()
{

File dataFile = SD.open(“servopos.txt”);
File dataFile1 = SD.open(“servoposa.txt”);

// If the file is available, read it
if (dataFile) {
while (dataFile.available()) {
// Write one line to buffer
buffer = dataFile.readStringUntil(’\n’);
// Print to serial monitor
Serial.println(buffer);
// Convert string to integer and position servo
myservo.write(buffer.toInt());
delay(15);

}
}

// If the file is available, read it
if (dataFile1) {
while (dataFile1.available()) {
// Write one line to buffer
buffer1 = dataFile1.readStringUntil(’\n’);
// Print to serial monitor
// Convert string to integer and position servo
myservo1.write(buffer1.toInt());
delay(15);

}
}
dataFile.close();
dataFile1.close();

}

So to clear out I want to record both of my potentiometers every 15ms and save that position on SD card. So if I don’t change value on my pot the position of servo is saved as the same every 15ms until I move my pot again. And when I hit button for the second time I want my servo to read everything from those files at the same time so that motors move exactly as I was controling it in Record mode.
Thanks!

I cant open second file on SD card.

That is the problem. You can only have one file open at a time

How many servo movements will be saved for playback ?

UKHeliBob:
That is the problem. You can only have one file open at a time

How many servo movements will be saved for playback ?

Yeah I heard about that but i also read that in newer versions it is possible to open and write to more then one file at a time. I also tried to close the first one and then open the second but that also won't work.

My plan is to control 4 or 5 servos for robotic arm. I don't know exactly how many movements it will be, I plan to do some simple task with him like pick and place some object so I need positions of each servo to be saved and then read in exactly the same order. So first I am trying to do that with 2 motors. Is it possible to save data on SD card in some other format than string, something like array?

You could certainly save the data for all of your servos at the same time in the same file if you saved a servo identifier with each value so that you knew which servo the value related to when read back

Okay, the problem is that I don't know exactly how to do that. Is it possible for you to write a little example?
However thanks for your help.

Suppose that you had say 3 servos and when they were positioned as you required you pressed a button to save their positions then you could build a string like

s0/120:s1/090:s2/055

indicating that servo 0 is at 120, servo 1 at 090 and servo 2 at 055 and save that. Later it could be read back, parsed and the values sent to the servos.

The actual coding scheme for the data is up to you and could be made less error prone and more sophisticated, such as only saving data for servos that have moved, for instance

I tried with strings as you recommended and I made it work.
Thanks!

That's good news.

Would you care to post your code so that others may benefit from it ?

Sure, here it is!

#include <SPI.h>
#include <SD.h>
#include <Servo.h>

// CS pin for SD Card Module
const int chipSelect = 4;

// Analog pin for potentiometer
int analogPin = A0;
int analogPin2 = A2;
int analogPin3 = A3;
int analogPin4 = A4;
int analogPin5 = A5;

// Integer to hold potentiometer value
int val1 = 0;
int val2 = 0;
int val3 = 0;
int val4 = 0;
int val5 = 0;

// Create a buffer for storing data
String buffer;

// Create a Servo object
Servo myservo;
Servo myservo2;
Servo myservo3;
Servo myservo4;
Servo myservo5;

// Defining button pin and state
int pin_Button = 2;
int pin_Button_State = 0;
int pin_Button_State_Last = 0;
int recording = 0;

void setup()
{

Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

Serial.print(“Initializing SD card…”);

// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println(“Card failed, or not present”);
// don’t do anything more:
while (1);
}
Serial.println(“card initialized.”);
SD.remove(“servopos.txt”);

// Attach servo on pin 9 to the servo object
myservo.attach(9);
myservo2.attach(6);
}

void loop()
{

pin_Button_State = digitalRead(pin_Button);
if (pin_Button_State != pin_Button_State_Last) {
if (pin_Button_State == HIGH) {
recording++;
Serial.println();
Serial.print(" Buttonpress: ");
Serial.println(recording);
}
else {
}
delay(50);
}

if ( recording == 1) {
Record();
}

if (recording > 1){
Play();
}
}

void Record()
{
String dataString = “”;
String dataString2 = “”;
String dataString3 = “”;
String dataString4 = “”;
String dataString5 = “”;

val1 = map(analogRead(analogPin), 0, 1023, 0, 180);
dataString += String(val1);
myservo.write(val1);

val2 = map(analogRead(analogPin2), 0, 1023, 0, 180);
dataString2 += String(val2);
myservo2.write(val2);

val3 = map(analogRead(analogPin3), 0, 1023, 0, 180);
dataString3 += String(val3);
myservo3.write(val3);

val4 = map(analogRead(analogPin4), 0, 1023, 0, 180);
dataString4 += String(val4);
myservo4.write(val4);

val5 = map(analogRead(analogPin5), 0, 1023, 0, 180);
dataString5 += String(val5);
myservo5.write(val5);

File dataFile = SD.open(“servopos.txt”, FILE_WRITE);

if (dataFile) {

dataFile.print(“S01:”);
dataFile.println(dataString);

dataFile.print(“S02:”);
dataFile.println(dataString2);

dataFile.print(“S03:”);
dataFile.println(dataString3);

dataFile.print(“S04:”);
dataFile.println(dataString4);

dataFile.print(“S05:”);
dataFile.println(dataString5);

dataFile.close();
}
// if the file isn’t open, pop up an error:
else {
Serial.println(“error opening servopos.txt”);
}
}

void Play()
{

File dataFile = SD.open(“servopos.txt”);

// If the file is available, read it
if (dataFile) {
while (dataFile.available()) {
// Write one line to buffer
buffer = dataFile.readStringUntil(’\n’);

if(buffer.indexOf(“S01:”) >= 0){
Serial.print(“S01:”);
Serial.println(buffer.substring(4));
myservo.write(buffer.substring(4).toInt());
delay(30);
}

if(buffer.indexOf(“S02:”) >= 0){
Serial.print(“S02:”);
Serial.println(buffer.substring(4));
myservo2.write(buffer.substring(4).toInt());
delay(30);
}

if(buffer.indexOf(“S03:”) >= 0){
Serial.print(“S03:”);
Serial.println(buffer.substring(4));
myservo3.write(buffer.substring(4).toInt());
delay(30);
}

if(buffer.indexOf(“S04:”) >= 0){
Serial.print(“S04:”);
Serial.println(buffer.substring(4));
myservo4.write(buffer.substring(4).toInt());
delay(30);
}

if(buffer.indexOf(“S05:”) >= 0){
Serial.print(“S05:”);
Serial.println(buffer.substring(4));
myservo5.write(buffer.substring(4).toInt());
delay(30);
}
}

dataFile.close();
}

// if the file isn’t open, pop up an error:
else {
Serial.println(“error opening servopos.txt”);
}
}

So basically after the button is pushed first time ,the robot goes into Record mode which means that every servo is operated manually with potentiometers and data movements are stored on SD card with identifier for every motor for example S01:150 (motor one goes to position 150) and data is stored until we press the button for a second time. Then robot goes to Play mode which means that the data from SD file is read and every value is attached to specific motor. This is just first version of code and it has a lot of room for improvements but the general idea works!
I tried this with two motors and it works perfectly so I suppose that it will also work with five.

Some suggestions for possible improvements

// Defining button pin and state
int pin_Button = 2;
int pin_Button_State = 0;
int pin_Button_State_Last = 0;
int recording = 0;

None of these need to be 2 byte ints
All of them could be single bytes, Why waste memory ?
It would make more sense if the states were HIGH or LOW
It would make more sense if recording were a boolean with a value of true or false

 myservo.attach(9);
  myservo2.attach(6);

Once you have more than a couple of objects of the same type it is worth considering using an array of objects to avoid the need for repeated code

  if (pin_Button_State != pin_Button_State_Last)
  {
    if (pin_Button_State == HIGH)

Do you have a pulldown resistor on the input to keep it in a known state at all times ? If not then consider using INPUT_PULLUP in the pinMode() for the pin and changing the wiring and logic to match

    else
    {
    }

If you are not going to do anything then you don't need the else clause

  if ( recording == 1)
  {
    Record();
  }
  if (recording > 1)
  {
    Play();
  }

Making recording a boolean would make this easier to understand. For instance

  if (recording)  //recording is true
  {
    Record();
  }
  else  //recording must be false
  {
    Play();
  }
  String dataString = "";
  String dataString2 = "";
  String dataString3 = "";
  String dataString4 = "";
  String dataString5 = "";

Looks like another candidate for an array and using C stryle strings (lowercase s) instead of Strings in the limited memory available and the SD library is a bit of a memory hog

// Integer to hold potentiometer value
int val1 = 0;
int val2 = 0;
int val3 = 0;
int val4 = 0;
int val5 = 0;

Another array

Problem solved ??