# Programming the World with Arduino and Mathematica

GROUPS:
 Ian Johnson 15 Votes Note : this code is now obsolete, superseded by the built-in Mathematica Arduino driver starting in version 10.1Hello all, today I am going to demonstrate the use of Arduino Drivers I recently developed using the new functions in Mathematica 10. This demonstrations uses the following: Mathematica 10 Arduino Software Arduino board (Uno recommended) 220 Ohm resistor 10k Ohm resistor LED Momentary push-button 2x Potentiometers All of the hardware components can be found in the Official Arduino Starter Kit and almost all similar Arduino kits.The functions I developed should in theory be system independent, i.e. run on Linux, Mac OS X, Windows, etc., but I used Windows to develop the functions, so I can only confirm that it works on Windows. I would love for others to try this out on Linux and Mac OS X and post their results.The first step will be to upload the sketch I developed for the Arduino to your Arduino. You can do this using the Arduino software.You can download the sketch that is attached to this post. The filename was changed from a .ino to a .txt, so you may need to change it back before the Arduino software recognizes it. Now select your Arduino board (I developed this for the Uno, so can only confirm that the Uno works, but again in theory should work on any Arduino), and open the .ino file you downloaded and upload it to the board.After uploading the sketch to the Arduino, connect your Arduino and determine which Serial port your Arduino is attached on. One easy way to do this is to open the Arduino software and go under Tools -> Serial Port. On Windows machines this is a COMXX, where XX is some non-negative integer. On Macintosh machines, it is generally "/dev/tty.usbmodemXXXXXX" or "/dev/tty.usbserialXXXXXX", where X is some string of letters or numbers. In Linux, it is generally "/dev/ttyXXXX",where XXXX is some string of letters and numbers. Keep this port in mind as we will need it in a second.Now the last setup step is to install the Driver package. It can be downloaded as an attachment to this post. Download it and open up Mathematica 10 and run << "(path_to_file)/ArduinoDriver.m" Where (path_to_file) is wherever you downloaded the file to, for instance on Windows this might be C:\Users\Ian\Downloads\ArduinoDriver.mNow, to open a connection to the device we use arduinoObject = DeviceOpen["Arduino", "COM4"] Where "COM4" is my serial port, replace that with whatever port your Arduino is attached on.Now for some basic device control, we can use DeviceWrite[arduinoObject, <|pinNumber -> 1|>] To control the digital state of pinNumber, which should be an integer between 2 and 13, or a string corresponding to one of the analog pins, i.e. "A0" through "A5". Note that the strings must be capitalized.Now attach an LED as shown in the Fritzing diagram below.We can now blink the LED with the following code. Do[( DeviceWrite[arduinoObject, <|pinNumber -> 1|>]; Pause[1]; DeviceWrite[arduinoObject, <|pinNumber -> 0|>]; Pause[1]), {5}] This will blink an LED attached to pinNumber 5 times, for one second each time. Note that pinNumber which must be defined elsewhere. For the circuit above it should be equal to 11.We can also use the "analog" write functionality of the Arduino with DeviceWrite, using the following syntax DeviceWrite[arduinoObject, {pinNumber, "analogOutput", state}] Where pinNumber is a valid pin value, and state is an integer between 0 and 255, corresponding to the 8 bit resolution of the PWM pins.If your LED was attached as in the picture above, using the following will allow you to adjust the brightness of the attached LED. Note that as the value is dynamically changed, the brightness jumps around, this is a known bug. Manipulate[ DeviceWrite[arduinoObject, {11, "analogOutput", analogWriteValue}], {{analogWriteValue, 0, "Value"}, 0, 255, 1}] We can also read values from pin's states from the Arduino using DeviceRead. Before we can read values though, we need to configure the values using the function DeviceConfigure. To configure pinNumber as a digital input, we can use DeviceConfigure[arduinoObject, <|pinNumber -> "digitalInput"|>] This also works with analog pins, with the same syntax, except with "analogInput" instead of "digitalInput". Note that this is expandable to multiple pins, as it uses an association. In that case, we would just add another key-value pair to the association. This also works to configure a pin to be an output with "digitalOutput". Now that the pin is configured correctly, the Arduino will begin outputting values over serial, and the Serial TX light should light up on your device.Let's try reading a pin with the following simple circuit, using a button and a resistor. With the circuit built, to read values, we use DeviceRead[arduinoObject, pinNumber] This returns the value of the pin as either a 0, corresponding to a low voltage, or a 1, corresponding to a high voltage.Evaluating the previous command while holding down the button should return a 1, while without holding down the button should return a 0, if the circuit is built as described. The Serial read buffer may take two evaluations to be updated the very first time this is evaluated, but after that it should change properly.If pinNumber was an analog input, this would return a value between 0 and 1023, corresponding to the 10 bit resolution of the analog to digital converter inside the Arduino. This function is also compatible with lists of pin numbers, where an association of pins to values is returned. Note that pinNumber can be either a non-negative integer between 2 and 13, or a string of the type "AX", where X is a non-negative integer between 0 and 5. This is done as follows DeviceRead[arduinoObject, {pinNumber1, pinNumber2, ...}] This returns an association of the type <|pinNumber1->state1, pinNumber2->state2, ... |>.Let's also set up another circuit to demonstrate the analog input functionality. This would be ideally done with a joystick, but it can be done just as easily with two potentiometers (which is basically all a joystick is). The following code will display a circle at the coordinates, which are derived from the two potentiometers. The first thing we need to do is setup the pins to be analog inputs. We can get both values from DeviceRead as an association, which we then get the values from using Values, then divide the coordinates by 1023 to map the circle's coordinates to between 0 and 1. We also subtract the values from 0.5 to center the circle at the origin. DeviceConfigure[arduinoObject, <|"A0" -> "analogInput", "A1" -> "analogInput"|>]; Dynamic[Graphics[{Blue, Circle[ (Values[DeviceRead[arduinoObject, {{"A0", "A1"}}]])/1023 - .5, 0.1]}, Axes -> True, ImageSize -> {800, 800}, PlotRange -> {{-.75, .75}, {-.75, .75}}], UpdateInterval -> .5] Thanks! Attachments:
2 years ago
19 Replies
 Ian, this is an excellent post - thanks so much for sharing! Wolfram Community allows file uploads. I think you should attach whatever complimentary to your project files you have - to the actual post. Just click edit on your post and than attach the files. Again, thank you for great material and detailed project description.
2 years ago
 Ian Johnson 2 Votes Thanks for the suggestion, I attached a notebook, which is just basically the original post in notebook form.
2 years ago
 This is great - it is nice to have this all in one notebook. But I actually meant ArduinoDriver.m file that is currently linked to webpage with an expiration date. That file won't be accessible after some time. If you wish to attach it - your original post can take many attachments.
2 years ago
 Ian, when using your wonderful Arduino Driver with an Arduino Micro I find that serialBufferRead, at odd times, does not contain the full data array upon which or also unrelated to this occurrence the notebook looses connection to arduinoObject. Is it advisable to include a second If statement in ArduinoRead[pin_] which checks for the Length of serialBufferRead ? I am using OS X 10.9.5 . I include a notebook with results. Thank you in advance, Hanspeter Attachments:
1 year ago
 Hi, I have been looking into this, and I think the problem here is that too many requests are being sent to the Arduino, and the Arduino Micro chip doesn't have an additional chip for processing incoming Serial bytes, so I would say that it is possibly the cause of losing the connection, but is still quite wierd. I have an Arduino Micro chip here, and I can't seem to reproduce the disconnection, so it could be unrelated or something in the driver code I'm not seeing.On the topic of ArduinoRead, I can almost guarantee that the problem is because too many requests are being sent to the Arduino, and Mathematica reads the serial buffer too fast, so it doesn't get a chance to become populated. As you mentioned a check for the length of serialReadBuffer[] would probably solve at least some of the problems, but the other problem is that because so many requests are being sent into the serial buffer on the Arduino, the entirety of the buffer can be overwritten in the time it takes to process an analogRead, as analogRead's are somewhat slow on the Arduino, mainly because the buffer is only 64 bytes. This is why my error values of "qqqq" are showing up, because the original bytes were overwritten, and now there are new bytes there that cause undefined behavior.If you are curious, you can look into increasing the size of the Serial buffer on the arduino here. That refers to modifying the builtin arduino library that defines the size of the serial buffer to 256 in that case for the Arduino Uno, but it can be easily modified for a Micro. That will probably help out quite a bit with the "qqqq" showing up, but my main recommendation is to put a Pause in between the DeviceReads, something not less than 1/2000 seconds I think should be enough.Ian
1 year ago
 Thank you Ian for looking into my problem. With a pause the error rate is significantly lower (almost perfect). I find that the error which I reported appears ALWAYS, when the Arduino Serial Monitor pop-up window is open at the time the Mathematica program is running, but this is not surprising. I have a second question though: Why do commands likeDeviceConfigure[arduinoObject,<|"A5"->"analogInput"|>] or DeviceConfigure[arduinoObject,<|6->"digitalInput"|>] trigger a continuously repeated transmission of the serial buffer from the Arduino Micro, rather than enable a single transmission once a DeviceRead statement is sent ?Thanking in advance,Hanspeter
1 year ago
 I'm glad that helped! And the reasoning I had for putting the device into an always reporting mode is that once one read is triggered, it's likely that more reads are going to be expected, so that was a way to help performance with something like Dynamic[DeviceRead["Arduino",2]] or something similar. In the version of the driver that will be released with Mathematica soon, this has changed so that one request provides one response, rather than putting the Arduino into an always reporting cycle.
1 year ago
 Timothy Stasevich 1 Vote Very nice! I'd like to be able to create a GUI with mathematica to control our microscope lasers via the Arduino. This seems like a very good start. Just tested and it works on my system (Windows). However, any thoughts on how fast this can pulse the LED? I tried setting the time delay to 1 ms and it seemed a bit off. How fast can we pulse?
2 years ago
 Ian Johnson 1 Vote Well, when I built the drivers I used 19200 as the baud rate, which is quite slow for serious applications. It is definitely possible to increase the speed (in both the Mathematica driver file and the Arduino firmware) to 115200, which is the fastest I have seen with an Arduino. However, I would be surprised if it would ever be possible to have something akin to Do[(DeviceWrite[aruidnoObject,<|pinNumber->1|>];Pause[1/10000];DeviceWrite[arduinoObject,<|pinNumber->0|>;Pause[1/10000]),{5}] work faster than about 1 KHz, because the front end combined with all of the necessary Mathematica functions to write over serial, etc. add up pretty quickly and the timing becomes problematic.Instead, I am currently developing a new functionality (using DeviceExecute), which would basically send one command over Serial to the Arduino, which would then cause the Arduino to run some pre-uploaded code (in C/C++), at which point there would be absolutely no problem doing things on the order of microseconds.This is not yet available because what I plan to do is be able to write whatever commands you want the Arduino to be able to execute in Mathemetica using Symbolic C, then have Mathematica automatically update the firmware file, and then automatically upload the firmware to the chip, all without ever leaving Mathematica. I haven't quite gotten that far, but the most difficult task to me would seem to be the Symbolic C portion of it and the updating of the firmware, as I have accomplished just about all the other tasks. Also, if you would like to change the baud rate on your drivers, you can do so by opening up the package in Mathematica, and right underneath Begin["Private"] is the definition for open[], which opens the Serial Port. Here, you can change the option from "BaudRate"->19200 to "BaudRate"->115200.Changing the Baudrate in the Arduino firmware file, you can open up the file, and down a ways is the void Setup() loop. The second to last line here is Serial.begin(19200). Just change it to Serial.begin(115200), and re-upload it and you should be good to go. I tried this, and it seemed to have about 1 KHz frequency, but stopped flashing after a second or two and stayed on, so it's possible that the Arduino runs it fine, but after it finishes Mathematica takes a couple of seconds to catch up.
2 years ago
 Marco Thiel 1 Vote Hi,this might be interesting in terms of Arduino's speed:http://www.dustynrobots.com/robotics/arduino-data-logging-and-speed-test/http://arduino.cc/en/Reference/AnalogReadThis one is the fastest I could find:http://forums.adafruit.com/viewtopic.php?f=31&t=30557which claims about 100kHz sampling rate. And inhttp://community.wolfram.com/groups/-/m/t/250923I had trouble getting even close to that. The decay can happen very fast and I need a sampling rate that is as high as possible.Cheers,Marco
2 years ago
 Ian Johnson 1 Vote While I'm not familiar with how the Gieger counter mentioned in your post works, it looks like it is doing one of two things. Either one, you send it a command over serial, it changes something, then waits for another command; or two you send it a command over serial, then it executes some type of small set of commands on its own processor, then returns the result.As I mentioned above, the first method of having Mathematica and your computer do the legwork in determining what command to run when is very ineffective at high frequencies. Instead, having the Atmel chip on the Arduino execute things is much more effective, as there is no other processes to slow it down, i.e. serial communication, OS processes, etc. If one needs high frequencies I would say that having the Atmel chip on the Arduino execute those commands is the way to go. I would also say that any faster than the theoretical limit mentioned on the documentation page for analogRead would probably require special hardware, and then another driver developed for it, but it is certainly possible to have the Arduino execute some command at that frequency, then pump out the result (or an array of the results) over serial would be the best way to move forward.In short, serial communication and Mathematica are definitely the bottlenecks for doing things quickly.
2 years ago
 Marco Thiel 1 Vote Hi Ian,well, the Geiger counter is actually rather simple. Like the Arduino it has an AMTEL chip, which in principle can be programmed. Whenever it detects a decay it sends a zero or a one to the serial, depending on whether the last inter-decay interval was shorter or longer than the previous one. It can send the 0/1 rather fast. Mathematica listens via the serial. Sometimes, the inter decay event time is longer then 10 s and Mathematica times out; that's easy to detect and can be mended in post-processing. The problem is when two events happen in very quick succession. In some projects, I actually do what you say and Either one, you send it a command over serial, it changes something, then waits for another command; or two you send it a command over serial, then it executes some type of small set of commands on its own processor, then returns the result. but in this case I just listen with Mathematica. There is no two way communication, I believe. When I used SerialIO I got to an update interval of 0.002 which was slightly better than the one I choose in MMA10, at 0.01 - everything else being the same. Mathematica is used to determine the times at which the event has (approximately) happened, up to a precision of the sampling interval.With a couple of students, we also did try to read a simple Potentiometer as fast as we could - one way communication from the Arduino to MMA10. Do you know what the shortest UpdateInterval/highest ScheduledTask frequency is that MMA10 can handle?Cheers,Marco
2 years ago
 Ian Johnson 1 Vote I am not familiar enough with the inner workings of Mathematica to know exactly what the upper limit is, but I do know that operations handling files, like OpenWrite and Write work much faster than higher level functions. You can see Arnoud's response here for some information on how to do that with a Raspberry Pi, but I'm not sure that would help you if you plan on using a normal computer (i.e. Mac or PC).What you could try is to have an Arduino connected to your Geiger counter, then that Arduino would be connected to Mathematica. This would require a library known as Software Serial to have the Arduino be able to communicate with two UART (serial devices) simultaneously. Although, if as you said the Geiger counter only sends information, you could have just the receive pin of the Arduino connected to the Geiger Counter, then the transmit pin going to the Computer. Obviously this would require some hardware modification such that you take care of the UART to USB handling without using the onboard ATmega32u4 as the serial to USB converter. Anyways, with all of that, you can have code on the Arduino listening for the 1's and 0's from the Geiger counter and be able to handle those at just about whatever frequency you like, then once the Arduino determines, hey something changed that is important, it can then send off a command to the computer and you can either send the raw data trough the Arduino to the computer or have the Arduino do some processing on it (as I said I am not familiar with this device, so I don't know what exactly that data looks like or if the Arduino has the capabilities to process it properly).
2 years ago
 Marco Thiel 1 Vote Hi Ian,I am not sure where you are currently sitting but Arnoud has such a counter. Anyway, your post is brilliant and I will try to put your code to use in some of my projects as well. In one of your earlier replies you said that you could go up to 1kHz. Did you actually get there? If you manage a bidirectional communication at that speed that would be quite good. Cheers, MarcoPS: By the way arduinoObject = DeviceOpen["Serial", {Quiet[FileNames["tty.usb*", {"/dev"}, Infinity]][[1]], "BaudRate" -> 9600}] seems to work fine on a Mac and you don't have to actually look anything up in the /dev directory. I found that useful.
2 years ago
 Ian Johnson 1 Vote I work remotely from Minnesota, but anyways I did somewhat manage to get to 1KHz, but I can't confirm that it was 1KHz, as I don't have an oscilloscope handy, but it appeared to be flickering so fast that it almost seemed steady. I accomplished that by just using Do[( DeviceWrite[arduinoObject,<|pinNumber->1|; Pause[1/2000]; DeviceWrite[arduinoObject,<|pinNumber->0]; Pause[1/2000]), {1000}] However when I wrapped that in Timing, it took about seven seconds to evaluate, and the light would flicker as I mentioned for about twoish seconds (again, don't have an oscilloscope handy, so can't confirm the time), then it would flash on and off for about two more seconds, then after that it would stay steady on either on or off, depending on which time I ran it, i.e. sometimes it would end with being on, sometimes it would end with being off. So that leads me to suspect that Mathematica is either doing stuff after sending the commands that takes seven seconds, or that it is getting "confused" with all the serial output such that it doesn't output correctly, on top of being slower than suspected. Also, thanks for the tip on Mac serial discovery, I may have to integrate that into the FindDevice functionality!Ian
2 years ago
 Hi there,I just wonder whether the link to the firmware has been disabled on purpose or whether it's just me who cannot access it.Cheers,Marco
1 year ago
 I reattached the file as an attachment to the post. The file had a limited amount of time it was hosted on the server, and I had thought that the official driver would be in the software by the time it had expired, but unfortunately not. It will be a little bit longer before the official driver (which was derived from this work) will be integrated into the product.Ian
1 year ago
 Dear Ian,thanks a lot! That's great. Fantastic work!Thanks,Marco
1 year ago
 Hello Ian, thank you for this approach!.Can I use this with my Arduino DUE board, using the 32bit ARM cortex M3 CPU Atmel AtSam3X8E ? In Arduino, you have to let it download the Board via Boards Manager. DUE has a USB to serial bridge with Atmel ARM ATmega16U2 on board, having its own bootloader. The Sam3X8E also has a built-in USB device. And several Hardware Serial Ports, normally the standard one attached to Serial of 32U4 to get the Program in the chip with normal bootloader and bossac programmer.I am looking forward for this, because combined with coding from mathematica, one could do an oscilloscope with the 12bit 2MHz 2 ADC's it employs. DAC is also there. And 12 PWMs, etc...Could you use OpenOCD.org's Debugging features to inject code "live"? Thanks againAndi
1 year ago
1 year ago
 Hello Ian, unfortunately my ideas are way beyond the skill I reacht up to now. I will try to hook up an arduino micro or nano first, 32u4 / 328P. Then the due...The temptation is that DUE is not so limited in pin count as are the small arduinos. And the limitation of 10bit DAC, beiing noisy as it is, diminishes together with 4kHz usable sample rate the use as aquisition device. Due would probably stand out there, so I will try.For you I found a link that mentiones M3 simulation model as open source, so you could swallow it in Mathematica, and it has morphing technology...YoursAndi
1 year ago
 This is a great subject. But a bit advance for new users. May you explain what is the "Arduino firmware" and ho w it differs from a "sketch"?Also , explain what is a Wolfram package and how it is different from running a standard notebook?Thank you!
1 year ago
 Hi Jose,The Arduino firmware as I called it in the post is the same thing as a sketch. They are the same.A Wolfram Language package is a file that contains Wolfram Language code and definitions that is meant to be portable. It is intended that packages contain useful definitions that is to be used multiple times. It is similar to a library file in other programming languages. You load packages with either the function Get or the function Needs. In my post, << is a shorthand notation for Get.Ian
1 year ago
 Programming the World with Arduino and Mathematica In[2]:= arduinoObject = DeviceOpen["Arduino", "COM3"] Out[2]= DeviceObject[{"Arduino", 1}] Where "COM4" is my serial port, replace that with whatever port your Arduino is attached on. Now for some basic device control, we can use In[15]:= DeviceWrite[arduinoObject, <|11 -> "HIGH"|>] Out[15]= <|11 -> "HIGH"|> In[9]:= <|1 -> 1|> Out[9]= <|1 -> 1|> Also tested the LED with the insire 3V power supplied to confirm the LED is ok.
1 year ago
 I also use <|11 -> 1> but dod not work either.
1 year ago
 Hi again Jose,So what exactly is not working for you? Have you uploaded the sketch to your Arduino with the Arduino software?Ian
1 year ago
1 year ago
 And you know that your serial port is "COM3"?
1 year ago
 sketch to verify everything is ok with the board. At what speed is the Mathematica download running? Does this matter? My Device manager states that arduino receives at 9600 buds.