I got it working (M8 on Ubuntu 12.04)! The answer here is not elegant, may use redundant commands and may not work across other systems. But it got M8 in contact with the USB port and my Arduino. I used the SerialIO package on Wolfram site).
Some suggestions/commands that may be useful in troubleshooting:
Identifying the USB connection for the device
In Terminal, you can use the command below (\$ is my shorthand for the terminal prompt. Don't type the $, but you do need a space between ls and /dev/..)
$ ls /dev/tty*
and try plugging your device in/out and rerunning the ls command. You'll soon figure out what is changing. On my system the Arduino Uno appears under /dev/ttyACM <+values>. Other Linux systems may show up as /dev/ttyUSB <+values>. So I generally start (in Terminal) with
$ ls /dev/ttyACM*
to find the device. On my machine, the values may increment each time its plugged in e.g. a device unplugged from /dev/ttyACM0
may reconnect at /dev/ttyACM1
.
you can also do this in Mathematica using the function below which also returns values you can use in other commands:
usblist = ReadList["!ls /dev/ttyACM*", String]
As outlined above, adjust the command to fit your system (eg .../ttyACM*
or .../ttyUSB*
etc). The * part returns all names that begin with the prefix ..ACM". Look up the definition of ReadList
and the "!
" to understand how this interesting command allows Mathematica to get information directly from your OS.
Using SerialIO in a Notebook
Before calling the SerialIO package in the notebook, I changed directory to the one where I unzipped the SerialIO
package. Since I put mine in /usr/local/Wolfram/Mathematica/8.0/AddOns/Packages/
, I used the command
SetDirectory[$InstallationDirectory <> "/AddOns/Packages/SerialIO/" <> $SystemID]
Assuming your folder structure is standard and you installed SerialIO
under the M8 directory structure then the $InstallationDirectory
takes care of the main part of the path (up to the ../8.0 in my case), "/AddOns/Packages/SerialIO" is the "glue" to the specific SerialIO folder under Mathematica and $SystemID
is your OS specific file path (from MacOSX, Windows, Windows-x-64 etc) within the SerialIO folder itself. (To test these values you can evaluate the commands $InstallationDirectory
and $SystemID
in a notebook)
To start a SerialIO Link use
Install["./SerialIO"]
to load the SerialIO package. I tried Needs
and <<
with their formatting (quotes and backticks) but they either didn't work and/or didn't return error messages. If this works, the Output should return info on a LinkObject
such as:
LinkObject["/usr/local/Wolfram/Mathematica/8.0/AddOns/Packages/SerialIO/Linux-x86-64/SerialIO", 137309, 10]
If you don't see a LinkObject, you need to do more digging. A handy function is reportPackages
from wilbert van meerwijk that you can include in your notebook here and double-check SerialIO Package is installed.
Another command to show you have established a connection to SerialIO is Links[]
. Again, the output should include a LinkObject like the example above.
To connect to a device (eg an Arduino), set comms parameters and get data, you need to know the path the Arduino is on and elect the same baud rate that your Arduino sketch is sending data, as defined in Serial.begin
function e.g Serial.begin(115200)
;
Mathematica commands (myArduino is a arbitrary description):
myArduino = SerialOpen["/dev/ttyACM2"]
SerialSetOptions[myArduino, "BaudRate" -> 115200]
x = Dynamic[Table[SerialRead[myArduino], {10}], UpdateInterval ->1]
If the Arduino is streaming values to the Serial port with line terminations (e.g Serial.println(value)
, then the Dynamic
function picks them up in groups of 10 and updates their display in M8 once a second. For this to work, under the Mathematica menu choice Evaluation
, check the box for Dynamic Updating Enabled
.
Unfinished business - direct USB baud control
I have found that the SerialSetOptions
does not always set the baud rate and you see gibberish characters coming through. I instead use Terminal
before calling the M8 SerialOpen
command. So in Terminal
$ stty 115200 cs8 -parenb crtscts -echo -F /dev/ttyACM2
builds on what we already know to set the baud rate on the PC side. Change baud rate (here 115200
) and the path to the device (here /dev/ttyACM2
) based on the baud rate of your Arduino's output and device path.
I'll update/edit if I can solve any of these issues.
EDIT: REVISION/IMPROVEMENT
The code below uses Mathematica alone to identify, and set the baud rate for, the device connection. It assumes the highest numbered device is the Arduino.
Load the SerialIO Package:
I don't know why, but for dependable function it seems to need both Install
and Needs
, at least for an initial run.
SetDirectory[$InstallationDirectory <> "/AddOns/Packages/SerialIO/" <> $SystemID]
Install["./SerialIO"]
Needs["SerialIO`"]
and you should see a LinkObject created e.g.
LinkObject["/usr/local/Wolfram/Mathematica/8.0/AddOns/Packages/SerialIO/Linux-x86-64/SerialIO", 732, 22]
Now find the device (assuming its the highest number). Reflecting the techniques on this page, Natural number sorting is required to identify device in case we get into double digits i.e so that /dev/ttyACM10
follows /dev/ttyACM9
and is Last
.
(Edit the /dev/.
path as described to search on your machine. An other choice might be "!ls /dev/ttyUSB*"
).
wherePorts = ReadList["!ls /dev/ttyACM*", String];
whereArduino = Last@wherePorts[[Ordering[Characters[wherePorts]]]]
Prepare the Arduino's port (using 57600 baud in this example) by running the stty
[+options]
command. The SerialSetOptions
function of SerialIO didn't work in my hands to set baud rate.
Then open Serial through the SerialIO command SerialOpen
.
setArduino="stty 57600 cs8 -parenb crtscts -echo -F " <> whereArduino
Run[setArduino];
Pause[2]
myArduino = SerialOpen[whereArduino]
Gather some data (here, 10 "sets").
fromArduino=Table[SerialRead[myArduino],{10}]
EDIT#2
Apologies for the length but an improved way to find the path to your Arduino assuming its the last device plugged in is to probe the system log via dmesg
. In my case, the Arduino is the last log entry that includes the phrase being searched i.e "USB ACM device". The approach is from this answer and might need adjustment as to the phrase being grepp'd. Typing dmesg
into your Teriminal will list all system events in chronological order (last at bottom of list) and you can choose from there.
This Mathematica code does the dmesg
and grep
, cuts the String into pieces at ":", takes the 2nd last entry and Joins
it to give a path string that can now be used:
betterwhere = StringTrim@StringSplit[Last@ReadList["!dmesg | grep 'USB ACM device'", String], ":"];
betterwhere2 = betterwhere[[-2]];
whereArduino2 = "/dev/" <> betterwhere2;
Again, your actual path specifics may vary.