max patch to control sound with an arduino encoder wheel question ..

Apr 5, 2010 at 4:15pm

max patch to control sound with an arduino encoder wheel question ..

hi !

first i have to say i am quite new to all this !
i am working on a sound installation where i basically want to
control the pitch or the movement of a sound in a sourround setup
with an encoder wheel that is connected to an arduino board sending
a counting signal to max.

heres a bit more info about the encoder wheel setup :

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1263157149/10

what allready works is to get the signal of the encoder wheel
(http://www.pololu.com/catalog/product/1217)
into max.

#49556
Apr 5, 2010 at 4:21pm

oops, sorry i posted to soon ..
anyway,
i somehow have to translate the on/off signal of the wheel encoder to a
signal which i can use to control the movement of the position of
a sound in a sourround setup with 4 speakers.

lets say, for example:
one turn of the wheel is one turn arround of a sound
in the 4 speakers.
sorry, i hope this is clear, my english is not the best.

i am thankful for any help !!
all the best
chris

#178085
Apr 10, 2010 at 6:49am

no ideas ? just for a start …..

#178086
Apr 10, 2010 at 10:29am

How important is the use of an encoder wheel? Never used one in an Arduino setup but it seems a little overly complex (to me) for what you wish to achieve. I know data wheels are continuous, so identifying a default centre position might be tricky to code; I would use a potentiometer. But i’m lazy and my programming skill might be less than yours.

#178087
Apr 12, 2010 at 9:27pm

hi,
thanks for answering.
i am sure your programming skills are way better than mine, because mine are just
not there… i am really still a beginner .. :-)
what kind of potentiometer do you mean, could you send me a link ?
any ideas what kind of objects i could use in max for my encoder wheel ?
greetings
cris

#178088
Apr 13, 2010 at 12:14pm

In order to get further help, you should probably post your Max patch to this forum so others can see it. I assume you have a custom Arduino program which is sending the analog sensor data to Max via the [serial] object. A potentiometer is a variable resistor, and there are many beginner tutorials on the Arduino website which feature this type of controller. It is much less complex than a data wheel, but doesn’t have 360deg continuous rotation – it has approx 270deg, and has a minimum and maximum. But it could easily be implemented in a surround/multichannel diffusion patch.

http://arduino.cc/en/Tutorial/AnalogInput

Brendan

#178089
Apr 14, 2010 at 10:03am

hi brendan!
i cant really use a poti for this project as i need an ongoing signal from my sensor, turning arround and arround…an encoder wheel seems just perfect for this, as far as i know till now.
the wheel encoder is connected to the plattform, which is rotating.
in max i use a part of the maxuino patch.
my encoder is connected on analog pin 1 on arduino, i get a signal in my max patch.
but the number is always just 0 and 0.06.
i hope i can make that clear, my english is not the best.

so heres the code of the max patch, its really just trying out.
in the patch i am trying to pitch a sound file with the encoder wheel.
thanks you…cris

– Pasted Max Patch, click to expand. –
#178090
Apr 14, 2010 at 10:03am

oh, i forgot.
i got the standard firmdate loaded into arduino board.

#178091
Apr 14, 2010 at 10:15am

If you haven’t done so already, I would try to debug the Arduino program first. You do this by adding the following lines to your code, inside your loop function:

Serial.println (myVar);
delay (20);

where ‘myVar’ is the name of the variable you are using to read the encoder wheel values; upload it, run it, and press the Serial Monitor button in the Arduino window. This will tell you what values the controller is sending to the Arduino board.

#178092
Apr 14, 2010 at 11:51am

hi brendan,
this doesent seem to be correct:

/*==============================================================================
* LOOP()
*============================================================================*/
void loop()
Serial.println (5);
delay (20);
{
/* DIGITALREAD – as fast as possible, check for changes and output them to the
* FTDI buffer using Serial.print() */
checkDigitalInputs();
currentMillis = millis();
if(currentMillis > nextExecuteMillis) {
nextExecuteMillis = currentMillis + samplingInterval;
/* SERIALREAD – Serial.read() uses a 128 byte circular buffer, so handle
* all serialReads at once, i.e. empty the buffer */
while(Firmata.available())
Firmata.processInput();
/* SEND FTDI WRITE BUFFER – make sure that the FTDI buffer doesn’t go over
* 60 bytes. use a timer to sending an event character every 4 ms to
* trigger the buffer to dump. */

/* ANALOGREAD – right after the event character, do all of the
* analogReads(). These only need to be done every 4ms. */
for(analogPin=0;analogPin
if( analogInputsToReport & (1 < < analogPin) ) {
Firmata.sendAnalog(analogPin, analogRead(analogPin));

}
}
}
}

i mean where i put the code you posted ? where exactly i should write it ?

#178093
Apr 14, 2010 at 12:29pm

can you post your entire Arduino code? The Serial.println (5) should have a variable name inside the brackets, not ’5′; and Serial.println should appear after you have asked the program to read the inputs (after the first analogRead)

#178094
Apr 14, 2010 at 12:36pm

ps the issue may be that you are using ‘dense’ Firmata code, without really understanding what it’s doing; it looks a little tricky to me too. I don’t normally use code that ‘scans’ several inputs and parses them, which is what this code snippet looks like it’s doing. If you have time, look for Massimo Banzi’s or Brian Evans’ handbooks on Arduino coding.

http://www.lulu.com/items/volume_63/1108000/1108699/4/print/ARDUINO_NOTEBOOKv6.pdf

http://www.amazon.co.uk/Getting-Started-Arduino-Make-Projects/dp/0596155514/ref=sr_1_1?ie=UTF8&s=books&qid=1271248587&sr=8-1

Brendan

#178095
Apr 14, 2010 at 1:11pm

i ordered the book …. :-)
heres the whole arduino code,
but its just the standard firmdate from the examples,

/*
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

See file LICENSE.txt for further informations on licensing terms.

formatted using the GNU C formatting and indenting
*/

/*
* TODO: add Servo support using setPinModeCallback(pin, SERVO);
* TODO: use Program Control to load stored profiles from EEPROM
*/

#include
#include

/*==============================================================================
* GLOBAL VARIABLES
*============================================================================*/

/* analog inputs */
int analogInputsToReport = 0; // bitwise array to store pin reporting
int analogPin = 0; // counter for reading analog pins

/* digital pins */
byte reportPINs[TOTAL_PORTS]; // PIN == input port
byte previousPINs[TOTAL_PORTS]; // PIN == input port
byte pinStatus[TOTAL_DIGITAL_PINS]; // store pin status, default OUTPUT
byte portStatus[TOTAL_PORTS];

/* timer variables */
unsigned long currentMillis; // store the current value from millis()
unsigned long nextExecuteMillis; // for comparison with currentMillis
int samplingInterval = 19; // how often to run the main loop (in ms)

Servo servos[2]; // the servo library can control servos on pins 9 and 10 only

/*==============================================================================
* FUNCTIONS
*============================================================================*/

void outputPort(byte portNumber, byte portValue)
{
portValue = portValue &~ portStatus[portNumber];
if(previousPINs[portNumber] != portValue) {
Firmata.sendDigitalPort(portNumber, portValue);
previousPINs[portNumber] = portValue;
Firmata.sendDigitalPort(portNumber, portValue);
}
}

/* —————————————————————————–
* check all the active digital inputs for change of state, then add any events
* to the Serial output queue using Serial.print() */
void checkDigitalInputs(void)
{
byte i, tmp;
for(i=0; i < TOTAL_PORTS; i++) {
if(reportPINs[i]) {
switch(i) {
case 0:
outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
break;
case 1:
outputPort(1, PINB);
break;
case ANALOG_PORT:
outputPort(ANALOG_PORT, PINC);
break;
}
}
}
}

// —————————————————————————–
/* sets the pin mode to the correct state and sets the relevant bits in the
* two bit-arrays that track Digital I/O and PWM status
*/
void setPinModeCallback(byte pin, int mode) {
byte port = 0;
byte offset = 0;

// TODO: abstract for different boards
if (pin < 8) {
port = 0;
offset = 0;
} else if (pin < 14) {
port = 1;
offset = 8;
} else if (pin < 22) {
port = 2;
offset = 14;
}

if(pin > 1) { // ignore RxTx (pins 0 and 1)
if(pin > 13)
reportAnalogCallback(pin – 14, mode == ANALOG ? 1 : 0); // turn on/off reporting
switch(mode) {
case ANALOG:
digitalWrite(pin, LOW); // disable internal pull-ups and fall thru to ‘case INPUT:’
case INPUT:
pinStatus[pin] = mode;
pinMode(pin, INPUT);
portStatus[port] = portStatus[port] &~ (1 < < (pin - offset));
break;
case OUTPUT:
digitalWrite(pin, LOW); // disable PWM and fall thru to ‘case PWM:’
case PWM:
pinStatus[pin] = mode;
pinMode(pin, OUTPUT);
portStatus[port] = portStatus[port] | (1 < < (pin - offset));
break;
case SERVO:
if((pin == 9 || pin == 10))
pinStatus[pin] = mode;
else
Firmata.sendString(“Servo only on pins 9 and 10″);
break;
case I2C:
pinStatus[pin] = mode;
Firmata.sendString(“I2C mode not yet supported”);
break;
default:
Firmata.sendString(“Unknown pin mode”); // TODO: put error msgs in EEPROM
}
// TODO: save status to EEPROM here, if changed
}
}

void analogWriteCallback(byte pin, int value)
{
switch(pinStatus[pin]) {
case SERVO:
if(pin == 9) servos[0].write(value);
if(pin == 10) servos[1].write(value);
break;
case PWM:
analogWrite(pin, value);
break;
}
}

void digitalWriteCallback(byte port, int value)
{
switch(port) {
case 0: // pins 2-7 (don’t change Rx/Tx, pins 0 and 1)
// 0xFF03 == B1111111100000011 0×03 == B00000011
PORTD = (value &~ 0xFF03) | (PORTD & 0×03);
break;
case 1: // pins 8-13 (14,15 are disabled for the crystal)
PORTB = (byte)value;
break;
case 2: // analog pins used as digital
byte pin;
byte pinModeMask;
for(pin=0; pin<8; pin++)
if(pinStatus[pin] == OUTPUT)
pinModeMask += 1 < < pin;
PORTC = (byte)value & pinModeMask;
break;
}
}

// —————————————————————————–
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
*/
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
//}
void reportAnalogCallback(byte pin, int value)
{
if(value == 0) {
analogInputsToReport = analogInputsToReport &~ (1 < < pin);
}
else { // everything but 0 enables reporting of that pin
analogInputsToReport = analogInputsToReport | (1 < < pin);
setPinModeCallback(pin, ANALOG);
}
// TODO: save status to EEPROM here, if changed
}

void reportDigitalCallback(byte port, int value)
{
reportPINs[port] = (byte)value;
if(port == ANALOG_PORT) // turn off analog reporting when used as digital
analogInputsToReport = 0;
}

/*==============================================================================
* SYSEX-BASED commands
*============================================================================*/

void sysexCallback(byte command, byte argc, byte *argv)
{
switch(command) {
case SERVO_CONFIG:
if(argc > 4) {
// these vars are here for clarity, they’ll optimized away by the compiler
byte pin = argv[0] – 9; // servos are pins 9 and 10, so offset for array
int minPulse = argv[1] + (argv[2] < < 7);
int maxPulse = argv[3] + (argv[4] < < 7);
servos[pin].attach(argv[0], minPulse, maxPulse);
// TODO does the Servo have to be detach()ed before reconfiguring?
setPinModeCallback(pin, SERVO);
}
break;
case SAMPLING_INTERVAL:
if (argc > 1)
samplingInterval = argv[0] + (argv[1] < < 7);
else
Firmata.sendString(“Not enough data”);
break;
}
}

/*==============================================================================
* SETUP()
*============================================================================*/
void setup()
{
byte i;

Firmata.setFirmwareVersion(2, 1);

Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
Firmata.attach(SET_PIN_MODE, setPinModeCallback);
Firmata.attach(START_SYSEX, sysexCallback);

portStatus[0] = B00000011; // ignore Tx/RX pins
portStatus[1] = B11000000; // ignore 14/15 pins
portStatus[2] = B00000000;

for(i=0; i
setPinModeCallback(i,OUTPUT);
}
// set all outputs to 0 to make sure internal pull-up resistors are off
PORTB = 0; // pins 8-15
PORTC = 0; // analog port
PORTD = 0; // pins 0-7

// TODO rethink the init, perhaps it should report analog on default
for(i=0; i
reportPINs[i] = false;
}
// TODO: load state from EEPROM here

/* send digital inputs here, if enabled, to set the initial state on the
* host computer, since once in the loop(), this firmware will only send
* digital data on change. */
if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
if(reportPINs[1]) outputPort(1, PINB);
if(reportPINs[ANALOG_PORT]) outputPort(ANALOG_PORT, PINC);

Firmata.begin(57600);
}

/*==============================================================================
* LOOP()
*============================================================================*/

void loop()
{
/* DIGITALREAD – as fast as possible, check for changes and output them to the
* FTDI buffer using Serial.print() */
checkDigitalInputs();
currentMillis = millis();
if(currentMillis > nextExecuteMillis) {
nextExecuteMillis = currentMillis + samplingInterval;
/* SERIALREAD – Serial.read() uses a 128 byte circular buffer, so handle
* all serialReads at once, i.e. empty the buffer */
while(Firmata.available())
Firmata.processInput();

/* SEND FTDI WRITE BUFFER – make sure that the FTDI buffer doesn’t go over
* 60 bytes. use a timer to sending an event character every 4 ms to
* trigger the buffer to dump. */

/* ANALOGREAD – right after the event character, do all of the
* analogReads(). These only need to be done every 4ms. */
for(analogPin=0;analogPin
if( analogInputsToReport & (1 < < analogPin) ) {
Firmata.sendAnalog(analogPin, analogRead(analogPin));

}
}

}
}

#178096
Apr 14, 2010 at 1:12pm

pps

also look here

http://www.sarc.qub.ac.uk/~MuSE/?p=138

Brendan

#178097
Apr 14, 2010 at 1:54pm

WOAH
that’s a lot of code! Far too dense for me I’m afraid; I can’t even see where the input from the data wheel is; is your wheel connected to analog or digital pins? And are you driving a servo motor as well with this program? Sorry I can’t be more help, but if you are getting strange input to Max from the [serial] object, the first place to start is the source of the data, and that’s the Arduino code. Is there an Arduino community forum that could help you?

#178098
Apr 14, 2010 at 3:21pm

i posted also in the arduino forum, unfortunatly no answer ..
i use analog pin #0.
thanks alot anyway, i ll try out the sarcuino thing.
all the best
chris

#178099
Apr 14, 2010 at 3:21pm

oh, i forgot.
a simple question.
i dont know how to open a patch as an object,
but i will try to google it ..

#178100
Apr 14, 2010 at 3:39pm

ok, the sarcuino code works fine for me as well as far i understand it ..
i get two numbers in the monitor of the maxpatch when i turn my encoder wheel
0 and 1022.
to me it looks like its just an on off signal.
is there any way i can count this signal in max.
lets say i turn the wheel a whole round and thats for example 25 on/offs ..
with which object i could count that.
i tried the counter object, but no success.
heres the arduino code i use now.

//*************************************************************************//
//* Sarcuino
//* Version: Beta 0.17
//* By Nicholas Ward, Michael Gurevich, Miguel Ortiz and Javier Jaimovich
//* Last modified by: Javier Jaimovich
//* Date: October 1st, 2009
//*************************************************************************//

#define SAMPLE_PERIOD 10 // Sample Period in Milliseconds
// N.B. The arduino can sample all pins at 500Hz
// This however causes serious burstiness
// Default is 100Hz (Same as HID devices)
// This avoids burstiness for most applications,
// Only change this if you really need a faster SR.
// Choose number of analog inputs to enable (0=OFF, 1=ON)
int setPins[] = {1, 1, 1, 1, 1, 1}; // Set no of analog pins e.g. {1, 0, 1, 1, 0, 0} enables pins 0, 2 and 3.
//*************–0–1–2–3–4–5

// FOR REALTIME CONTROL (lower latency and burstiness)
// To avoid data being buffered and sent in blocks of 4KB you should insure that
// ((ANALOG_INPUTS_ENABLED * 2) + 3) * ((1/SAMPLE_PERIOD)*1000) < 3875
// This is a limitation of the ftdi usb driver
// Further details and possible solutions can be found here
// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1170939903/15
// Default Sampling frequency is 100Hz (every 10ms)

//**************************************************************************//
//** Variables for data polling
//**
int analogPin, digitalPin; // Counters for poll loop
int analogData; // outgoing ADC value
byte x = 0; //byte to store digital status
byte y = 0; //same as above to store remaining digital pins status

//**************************************************************************//
//** Setup
//**
void setup() {
//setup serial baudrate for USB connection
Serial.begin(57600);

//enable digital pullups. All digital pins are set high
//and will only output change when connected to ground
for(digitalPin=2;digitalPin> 2; // Shift digital pin port D by 2 to avoid TX and RX pins
//(more info: http://www.arduino.cc/en/Reference/PortManipulation)
Serial.print(x, BYTE);
y = PINB; // Read remaining digital pins
Serial.print(y, BYTE);

for(analogPin=0; analogPin> 7, BYTE); // shift high bits into output byte
Serial.print(analogData % 128, BYTE); // mod by 128 for the small byte
}
else
{
Serial.print(0, BYTE); // Send 0 to output
Serial.print(0, BYTE); //
}
}

Serial.print(255, BYTE); // end of packet signifier

/* This bit of code was used for checking how long a full read takes
Serial.println(millis());
*/
}

and the code of the sarcuino max patch:

– Pasted Max Patch, click to expand. –
#178101
Apr 14, 2010 at 4:15pm

Can you send me a good quality photo or sketch of the physical setup, how your encoder is connected to the arduino.

email me at
brendan_mccloskey (at) yahoo (dot) ie

#178102
Apr 14, 2010 at 5:28pm

ok, sent it.

#178103

You must be logged in to reply to this topic.