[NOTE! arduino-serial has been greatly updated. See the “Arduino-serial: updated!” post for details]
The Arduino’s USB port is actually a serial port in disguise. To your computer it appears as a ‘virtual’ serial port. This is good news if you want to write custom code on your computer to talk with the Arduino, as talking to serial ports is a well-solved problem. (Unfortunately, so well-solved that there’s many ways of solving it.)
On the Arduino forum there’s been a few requests for some example C code of how to talk to Arduino. The nice thing about standard POSIX C code is that it works on every computer (Mac/Linux/PC) and doesn’t require any extra libraries (like what Java and Python need). The bad thing about C is that it can be pretty incomprehensible.
Here is arduino-serial.c (github for full source), a command-line C program that shows how to send data to and receive data from an Arduino board. It attempts to be as simple as possible while being complete enough in the port configuration to let you send and receive arbitrary binary data, not just ASCII. It’s not a great example of C coding, but from it you should be able to glean enough tricks to write your own stuff.
Usage
laptop% ./arduino-serial Usage: arduino-serial -b <bps> -p <serialport> [OPTIONS] Options: -h, --help Print this help message -b, --baud=baudrate Baudrate (bps) of Arduino (default 9600) -p, --port=serialport Serial port Arduino is connected to -s, --send=string Send string to Arduino -S, --sendline=string Send string with newline to Arduino -r, --receive Receive string from Arduino & print it out -n --num=num Send a number as a single byte -F --flush Flush serial port buffers for fresh reading -d --delay=millis Delay for specified milliseconds -e --eolchar=char Specify EOL char for reads (default '\n') -t --timeout=millis Timeout for reads in millisecs (default 5000) -q --quiet Don't print out as much info Note: Order is important. Set '-b' baudrate before opening port'-p'. Used to make series of actions: '-d 2000 -s hello -d 100 -r' means 'wait 2secs, send 'hello', wait 100msec, get reply'
Example Use
Send the single ASCII character “6” to Arduino
laptop% ./arduino-serial -b 9600 -p /dev/tty.usbserial -s 6
This would cause the Arduino to blink 6 times if you’re using the serial_read_blink.pde sketch from Spooky Arduino.
Send the string “furby” to Arduino
laptop% ./arduino-serial -b 9600 -p /dev/cu.usbserial -s furby
Receive data from Arduino
laptop% ./arduino-serial -b 9600 -p /dev/cu.usbserial -r read: 15 Hello world!
The output is what you would expect if you were running the serial_hello_world.pde sketch from Spooky Arduino.
Send ASCII string “get” to Arduino and receive result
laptop% ./arduino-serial -b 9600 -p /dev/cu.usbserial -s get -r read: d=0
Internals
There are three interesting functions that show how to implement talking to serial ports in C:
int serialport_init(const char* serialport, int baud)
— given a serial port name and a speed, return a file descriptor to the open serial port.int serialport_write(int fd, const char* str)
— write out a string on the given a serial port file descriptorint serialport_read_until(int fd, char* buf, char until, int timeout)
— read from serial port into a buffer until a given character is received or timeout reached
You can and should write improved versions of the read and write functions that better match your application.
Update 8 Dec 2006:
Justin McBride sent in a patch because it turns out Linux’s termios.h doesn’t define B14400 & B28800. I’ve updated arduino-serial.c to include the patch, but commented out for now. No one uses those baudrates much anyway. :) If you need them, uncomment the additions out, or better yet, download Justin’s tarball that includes the changes and a Makefile to auto-detect your platform.
Update 26 Dec 2007:
Added ability to sent binary bytes with the ‘-n’ flag.
Added a delay option so you can open a port, wait a bit, then send data. This is useful when using an Arduino Diecimila which resets on serial port open.
Update 29 Apr 2013:
I apologize to everyone who has commented on this post but who hasn’t received a reply. This code has had a much longer life than I expected and it was hard to get back to it to fix some of its obvious deficiencies.
I did finally get back to it (but not the comments). I’ve rewritten arduino-serial a bit and added some new options. Hopefully this will address many of the issues people have had. You can read about the changes in the “Arduino-serial: updated!” post.
Also, arduino-serial now lives on Github at:
https://github.com/todbot/arduino-serial
Please post issues and patches there. Thanks!
Thanks, but still getting a “No such file or directory” error. Anything else I might try?
Carl
Hi Carl,
Your command looks good. But since “arduino-serial” was written back before the auto-resetting Arduinos, you may want to add a slight delay before sending the “a” to let the Arduino come out of reset. That is, try:
./arduino-serial -b 9600 -p /dev/tty.usbmodemb21 -d 2000 -s a
This will cause arduino-serial to open the serial port (which causes the Arduino to reset), wait 2 seconds, then send an “a”.
Thanks, been trying a bunch of variations of the command above that sends a single character
but no go yet. I substituted the name shown in the Arduino app for the board and tried this to send it an
“a” but still no joy.
./arduino-serial -b 9600 -p /dev/tty.usbmodemb21 -s a
Any thing else I might try.
Very much appreciate your help.
Carl
Thanks, been trying a bunch of variations of the command above that sends a single character
but no go yet. I substituted the name shown in the Arduino app for the board and tried this to send it an
“a” but still no joy.
./arduino-serial -b 9600 -p /dev/tty.usbmodemb21 -s a
Any thing else I might try.
Very much appreciate your help!
Carl
Hi Carl,
Yup, those commands are run from Terminal.app. When you open Terminal up, you will see your computer name instead of “laptop”.
Dumb question I’m sure, but are these commands executed from the Terminal app?
Also how do I define my machine as opposed to the “Laptop” used in the samples?
Thanks,
Carl
It works for me on Mac Lion. Thank you for this code sample.
To those getting gibberish when reading,
Are you placing the -d before the -r ?
example working command:
./arduino-serial -b 9600 -p /dev/ttyUSB0 -d 2000 -r
Well, it seems there really isn’t a solution here. Too bad for the lack of support (or suggestions), I really liked this library.
I’m having the same problem as Nicola, what to do?
Just wondering if you had any suggestion on what I should try?
By the way, even using CoffeeNinja’s example I get the same gibberish (namely: testtest, tt, tetest), even after adding a delay…
Thanks for the fast reply and for any insight. Yes, I am using serial.println(). As I mentioned, I can read the serial well using other methods, including a very simple python script I wrote.
Here’s the very simple sketch:
Can you paste in the sketch you’re using on the Arduino? Are you doing a Serial.println()?
Hi,
Thanks for this great library. I am having issues with it, when trying to read from serial. I am using, as a test case, the Hello World program which is supposed to output: “0 Hello world!” “1 Hello world”. Instead I have only random chunks, such as: “0 world!”, “0Hello world!”, “0 H world”, etc…
I tried several delay times, with similar results. I wonder, why isn’t the system reading the full string?
Thanks for any insight.
Regarding my last post, I just need to add some delay
-d 2000 did the trick
I am getting jibberish when reading with this, any ideas?
./arduino-serial -b 9600 -p /dev/ttyUSB0 -r
read: ?/|?5|?
The jibberish changes even though I’m writing a static string of “test” to the serial port from arduino.
Baud rates are the same, serial monitor from arduino IDE and cat /dev/ttyUSB0 shows “Test” which is what I would expect.
Sketch:
void setup(){
Serial.begin(9600);
}
void loop(){
Serial.println("test ");
delay(1000);
}
Hello. I added fsync(fd) into serialport_write() function.
Hi Joshua, Apologies, I had some file issues. The updated version of arduino-serial with the ‘-d’ option is back now.