But now I have to figure out how to write data to arduino memory, and when it is full stop the movement of the robot and write data to SD card.
JohnyNapalm:
But now I have to figure out how to write data to arduino memory, and when it is full stop the movement of the robot and write data to SD card.
Yes, that is exactly what you need to figure out. This might get you started.
LightuC:
Yes, that is exactly what you need to figure out. This might get you started.
writing to EEPROM right?
No, the idea is to first buffer it in your SRAM. If the amount of data in the buffer is x or if y time has passed or whatever you want, then you issue the write from SRAM to SD.
JohnyNapalm:
The ''small wheel" have an ammount of 20 holes in it as you could see on the previous picture.
The point is that I could NOT see that from your picture.
So, finally, we know that you have an encoder that produces 20 pulses per revolution. If all you want to do it measure the speed of the motor the simple solution is probably to save the value of micros() after every 20 pulses (i.e. once per revolution) and then you can work out the speed.
Have a look at the code in this link. It is designed for an encoder that produces one pulse per second but it will be straightforward to adapt it to report the value of micros() after 20 pulses.
...R
LightuC:
No, the idea is to first buffer it in your SRAM. If the amount of data in the buffer is x or if y time has passed or whatever you want, then you issue the write from SRAM to SD.
And can I use writing to EEPROM?? Because there is much more information about it. I can't find anything about writing to SRAM in arduino.
All variables you define are put in SRAM (unless explicitly tagged for progmem). So to store your data to SRAM you create a buffer-array that holds the amount of data you want to buffer:
// This is a structure to hold your data. I assumed, that your values
// are in the range 0-255 so a uint8_t aka unsigned char is enough
// to hold the data.
struct RobotLog
{
uint8_t rightEngine;
uint8_t leftEngine;
uint8_t averageSpeed;
};
// Now create the buffer. The size is determined by the constant
// 'numOfLogsToBuffer'. I've choosen 60, that would correlate
// with 60 seconds of data recording.
const unsigned int numOfLogsToBuffer = 60;
RobotLog sdBuffer[numOfLogsToBuffer ];
// You will also need an index to indicate the current position in
// the buffer.
unsigned int logBufferIndex = 0;
Now that you have set up your buffer, you will need to implement the following (pseudo) code:
Do every second:
Get the right engine value
Get the left engine value
Get the average speed
Store the values in the buffer at index logBufferIndex
Increment logBufferIndex by one
Check if logBufferIndex is equal to the buffer size
If yes, then stop robot and save buffer to sd
Else continue operation
Thank you veeery much.
I will try to do it all now, and let you know about the progres! :-*
void storeData() {
rbl.leftEngine = leftMotorSpeed;
rbl.rightEngine = rightMotorSpeed;
rbl.Direction = driving_status;
sdBuffer[logBufferIndex] = RobotLog();
logBufferIndex++;
if (logBufferIndex = 60) {
motor_stop();
for(int i = 0; i > 60; i++){
myFile.print(sdBuffer[i]);
}
logBufferIndex = 0;
goBackToDriving();
}
}
You ment something like this? Or I shouldnt make it all in one loop?
Exactly, but I can spot some minor bugs in there:
// This has to be changed.
rbl.leftEngine = leftMotorSpeed;
rbl.rightEngine = rightMotorSpeed;
rbl.Direction = driving_status;
sdBuffer[logBufferIndex] = RobotLog();
// To this
sdBuffer[logBufferIndex].leftEngine = leftMotorSpeed;
sdBuffer[logBufferIndex].rightEngine = rightMotorSpeed;
sdBuffer[logBufferIndex].Direction = driving_status;
Because the buffer is already allocated you should use it directly.
if (logBufferIndex = 60) {
You need to replace the single '=' to '=='
LightuC:
Exactly, but I can spot some minor bugs in there:// This has to be changed.
rbl.leftEngine = leftMotorSpeed;
rbl.rightEngine = rightMotorSpeed;
rbl.Direction = driving_status;
sdBuffer[logBufferIndex] = RobotLog();
// To this
sdBuffer[logBufferIndex].leftEngine = leftMotorSpeed;
sdBuffer[logBufferIndex].rightEngine = rightMotorSpeed;
sdBuffer[logBufferIndex].Direction = driving_status;
Because the buffer is already allocated you should use it directly.
if (logBufferIndex = 60) {
You need to replace the single '=' to '=='
thanks!
I got this error message right now:
no matching function for call to 'SDLib::File::print(RobotLog&)'
I guess I cant just print to file a struct
And the code looks like that right now
void storeData() {
sdBuffer[logBufferIndex].leftEngine = leftMotorSpeed;
sdBuffer[logBufferIndex].rightEngine = rightMotorSpeed;
sdBuffer[logBufferIndex].Direction = driving_status;
logBufferIndex++;
if (logBufferIndex == 60) {
motor_stop();
for(int i = 0; i > 60; i++){
myFile.print(sdBuffer[i]);
}
logBufferIndex = 0;
checking_status();
}
}
for(int i = 0; i > 60; i++){
myFile.print(sdBuffer[i].leftEngine);
myFile.print(sdBuffer[i].rightEngine);
myFile.print(sdBuffer[i].Direction);
}
You can access the struct members like you did, when you assigned them. You should also insert some delimiters like whitespaces, so you can separate the data later.
LightuC:
for(int i = 0; i > 60; i++){
myFile.print(sdBuffer[i].leftEngine);
myFile.print(sdBuffer [i].rightEngine);
myFile.print(sdBuffer[i].Direction);
}
You can access the struct members like you did, when you assigned them.
Oh yes of course I can, stupid me. Thank you very much.
And now do I have to set everything with timers in the link that you sent? Can't I just add this function to the loop section?
I mean, should I use this function as an interrupt or what? Because now I have the problem with stoping robot. So the function that I added to storeData function called "motor_stop" has delay in it and it breaks it all.
Setup an interrupt to fire every second. In the interrupt service routine, set a flag to true. In your loop you poll that flag and invoke the method, when it is true. Or you can use millis() to provide a timebase. You need to keep your isr's short and writing to an sd cards takes like 10 000 ages.
LightuC:
Setup an interrupt to fire every second.
It is hardly necessary to set up an interrupt for a long period like that. Just use millis().
...R
//setting up timer 1
cli();//stop interrupts
//set timer1 interrupt at 1Hz
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register for 1hz increments
OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS10 and CS12 bits for 1024 prescaler
TCCR1B |= (1 << CS12) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();//allow interrupts
//end timer setup
ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz
Serial.println(millis());
}
Ok so I did add timer, and it works well, doesnt interrupt the ride of the robot.
So now in the interrupt service routine I should add the flag as you LightuC wrote.
So I did:
ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz
timeToWrite = true;
}
void loop() {
if(timeToWrite = true){
storeData();
}else{
//starts robot
checking_status();
}
}
void storeData() {
sdBuffer[logBufferIndex].leftEngine = leftMotorSpeed;
sdBuffer[logBufferIndex].rightEngine = rightMotorSpeed;
sdBuffer[logBufferIndex].Direction = driving_status;
logBufferIndex++;
if (logBufferIndex == 60) {
//STOP MOTOR HERE UNTIL FOR LOOP FINISHED
for (int i = 0; i > 60; i++) {
myFile = SD.open("DaneMapy.txt", O_CREAT | O_APPEND | O_WRITE);
if (myFile) {
Serial.println("Writing to DaneMapy.txt");
myFile.print(sdBuffer[i].leftEngine);
myFile.print(" | ");
myFile.print(sdBuffer [i].rightEngine);
myFile.print(" | ");
myFile.println(sdBuffer[i].Direction);
Serial.println("done.");
}
myFile.close();
}
logBufferIndex = 0;
}
timeToWrite = false;
}
Do you think it should work?
Don't print from inside an ISR
ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz
Serial.println(millis());
}
For one reason, printing is very slow and you need the ISR to complete as quickly as possible and secondly, printing requires the use on interrupts and they are halted while inside the ISR.
...R
Robin2:
Don't print from inside an ISRISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz
Serial.println(millis());
}
For one reason, printing is very slow and you need the ISR to complete as quickly as possible and secondly, printing requires the use on interrupts and they are halted while inside the ISR. ...R
Yes I know. That was just for testing. This is not in main program.
void loop() {
if(timeToWrite = true){
storeData();
}else{
//starts robot
checking_status();
}
}
You need to use the '==' for comparison. The single '=' is used for assignments.
for (int i = 0; i > 60; i++) {
myFile = SD.open("DaneMapy.txt", O_CREAT | O_APPEND | O_WRITE);
if (myFile) {
Serial.println("Writing to DaneMapy.txt");
myFile.print(sdBuffer[i].leftEngine);
myFile.print(" | ");
myFile.print(sdBuffer [i].rightEngine);
myFile.print(" | ");
myFile.println(sdBuffer[i].Direction);
Serial.println("done.");
}
myFile.close();
}
You should move your SD.open() and myFile.close() statements out of the for loop. Otherwise you will be closing and opening the file on every iteration. Other than that, this should work.