Update 12-8-2013
In this update, I demonstrate that not only is the RPi a good platform for introducing and using the MathLink API
, but it is likely necessary giving the significant speed limitations on the RPi. I include working c-code since there are presently few examples of Mathematica/MathLink/RPi implementation.
As of now, it appears that there needs to be some back-end development of the DeviceWrite
and DeviceRead
commands in order to use them in any practical, custom GPIO data acquisition platform on the Raspberry Pi. Fortunately, significant improvements in the read/write cycling can be made through the help of MathLink-enabled c-programming and a GPIO interface for the Raspberry Pi. Using this library, I was able to generate some simple functions of the type:
#include <wiringPi.h>
#include "mathlink.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int pinread(int pin);
int pinhi(int pin);
int pinlo(int pin);
int pincycle(int pin, int num);
void multiread(int pin, int num);
int main(int argc, char *argv[]){
wiringPiSetupGpio();
return MLMain(argc, argv);
}
int pinread(int pin) {
pinMode(pin, INPUT);
return digitalRead(pin);
}
int pinhi(int pin) {
pinMode(pin, OUTPUT);
digitalWrite(pin,1);
return 0;
}
int pinlo(int pin) {
pinMode(pin, OUTPUT);
digitalWrite(pin,0);
return 0;
}
int pincycle(int pin, int num) {
int i;
for (i=0;i<num;i++) {
pinhi(pin);
pinlo(pin);
}
return 0;
}
void multiread(int pin, int num) {
int i;
int val[num];
pinMode(pin, INPUT);
for (i=0;i<num;i++) {
val[i]=digitalRead(pin);
}
MLPutInteger32List(stdlink, val, num);
return ;
}
Calling pinread through a Mathematica structure, e.g. Table[pinRead[pinno],{1000}]
results in GPIO cycling on the order of 3 kHz, which is a marked improvement over the tens of hz I obtained with DeviceRead
. Still better is to offload the entire cycling process to the c-code, which is what I do with multiread()
. This change in GPIO interaction results in cycling between 1 and 3 MHz, which is about what one expects for the RPi.
Previous thoughts
Here's my latest advance, which is a solution of sorts; however I suspect there are better answers to be found. This circuit works by first using a GPIO low signal to discharge the capacitor. The time it takes for the capacitor to recharge depends on the resistance of the photocell and is monitored by continuously reading the GPIO pin until it is high. The assumption here is that the successive read commands happen at fixed and rapid time intervals, which is where I think the problem is.
As frequent visitors to M.SE know, functional programming is almost always faster than procedural programming, so the first step is to replace the While
in my original code with something faster. The following is one way to do that:
lightMeasure[] := Module[{pin = 23},DeviceWrite["GPIO", pin -> 0];
(pin /. Table[DeviceRead["GPIO", pin], {50}]) // Mean // N]
I made two changes from the original circuit: first, I changed the capacitor to 33 μF which increases the time constant and helps with the current reality that DeviceWrite
and DeviceRead
are not all that fast. The second change was to replace my photocell with a fixed resistor to make sure that the fluctuations I was observing were due to the programming and not the electronics. With 22 kOhm and 220 kOhm resistors, I obtained very consistent results with lightMeasure
(~ 10% relative error). I could make a simple data viewer with an intentionally spinning Manipulate
:
Manipulate[
If[measure, AppendTo[x, lightMeasure[]]];
ListLinePlot[x],
{measure, {True, False}}, Initialization -> (x = {lightMeasure[]};)]
Below is a sample output of the light in my office with me putting my hand or a small cap over the sensor.
There's still much to be done, but this is a decent first step (and as far as I know the first example of home built RPi-Wolfram data acquisition). The next step is to improve the time it takes to make the measurement (about 1 s with this setup).
time.sleep(0.1)
in your Mathematica code --Pause @ .1
? $\endgroup$Pause
afterDeviceWrite
does not keep the GPIO output low as it does in the python code. $\endgroup$