Pages: [1]   Go Down
Author Topic: Use data on SD card for controlling a servomotor  (Read 2199 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I would like to retrieve data previously recorded on an SD card using a microSD Shield (I use the SDfat library ).
These data are in fact numbers between 0 and 1024 obtained from a sensor. I want them back and then controlling a servomotor, yet I can't do it.
I think I'm stuck because the data that I get on the SD card are automatically of type char, and the servomotor request type int.
Do you have an idea to help me ? thank you !
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 651
Posts: 50841
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Do you have an idea to help me ?
Post the code that you have that is reading the data from the SD card.

Look at the documentation for atoi().
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

here is my program

the values I had in my SD card scrolls well in the serial monitor,  but I don't know hw to use them to move my servomotor.

Code:
#include <SdFat.h>
#include <SdFatUtil.h>
#include <ctype.h>

#include <Servo.h>
 
Servo myservo;

Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

char name[] = "Test.txt";   
char contents[256];           
char in_char=0;
int index=0; 
               
void setup(void)

    Serial.begin(115200);
    myservo.attach(9);       
    pinMode(10, OUTPUT);     
    card.init();               
    volume.init(card);       
    root.openRoot(volume);     
}


void loop(void){   
   
    file.open(root, name, O_READ);   
    in_char=file.read();             
   
    while(in_char >=0)
       {           
        Serial.print(in_char);   
        in_char=file.read();   
       }
    file.close();   
    delay(1000);     
}

Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 651
Posts: 50841
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
but I don't know hw to use them to move my servomotor.
Well, just sending them to the serial monitor is useless, as you've observed.

You need to make use of the data. Exactly how to do that depends on what the data on the card looks like.

If there is a continuous stream of characters that represent digits, you have a problem. If there are non-digit characters in between, like carriage return, line feed, space, etc. then those form delimiters.

You can store the characters in an array, and use atoi to convert the array to an int, then reset the array. Or, you can construct the int as you read each digit from the file.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thank you for your help,
but i don't manage with the delimiters.
In fact I used the fnction strtok_r, but it didn't work.
Are there any other fnction to make segmentation (delimiters are line feed in my case) ?
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 651
Posts: 50841
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
In fact I used the fnction strtok_r, but it didn't work.
You want to be using strtok(), not the thread-safe version.

"It didn't work" means that you wrote your code wrong. Since you didn't share that code, we can only guess at the problem. I'm going to guess 57.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
#include <stdio.h>
#include <stdlib.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <ctype.h>

 
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

char name[] = "Test.txt";     
char contents[256];           
char in_char=0;
char* val = "0";
int index=0;
int a;

void setup(void)

    Serial.begin(115200);
    pinMode(10, OUTPUT);       
    card.init();             
    volume.init(card);         
    root.openRoot(volume);       
}


void loop(void){   
   
    file.open(root, name, O_READ);   
     val[0] = file.read();
    while(val >=0){           
       val[0]=file.read();   
 char *str;
while ((str = strtok_r(val, ";", &val)) != NULL)    // delimiter is the semicolon
     
  int a = atoi(str);
   Serial.print(a);
delay(10);
    }
   
    file.close();   
     
}
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 651
Posts: 50841
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There are so many things wrong with that code that it is hard to know where to begin.

Code:
char* val = "0";
This points to the character 0 stored somewhere in memory.

Code:
     val[0] = file.read();
    while(val >=0){           
       val[0]=file.read();   
This attempts to overwrite the one character that val points to. The while loop will always be true, because val is an address, and that address is not 0. So, you read another byte into the same memory location, overwriting the previous one.
Code:
char *str;
while ((str = strtok_r(val, ";", &val)) != NULL)    // delimiter is the semicolon
     
  int a = atoi(str);
Then, you try to pass a non-NULL-terminated array to a function that expects a NULL terminated array of chars. Fail!

You need to define an array of fixed size, NOT using a pointer. You need to read data from the card until some end-of-record marker is read, or until the end-of-file marker is encountered. Collect the characters in the array as they are read, adding a NULL after each character added to the array.

When the end of record marker is read, then you want to parse the data, using strtok, not strtok_r.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I see what you mean.
In fact I am a novice in arduino and C language, that's why it's a bit difficult for me to code this program.
I thank you for ur advices, but can u explain me quickly how to use them ?

Code:
char* val = "0";
By example, what should i put instead of that.

 
   
Code:
while(val >=0){           
       val[0]=file.read();
   
 this must be deleted?

 how to create a non-NULL-terminated array?
and a end of record marker ?

If you have a little time  to dedicate to my program, could you correct my wrong things, this will help me a lot!
ty
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 651
Posts: 50841
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
By example, what should i put instead of that.
char val[10];
(If the record length does not exceed 10 characters. If it does, make the value larger.)

Quote
this must be deleted?
No. You need an index into the array. That index should be incremented as the character is added. Don't keep overwriting position 0.

Quote
how to create a non-NULL-terminated array?
That's not what you want. You want a NULL terminated array of characters.

Quote
and a end of record marker ?
That needed to be done when the file on the SD card was created. What does the file look like?

Here is some code that reads from the serial port. It expects the data to be bounded by start and end of packet markers. Reading from a file is simpler, since you know when "the start marker arrives". That happens when you open the file, and after processing each record in the file.

The end of packet marker is probably a carriage return or linefeed (\r or \n).
 
Code:
#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}
You should be able to adapt this to reading from a file, instead of the serial port.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

TY for your help, but I've still problems of conversion.. smiley-sad
In fact my file "Test.txt" contains 3digit-numbers from 0 to 255, like this :
"076;234;145;024;245;ect..."

Here is your code that I adapted.

Code:
#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char name[] = "Test.txt";    // name of the file n my SD card
char inData[1000];
byte index;

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

void loop()
{
  file.open(root, name, O_READ);    //Open the file in read mode.
   char inChar=file.read();              //Get the first byte in the file.
    while(inChar >0){          
    char inChar = file.read();

    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 999)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }
    }
  We are here because all pending serial data has been read , does it change something in the code ?
Code:
 if(started && ended)
  {
 
   // Process the packet = Segment + store in an array + convert to int ?

// segmentation
    char *token;
    token = strtok (inChar, ";");  

// creation of an array (3 digit-numbers)
int a;
char array[3]= {0};  
how to store "token" in this array ?  does   "a=sprintf(array,token)"  is correct ?

Code:
   int a = atoi (array);  
and how to convert them one by one ?

  
Code:
 
    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }

}
« Last Edit: April 29, 2012, 04:40:41 pm by leot » Logged

Offline Offline
Sr. Member
****
Karma: 11
Posts: 358
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Have you considered storing your code in binary instead of text it would simplify this a lot.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 651
Posts: 50841
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
   char inChar=file.read();              //Get the first byte in the file.
    while(inChar >0){           
    char inChar = file.read();
Get the first byte. If it's not NULL, throw it away. Well, OK. I guess that will work.

Define another variable named inChar, that is local to the while loop. Guess what you have now. An infinite loop. The while loop variable never changes value, so the loop never ends.

Quote
In fact my file "Test.txt" contains 3digit-numbers from 0 to 255, like this :
"076;234;145;024;245;ect..."
No <? No >? So, why are SOP and EOP defined as < and >?

Code:
char inData[1000];
Between this array and the SD library, 3/4 of your SRAM is gone.

Code:
byte index;
You can not use a byte sized index into a 1000 element array.

Quote
We are here because all pending serial data has been read , does it change something in the code ?
You'll never get there. So, don't worry about it.

Fix the issues above, then we can talk.
Logged

Pages: [1]   Go Up
Jump to: