As a total noob, I need some guidance on reading from a CSV file for my project.
My project involves driving a set of servos based on the information stored in a CSV file. my intention is for the program to read a line of the CSV file, extrapolate where the motor should be, move the servo to the correct position, and then move on to the next line. Ideally, this would happen at a rate of 4 times a second.
My code for interpreting basic inputs and directing the servos is operational (I've tested it with a simple button/potentiometer) but I have no idea how to use my CSV file as an input.
would I bring the file into an array and read off it? do I need to create a function to import the file? is there any libraries I should be using?
The following are some example records of the CSV file.
120.000,126.000000,0.000000
120.250,130.100006,0.000000
120.500,134.199997,0.000000
120.750,138.199997,0.000000
121.000,142.100006,0.000000
121.250,146.000000,0.000000
121.500,149.699997,0.000000
121.750,153.199997,0.000000
You describe processing a line at a time, so I'd read a line at a time.
Other than that, can't say much until you show us the code you have, so we can suggest how to fold in the new code.
By the way, I'd use Serial Monitor to feed my code one line at a time while testing, then once that's working, focus on a separate code for the file reading part, just reading and echoing the file to SerialMonitor; then as a final step, merge the two.
On simple projects, divide and conquer seems overkill, but OTOH the scope for errors is much smaller, so it's easier to debug where you've gone astray, for both us and you.
Also, please consider reading up on the use of "millis()" instead of "delay()", when it comes time to arrange your scheduling in the file reading sketch.
servo tends to be pretty fast to gain their target position but maintaining a 4Hz timing of course depends on your servo capabilities
your CSV seems pretty simple to read, I assume the first field is timing, and then a couple variables, all coma separated and lines ending with a '\n' ➜ should be pretty straightforward
Did you get these from an actual spread sheet or just make them up? I suspect any spread sheet is smart enough to NOT include trailing zeros. Better check it before writing any code.
DronebotWorkshop shows you how to record and playback data - his example (at 21:45) reads a potentiometer to position a servo, records that data, then plays the positioning data back to move the servo.
the records are taken from the actual file. it was not sourced from a spreadsheet but from a data analysis program.
almost, but not quite. the first field is a timing variable that fluctuates (it resets to zero at inconsistent intervals)
the total file size is around 68kb but could be shortened if needed. As for timing, I'd like it to be reasonably accurate as possible. the movement of the motors would be paired with a pre-recorded video, and going out of sync would not be ideal. A few seconds of fluctuation over maybe 5-6 hours would be okay, but a few seconds over 10 minutes would not.
Of course. I've been testing with a Hall effect sensor so ignore that for now. while I know mapping my speed value to the servo position would be more efficient, I wanted to use conditionals for the option to refine the output durnig later testing.
#include <Servo.h> // add servo library
#define HALL_SENSOR_PIN 9 // Signal pin of hall effect sensor
#define NUM_MAGNET_PER_REV 1 // Number of magnets in the rotating object
// Convert sensor readings to km/h
#define WHEEL_CIRCUMFERENCE 1 // circumference of wheel in meters
#define SECONDS_PER_HOUR 3600.0 // number of seconds in an hour
#define BRAKE 0 // placeholder for csv file
// create servo objects
Servo ServoA;
Servo ServoB;
// store servo posititon
int pos = 0;
void setup() {
ServoA.attach(10);
ServoB.attach(11);
Serial.begin(9600);
pinMode(HALL_SENSOR_PIN, INPUT_PULLUP); // setup hall effect sens
}
void loop() {
// Measure time between magnetic pulses
unsigned long t1 = micros();
while (digitalRead(HALL_SENSOR_PIN) == HIGH);
while (digitalRead(HALL_SENSOR_PIN) == LOW);
unsigned long t2 = micros();
// Calculate speed in km/h
float time_per_rev = (t2 - t1) / 1000000.0 / NUM_MAGNET_PER_REV;
float speed = WHEEL_CIRCUMFERENCE / time_per_rev / 1000.0 * SECONDS_PER_HOUR;
// check if brakes are applied, then set position
// this check would be carried out in feild 3 of the csv
if (BRAKE > 40) {
pos = 180;
ServoA.write(pos);
ServoB.write(pos);
}
// in not, find speed then move to mapped position
else {
if (speed < 10) {
pos = 0;
ServoA.write(pos);
ServoB.write(pos);
}
else if (speed < 30) {
pos = 80;
ServoA.write(pos);
ServoB.write(pos);
}
else if (speed < 50) {
pos = 60;
ServoA.write(pos);
ServoB.write(pos);
}
else if (speed < 75) {
pos = 45;
ServoA.write(pos);
ServoB.write(pos);
}
else if (speed < 100) {
pos = 30;
ServoA.write(pos);
ServoB.write(pos);
}
else if (speed < 125) {
pos = 20;
ServoA.write(pos);
ServoB.write(pos);
}
else if (speed < 150) {
pos = 15;
ServoA.write(pos);
ServoB.write(pos);
}
else if (speed < 200) {
pos = 0;
ServoA.write(pos);
ServoB.write(pos);
}
}
micros(250000);
}
Ok. But be careful to ALWAYS use the same source for the file. Some will remove useless zeros. Some will end a line with a CR. Others will end a line with CRLF.
If the .csv file will always have three entries per line, then this very simple minded approach serves as an example of extracting the data from each line:
// example of strtok() and atof()
char delim[] = ","; //substring delimiters
void setup() {
char* pch; //pointer to token extracted
char message[] = "120.500,134.199997,0.000000";
Serial.begin(115200);
Serial.print("message >"); //echo data line
Serial.print(message);
Serial.println("<");
pch = strtok(message, delim); //get first token
Serial.print("strtok returns >");
Serial.print(pch);
Serial.println("<");
Serial.print("atof returns: "); //extract data
Serial.println(atof(pch),6);
pch = strtok(NULL, delim); //second token
Serial.print("strtok returns >");
Serial.print(pch);
Serial.println("<");
Serial.print("atof returns: ");
Serial.println(atof(pch),6);
pch = strtok(NULL, delim);
Serial.print("strtok returns >");
Serial.print(pch);
Serial.println("<");
Serial.print("atof returns: ");
Serial.println(atof(pch),6);
// etc.
}
void loop() {