Pages: [1]   Go Down
Author Topic: Using command line "mode" and "copy" commands to obtain Arduino data  (Read 1222 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's a picture of my circuit.

http://imgur.com/ZEZon

Very simple. All it does is analogRead() the value of a potentiometer and serial.Print() it out. This is the sketch program.

void setup() {
    Serial.begin(115200);
}
void loop() {
    Serial.print(analogRead(0));
    Serial.print(byte(26)); //prints an end of file character. you'll see why.
}

When you open up the serial monitor in the Arduino IDE, you can easily see the potentiometer values streaming with no errors. What I wanted to do was get that potentiometer value into a C program as easily as possible. So I wrote this program :

include <iostream>
include <stdio.h>
FILE *arduino;
char tempf[64];
int main() {
    system("mode com3:115200,n,8,1");
    arduino=fopen("COM3:","r");
    while(1) {
        fscanf(arduino,"%s",tempf);
        printf("%s\n",tempf);
    }
    fclose(arduino);
    return 0;
}

I know the baud rate is really high, but that doesn't really seem to matter. The program works... sort of.

What will happen is that suppose the potentiometer is set at 712. In the Arduino IDE, I can see it streaming into the serial monitor at that value. I can twist it and watch the values change. Everything works. Here is the problem with pulling the data from the Arduino as a "copy" command or file copy. By file copy I mean that you can do this :

1. USB plug in the Arduino board.
2. Open the command line
3. Type in "mode com3:115200,n,8,1" without the quotes, where com3 is whichever port the USB is plugged into and 115200 has to match the baud rate set by Serial.begin() in the Arduino program.
4. Now type in "copy COM3: testfile.txt"
5. Open testfile.txt in notepad and you'll see that the contents are a single line with 712, which is the potentiometer value. Remember that Serial.print(byte(26)) line? That made sure that the copy command would stop. If you didn't have Serial.print(byte(26)) in the program, the copy command would run indefintely. You could open testfile.txt while it was copying and see a stream of data. If you cancel the copy command, it deletes testfile.txt. You can copy testfile.txt before canceling, but thats a pain in the neck. Just put at Serial.print(byte(26)) in there and that makes the copy command recognize an end of file and stop.

Here's where it all gets messy. Run that copy command a few times.

copy command 1 - testfile.txt shows 712 - everything is good.
copy command 2 - testfile.txt shows 712 - everything still good.
copy command 3 - testfile.txt shows 12 - it missed the 7.
copy command 4 - testfile.txt shows 712 - everything is good again.
copy command 5 - testfile.txt is empty - not good.
copy command 6 - testfile.txt shows 2 - it misse the 7 and the 1.

This doesn't happen in this order. It may get 712 twenty times in a row, then it will pull a 12, a 2 or nothing. I think what is happening is that since the Arduino is streaming out information which is not synchronized with the copy command, it's only picking up a character and then everything to the right.

At this point, if you turn the potentiometer, suppose to 286, the copy command will still pickup the change and show 286... but sometimes 86, sometimes 6 and sometimes nothing.

So I tried writing a C program which reads COM3: like a file. It works in the same manner as the serial monitor in the Arduino IDE. You can see the potentiometer values streaming along just fine. Twist the knob and watch the values change. You can see that the tempf[] variable is now very simply filled with data supplied by the Arduino.

But that didn't fix it.

If the potentiometer is stable, the streaming display in the C program shows it fairly stable. I made it output to a file and saw that when a potentiometer is stable, it only messes up the value about 1% of the time. If the value is 863, it will show 863 about a hundred times before it shows 63, 3 or nothing.

It gets worse when you turn the knob. Turning the knob when the C program is running makes all kinds of weird errors. It still does the catch-only-characters-to-the-right problem, but it is more like 50% this time. About half the potentiometer values are junk during a transient, when the knob is turned.

Any thoughts on how to fix this? I tried changing the baud rate, which didn't fix it. I tried slowing down the while(1) loop in the C program to only read the COM3: file once a second rather than 100 times a second, which didn't fix it.

I think it all comes down to the fact that the Arduino output data is not synchronized with the "copy" command or fscanf() in the C program.

I know there are all sorts of libraries out there I could install. The problem with that is that it seems silly to me to have to fill out 50 lines of code just to read from a serial port in a barebones simple ANSI C program.  I'm doing it in two lines of code... but it's not quite right yet.

There is bound to be some guy to tell me to learn python, C# or some other stupid idea. That is overkill. I'm able to do everything I want in plain C without having to learn 5 other programming languages.


I think there is something very simple that I am missing. I thought about writing a function to do some sort of idiot check of the potentiometer value, but that would be the equivalent of programming duct tape. I also thought about writing this code :

Serial.print(0);Serial.print(" ");Serial.print(0);Serial.print(" ");Serial.print(0);Serial.print(byte(26));

Which would, suppose the potentiometer value is 473, look like this :

473 473 473
473 473 473
473 473 473
73 473 473
473 473 473
3 473 473
473 473 473
 473 473
473 473 473

Which means that the fscanf() or "copy" commands might still miss a few characters, but it will still have the chance of getting some good ones.

Another idea might be that if I have 3 potentiometers set up on a board, I could make identifiers for each of them and stream that data out, where the C program could parse through and recognize what is what. Arduino code of :

Serial.print("potlabel0");Serial.print(" ");Serial.print("potlabel0");Serial.print(" ");Serial.println(0);
Serial.print("potlabel1");Serial.print(" ");Serial.print("potlabel1");Serial.print(" ");Serial.println(1);
Serial.print("potlabel2");Serial.print(" ");Serial.print("potlabel2");Serial.print(" ");Serial.println(2);

Supposing potlabel0 was set at 473, potlabel1=395, potlabel2=832 would have an output like this

potlabel0 potlabel0 473
potlabel1 potlabel1 395
potlabel2 potlabel2 832

would allow little bits of text to be cut off on the left side of each line, then the C program could read the string, match it to potlabel0 in the C program and assign 473 to a variable in the C program. This is another kind of programming duct tape, but it's a little more clever.


I'd rather not do this with duct tape, and I really don't want to install some library or worse, learn a completely new programming language. That's not the point. There has to be a way to make this very simple arrangement of two lines of code work. It's simple, it's quick, but it doesn't work quite perfectly yet. There has to be a way to get it working.

Any thoughts?
Logged

Lancashire, UK
Offline Offline
Edison Member
*
Karma: 9
Posts: 1991
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What I do (using BASH) is to have the arduino streaming the data in lines (load of Serial.print with Serial.println on the end).

Then I have in BASH :

Code:
cat /dev/ttyUSB0|head -n 6|tail -n 3 >> /root/arduino

It reads 6 lines from the port and chops off the last 3 and saves them to a file.  If the first line is caught half way through it doesn't matter since its thrown away. In this case I have 3 lines with different data in each. I have the arduino add something I can easily pick out on the end of a line and use grep to chop that line out from the file (since they don't arrive in any paricular order).  It works well, no libraries, no deep magic, it just goes.   It should be adaptable to be used from any system, using Linux and BASH I disabled the autoreset since other wise it resets every time the line above is called.  (I have a 47uF capacitor between GND & Reset).
Logged


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

That looks like what I am settling on. I'm putting in a lot of chaff text before, a space, a label, then the value, a space, then more chaff.

The C program reads in each piece of text, if one of the scanned in pieces of text matches the label I'm looking for, the next one is the value I want.

Can assign more label-value pairs with chaff between them. It works.
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 208
Posts: 8854
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

One way to get complete lines is to put in a "start of line" marker and throw out characters until you reach a "start of line"
For example if you had 5 pots you could send all five values each line:

#27 134 89 1012 396
#27 134 89 1012 396
#27 134 89 1012 396
#27 134 89 1012 396
...

Your program would read until it found a "#", then read digits until it reached a ' ' or '\n'.  Repeat for the other four number, then go back to looking for the next '#'.

You could send one value per line if that would be more convenient:

#0 27
#1 134
#2 89
#3 1012
#4 396
#0 27
#1 134
#2 89
#3 1012
#4 396
...
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Lancashire, UK
Offline Offline
Edison Member
*
Karma: 9
Posts: 1991
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Theres no chaff, just data read a couple of times and discard the earlier multiples that could be wrong.

These are the 3 lines saved from the 6 read. The arduino sends the 3 lines of data out every couple of seconds.  It reads 6 lines from 2 or 3 transmissions of the data and uses the last 3 lines.
The GAS,BITS & LEC I programmed the arduino to put on the ends so each line of data is easily picked out no matter what order they actually appear in.
Code:
1011947 1012218 1012487 1012754 1013022 1013288 1013555 1013820 1014086 1014352 1014619 1014885 1015150 1015416 1015683 1015948 1016214 1016480 1016747 1017014 1017281 1017546 1017814 1018081 1018347 1018613 GAS
1032097 E 1456 88812 270.00W 7068 G 101861398 692 DT 681 113 301 796 338 320 320 320 320 320 LI 496.21 390.00 304 TP 1020 312 BITS
1011399 1012096 1012724 1013466 1014210 1014956 1015586 1016117 1016647 1017161 1017672 1018187 1018687 1019427 1020275 1021121 1022156 1023342 1024510 1025686 1027083 1028282 1029189 1030079 1030968 1031857 LEC

They are then assembled to produce this :

http://pluggy.is-a-geek.com/
« Last Edit: February 27, 2011, 05:47:01 pm by pluggy » Logged


Pages: [1]   Go Up
Jump to: