Here’s a little Expect script for getting a control stream into Pure Data, in my case from a butchered Genius serial mouse that I wrote an interrupt-driven Arduino driver for. The driver sends a “+
” or “-
” down the serial line each time the optical rotary encoder in the mouse guts moves a click. This assumes the Arduino is connected on /dev/ttyUSB0
(e.g. on Linux). Use a [netreceive 3000]
(or whatever port you like) in Pure Data to receive.
Note: this only uses one mouse axis, requiring two interrupts. Apparntley the Arduino Mega has six interrupt lines externally available, so I'll be adding another axis of control soon.
#!/usr/bin/expect
# Take Arduino mouse '+'/'-' stream and convert into Pure Data FUDI format, without buffering.
# To run:
# expect mouse-pd.expect | pdsend 3000
# TODO: this should probably use Expect's stty command to set the serial port up to match the Arduino program.
eval spawn -noecho cat /dev/ttyUSB0
log_user 0
while (true) {
expect {
+ {send_user "1;\n"}
-- {-} {send_user -- "-1;\n"}
}
}
Here’s the Arduino code:
// Simple interrupt-driven driver for quadrature encoder input (e.g. from a disassembled photoelectric ball mouse).
// Many Arduino boards provide only two interrupts, I believe: INT0 (on pin 2) and INT1 (on pin 3):
const int intA = 0, intAPin = 2;
const int intB = 1, intBPin = 3;
volatile int A = 0, B = 0; // For storing the pin states for future reference to determine rotation direction
int A_Prev = 0, B_Prev = 0; // Should these be volatile, too?
void setup()
{
// Configure digital input pins for interrupt-driven timing:
pinMode(intAPin, INPUT); digitalWrite(intAPin, LOW);
pinMode(intBPin, INPUT); digitalWrite(intBPin, LOW);
Serial.begin(115200);
// Read initial state of the pins:
A_Prev = digitalRead(intAPin);
B_Prev = digitalRead(intBPin);
A = digitalRead(intAPin);
B = digitalRead(intBPin);
attachInterrupt(intA, changeA, CHANGE);
attachInterrupt(intB, changeB, CHANGE);
}
void changeA()
{
A = !A;
output();
A_Prev = A;
}
void changeB()
{
B = !B;
output();
B_Prev = B;
}
void output()
{
if (A == B_Prev)
Serial.print("+");
else if (B == A_Prev)
Serial.print("-");
else
Serial.print('?');
}
void loop() {}
Microcontroller programming is fun, BTW! I’d never written a driver or an interrupt handler until two days ago.