[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!
Cool! You can check out the instructable (with your modified code) here:
http://www.instructables.com/id/Mac_OS_Foot_Switch_from_a_Guitar_Amp_Pedal
I added a -R flag to read forever and a little bit to exec applescripts based on what it reads.
Thanks again for the great code sample.
Hi ayman,
Use the code however you like. No real license. I would like a link back if you publish it on the web. :)
Great little bit of code! I was unable to tail/screen the /dev/tty.usb* to see any of the data otherwise. Not sure why.
Is this code under any sort of BSD/CC license? I’d like to post a modification I made so it will read forever (or until ^C) and do stuff. Writing the instructable now. Just wanna know if I can reuse this. :)
Ok!, I got the time to document the Arduino Communcation through files, as described one post above. If anybody is interested, check out this webpage http://mrdoall.dnsalias.com/wiki/index.php/Arduino_Communications
Well I can say that this topic has been round and round, but I learned alot from all of it. Getting back to the communication part however, I have come up with a way to communicate bi-directional with any SW language via an Arduino log file as the output and the command line Arduino-serial as the input. Using the command “tail -f /dev/ttyUSB0 >> ArduinoLogFile” you can generate any output you desire from the command “serial.println()” into a log file. Using whatever SW you want you can call command-line Arduino-serial commands to send one char codes that the Arduino can respond to in any fashion you desire, including Arduino Log file entries.
I know I have not outlined this clearly and with examples, but I just got it all working and thought I would share it. It is a hack, but it is the quickest way I could get the 2-way communication without writing much code. You can even create shares to the directories where the data is and share it over the network. It is a simple concept, but fairly powerful with little effort.
If I get more time I will create an entire write up to publish.
A big thanks!!!!!!!! to all you hackers that provided the base of information and code for me to accomplish this method.
My shell script package (mentioned above 2/12/08) has grown to include GUI scripts for IO & PWM control using Xdialog. It is also available 24/7 now, via ‘wget http://user.cavenet.com/rolandl/SMS1.tgz‘
Please check it out, it’s a good source for fixing scripting problems as mentioned above.
Hi Ben,
No, you can’t. The bootloader protocol used to load sketches is pretty complex. Arduino actually uses the “avrdude” program to handle it. But you can load sketches from the command-line. Search around the Arduino forums and check out this page for how to do it:
http://www.arduino.cc/en/Hacking/CommandLine
Hi
Can i use the –send-data to load an arduino sketch into the device without using the arduino GUI?
Ben
This is the sort of thing i have been looking for but i want to be able to read key presses in real time so i can use key presses to control the arduino.
Is there any way of doing this at all that anyone knows of?
Hi rutro,
By design, the current Arduino’s will reset when the serial port is opened. See the “Automatic (Software) Reset” section of the Arduino Deicimila description. If you don’t want this automatic reset feature, you’ll have to hack your Arduino a bit. There’s some discussion in the forums on how to remove serial port reset.
And normally one shouldn’t open up a serial port with more than one application. The results can be undefined.
Hello Todbot.
Oddly, whenever I send things using -s it seems to reset my Arduino board. It works fine, however, when I have serial monitor mode enabled in Arduino IDE. When I have this enabled /bin/stty’s output changes as well, leading me to think arduino-serial is not setting some things, or there are problems with using it in OS X…
With serial monitor enabled:
speed 9600 baud;
lflags: -icanon -isig -iexten -echo
iflags: -icrnl -ixon -ixany -imaxbel -brkint inpck
oflags: -opost -onlcr -oxtabs
cflags: cs8 -parenb -hupcl clocal
min time
0 20
Without:
lflags: -icanon -isig -iexten -echo
iflags: -icrnl -ixon -ixany -imaxbel -brkint
oflags: -opost -onlcr -oxtabs
cflags: cs8 -parenb
Exact command used:
./arduino-serial -p /dev/tty.usbserial-A6004pba -n 6
Hi Pat,
That’s a great page, a better writeup than this one I think. :)
I think the reason why you’re seeing a lot of CPU usage for your script is that it’s spawning and killing processes as fast as possible, which is a fairly big task for an OS. Also, each time you run the arduino-serial program, it opens & closes the serial port (another potential heavyweight operation) which has the effect of resetting the newer Arduinos that have auto-upload circuitry.
You’ll probably have better luck for your application by either incorporating the arduno-serial code into another C program that does the logic your script does, or to use a scripting language like Python or Perl, which has both serial support and is a good scripting language. See some of the above comments for how to do ‘arduino-serial’ in Python.
hi todbot
very great program :) thanx alot. i’ve wrote a little bash script for reading some strings from arduino a starting some progs… every thing works fine. the only problem is, that “top” shows a big cpu capacity… has you or somebody an idea?
here is the script:
http://de.wikiants.org/Arduino-serial#Bash_Script_.7C_Kommunikation_mit_Linux
Hi Batoub,
What is the exact arduino-serial command you’re using? Are you trying to read data? If so, be sure to have at least a 2-second delay (see my previous comment) to deal with the Arduino’s reset.
It may be that screen is opening the serial port but not closing it, so by the time arduino-serial is used, it’s past the reset delay.
Hi everybody !
I have a strange problem.
The program is working when I have just upload the program to the arduino (with the arduino software), it’s working working very well.
But If I reboot, I try to configure the TTYUSO with this :
stty -F /dev/ttyUSB0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts
I try to launch the program : not working :/
I launch screen : screen /dev/ttyUSB0 9600
I stop screen, launch the program : it’s working.
What’s wrong with my configuration ??
Hi Casper,
I must admit the serialport_read_until() function is the least polished part of arduino-serial. So there might be a logic problem.
However, if you’re using an Arduino Diecimila or similar newer Arduino, you may be trying to read while the board is in reset, since on Mac OS X & Linux, opening the serial port resets the Arduino.
To deal with this, insert at least a 2-second delay before reading. Here’s an example that inserts a 5-second delay between opening the open and reading:
Hi harohase,
I’m not familiar with geexbox, but it looks like Linux, so I don’t see why you couldn’t make an arduino-serial package for it.
Hey Todd. Im basically trying to read my arduino from my /dev/ttyUSB0 (which works fine with screen). I found out that it exits in the serialport_read_until() with -1 (can’t read). I find this a bit strange since my arduino is just spamming the serial, so there should be something. Any ideas? (btw the baudrate is right so its not that.)
hi there
will all this things work with geexbox too?
can i implement a package to the geexbox iso to get it working?
Hi Jason, Sorry, no clue, I don’t use Windows; I thought that it had the POSIX libraries. I seem to recall seeing a Visual Basic serial port library a while back, perhaps generally usable in .NET. Try googling around for “VB serial library” or similar.