2
$\begingroup$

I've read and tried the previous StackExchange suggestions here about installing the SerialIO package (including placing SerialIO in the same folder as init.m and and editing the init.m file per Turkel. But when I use

 <<SerialIO`

I still get the error

LinkOpen::linke: Specified file is not a MathLink executable..

(I installed SerialIO from the github repository on a Ubtuntu 12.04 64 bit machine).

(Using Terminal) when I change directory to the SerialIO folder and run the script

./SerialIO

I see the "Create Link" and "Connect to Link" prompts.

I have 2 related questions:

  1. What should be entered at the Create Link / Connect to Link prompts to ensure SerialIO can 'connect' to a device on my system?

  2. What else can I check/adjust to have Mathematica correctly call the SerialIO package ?

$\endgroup$
0

1 Answer 1

7
$\begingroup$

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.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.