Go Down

Topic: Pd OSC ints > Processing > Arduino > shif (Read 2548 times) previous topic - next topic

Nicktriller

Jan 18, 2011, 01:16 pm Last Edit: Jan 18, 2011, 01:20 pm by NickJPM Reason: 1
Hi peeps,

As my first ever forum post I find myself begging for help. I'm not much of a coder and I somehow have talked myself into creating a project that takes sound data from pd and passes it over tcp ip to a processing sketch and then to an arduino. The idea is to influence LED colours through sound and pass the LED's through an old school video feedback loop in an immersion dome.

I'm using the osc external for pd and am getting data into processing fine with the following code:

import oscP5.*;
import netP5.*;
import processing.serial.*;

OscP5 oscP5;
NetAddress myRemoteLocation;
int pitchInt;
Serial myPort;

void setup() {
oscP5 = new OscP5(this,9997);
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 115200);
myRemoteLocation = new NetAddress("127.0.0.1",9997);
}

void draw(){
 try {
 myPort.write(pitchInt);
 int ardCallback = myPort.read();
 println(ardCallback);
} catch (Exception e) {
 //do anything you want to handle the exception
 println("Unable to parse int");
}
}


/* incoming osc message are forwarded to the oscEvent method. */
void oscEvent(OscMessage theOscMessage) {
 pitchInt = theOscMessage.get(0).intValue();
}



I'm then trying to write the values over serial to my arduino using a premade shiftbrite sketch I've found online:

/* Ports and Pins

Direct port access is much faster than digitalWrite.
You must match the correct port and pin as shown in the table below.

Arduino Pin        Port        Pin
13 (SCK)           PORTB       5
12 (MISO)          PORTB       4
11 (MOSI)          PORTB       3
10 (SS)            PORTB       2
9                  PORTB       1
8                  PORTB       0
7                  PORTD       7
6                  PORTD       6
5                  PORTD       5
4                  PORTD       4
3                  PORTD       3
2                  PORTD       2
1 (TX)             PORTD       1
0 (RX)             PORTD       0
A5 (Analog)        PORTC       5
A4 (Analog)        PORTC       4
A3 (Analog)        PORTC       3
A2 (Analog)        PORTC       2
A1 (Analog)        PORTC       1
A0 (Analog)        PORTC       0

*/

// Defines for use with Arduino functions
#define clockpin   13 // CL
#define enablepin  10 // BL
#define latchpin    9 // XL
#define datapin    11 // SI

// Defines for direct port access
#define CLKPORT PORTB
#define ENAPORT PORTB
#define LATPORT PORTB
#define DATPORT PORTB
#define CLKPIN  5
#define ENAPIN  2
#define LATPIN  1
#define DATPIN  3

// Variables for communication
unsigned long SB_CommandPacket;
int SB_CommandMode;
int SB_BlueCommand;
int SB_RedCommand;
int SB_GreenCommand;

// Define number of ShiftBrite modules
#define NumLEDs 1

// Create LED value storage array
int LEDChannels[NumLEDs][3] = {0};

// Set pins to outputs and initial states
void setup() {
 Serial.begin(115200);
 pinMode(datapin, OUTPUT);
 pinMode(latchpin, OUTPUT);
 pinMode(enablepin, OUTPUT);
 pinMode(clockpin, OUTPUT);
 digitalWrite(latchpin, LOW);
 digitalWrite(enablepin, LOW);
 SPCR = (1<<SPE)|(1<<MSTR)|(0<<SPR1)|(0<<SPR0);
}

// Load values into SPI register
void SB_SendPacket() {

   if (SB_CommandMode == B01) {
    SB_RedCommand = 127;
    SB_GreenCommand = 110;
    SB_BlueCommand = 110;
   }

   SPDR = SB_CommandMode << 6 | SB_BlueCommand>>4;
   while(!(SPSR & (1<<SPIF)));
   SPDR = SB_BlueCommand<<4 | SB_RedCommand>>6;
   while(!(SPSR & (1<<SPIF)));
   SPDR = SB_RedCommand << 2 | SB_GreenCommand>>8;
   while(!(SPSR & (1<<SPIF)));
   SPDR = SB_GreenCommand;
   while(!(SPSR & (1<<SPIF)));

}

// Latch values into PWM registers
void SB_Latch() {

 delayMicroseconds(1);
 LATPORT += (1 << LATPIN);
 //ENAPORT += (1 << ENAPIN);
 delayMicroseconds(1);
 //ENAPORT &= ~(1 << ENAPIN);
 LATPORT &= ~(1 << LATPIN);

}

// Send all array values to chain
void WriteLEDArray() {

 SB_CommandMode = B00; // Write to PWM control registers

 for (int i = 0; i<NumLEDs; i++) {
   SB_RedCommand = LEDChannels
  • & 1023;
       SB_GreenCommand = LEDChannels[1] & 1023;
       SB_BlueCommand = LEDChannels[2] & 1023;
       SB_SendPacket();
     }

     SB_Latch();

     SB_CommandMode = B01; // Write to current control registers

     for (int z = 0; z < NumLEDs; z++) SB_SendPacket();  

     SB_Latch();

    }

    // Fade between two colors at specified interval
    void fadeall(int rate, int fromred, int fromgreen, int fromblue, int tored, int togreen, int toblue) {

    for (int i = 0; i < 33; i++) {

        for (int j1 = 0; j1 < NumLEDs; j1++) {
          LEDChannels[j1][0] = (fromred * (32 - i) + tored * i)/32;
          LEDChannels[j1][1] = (fromgreen * (32 - i) + togreen * i)/32;
          LEDChannels[j1][2] = (fromblue * (32 - i) + toblue * i)/32;
        }

       WriteLEDArray();
       delay(rate);

      }  
    }

    void loop() {
    while (Serial.available() > 0) {
     int inByte = Serial.read();
     Serial.write(inByte);
     inByte = inByte *5;
     if (inByte > 0){
       fadeall(60,0,500,0,0,0,1023);
       delay(inByte);
       fadeall(60,0,0,1023,0,0,0);  
       delay(inByte);
     }
     else {
       
     }
    }
    }




    Due to the nature of this setup i'm finding it really hard to debug as the serial port is being used constantly. As my processing sketch is printing to the port I am having to process it on the arduino and then re-write it to the port and print it from processing :s

    Can anyone identify any silly mistakes I am making?

    Any help would be greatly appreciated :)


    Nick



PaulS

Quote
Can anyone identify any silly mistakes I am making?

Besides not telling us what problem(s) you are having, if any?

Quote
Due to the nature of this setup i'm finding it really hard to debug as the serial port is being used constantly. As my processing sketch is printing to the port I am having to process it on the arduino and then re-write it to the port and print it from processing :s

But, that works.

You could get a LCD to attach to the Arduino, and write debug data there...

You could avoid the issues with debugging by breaking the programming up into smaller pieces. Get Processing and Arduino to send data back and forth reliably. Then, extend the Arduino sketch to do something with the data. Then, extend the Processing sketch to send meaningful data.

Extend one sketch at a time. Then, any issues are with the new code...

Nicktriller

Hi Paul,

Thanks for the quick reply... basically the inByte I am receiving in arduino doesn't seem to work in the conditional statements or as an integer parameter for the other functions.

Is the arduino code for reading incoming data correct?

AWOL

#3
Jan 18, 2011, 01:49 pm Last Edit: Jan 18, 2011, 02:14 pm by AWOL Reason: 1
What about it 'doesn't seem to work'?
Could it be that you're overlowing your serial buffer because of all those delays?
Have you tried send commands singly, using the serial monitor instead of your Processing sketch?
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Nicktriller

#4
Jan 18, 2011, 02:31 pm Last Edit: Jan 18, 2011, 02:32 pm by NickJPM Reason: 1
Sending commands through the monitor works fine... What would be the best logical way of reading serial data in real time and then writing the incoming data on the fly?

Is anyone aware of how arduino interprets the port.write(int); method in processing... ie does it recognise the byte as an integer or do I have to convert it with atoi? Processing seems to do the conversion for me which I think is why I'm getting different results from the arduino?

Thanks again for the advice so far!

PaulS

Quote
Is anyone aware of how arduino interprets the port.write(int); method in processing... ie does it recognise the byte as an integer or do I have to convert it with atoi?

Processing sends data as strings. You need, on the Arduino side, to collect all the characters for a value into an array, and pass that (NULL terminated) array to atoi to reconstruct the integer value.

Nicktriller

Hi Paul,

Thanks again for the point in the right direction! I think I am almost there... trying to adapt a bit of AWOL's code from another post to mine but it seems to be concatenating values through the serial monitor. if i type a 1 first its fine... if i then type 33 the next number is 13... then a 3 will pop up. Any ideas on where I'm going wrong?

Code:

char val [10];
int index = 0;

void loop() {
 long now = millis();
 if (Serial.available() > 0) {
   inByte = Serial.read();
   // if (now % 1000){
   val[index++] = inByte;
   val[index] = '\0';
   int a = atoi(val);
   Serial.println(a);
     if (a > 0 && a < 60){
       fadeall(50,1023,0,0,0,0,1023); //from red to blue
     }
     else if (a > 60){
       fadeall(50,0,0,1023,1023,0,0); //from blue to red
     }
     else {
     }
     if (inByte <= '0' || inByte >= '9') {
       index = 0;
     }
   a = 0;
   //Serial.flush();
   //  }
 }
}

PaulS

Quote
if i type a 1 first its fine... if i then type 33 the next number is 13... then a 3 will pop up. Any ideas on where I'm going wrong?

You need some kind of end of packet marker. The Arduino needs to read all serial data available, on every pass through loop, not just one byte.

In addition, the Arduino should not be calling atoi until the end of packet marker arrives. When the end of packet marker arrives, do stuff with the serial data, and then re-initialize everything in preparation for the next packet.

macegr

I suggest the SSC "protocol". It's probably the absolute simplest possible, and seems to work well. A packet of data always starts with byte value of 255. All your other data must be less than 255; sacrificing that last bit seems worth the simplicity.

The processing logic is really easy. Look at the bytes as they come in; if you see 255, then reset an index counter and maybe set a flag that you're getting new data. From there, you can either wait for a known number of bytes, time out, or send another 255 to indicate end of transmission. You can put whatever you want in between. Set the first byte as a function type, or channel designator, etc.
Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

Nicktriller

#9
Jan 19, 2011, 08:57 pm Last Edit: Jan 20, 2011, 06:47 pm by NickJPM Reason: 1
Hi guys,

Firstly, Garet thank you for the SSC suggestion, I think that will do nicely as long as I can manipulate the data I'm receiving before passing it through to one of your shiftbrites (ie multiply the value by 100).

I have tried to implement the ssc protocol and can feel I am really close but cannot see where I am going wrong. Whenever I send for example "226" in the serial monitor I get the following:

colour = -1
I received: ÿ
this has an ASCII value of -1
Serial reset to: 0
colour = 54
I received: 6
this has an ASCII value of 54
Serial reset to: 0

So it's only seeing the 3rd byte I'm sending (I think this is supposed to happen?)

Arduino Code:

byte s = 0;
int colour = 0;
int SerialCount = 0;

void loop() {
 long now = millis();

 while (Serial.available() > 0) {
   byte s = Serial.read(); //1st byte received of message will be 255
   if (s == 255) {
     SerialCount = 0;
     byte s = Serial.read();
   }
   else if (s != 255 && SerialCount == 0) { //now read the colour value (expected 0-9)
     colour = Serial.read();
     SerialCount++;
     Serial.print("colour = ");
     //colour = colour * 100; //multiply the colour back up to usable number
     Serial.println(colour);

     fadeall(50,1023,0,0,1023,0,colour); //from red to a purple of somesort
     Serial.print("I received: ");
     Serial.println(colour, BYTE); //what byte value did I receive
     Serial.print("this has an ASCII value of ");
     Serial.println(colour,DEC); //what is this in ASCII format
   }
   if (SerialCount > 0 && SerialCount < 2){
   SerialCount = 0; //reset the counter
   }
   Serial.println("Serial reset to: ");
   Serial.print(SerialCount); //confirm it's been reset
 }
}

I did post something up earlier but after reading it it was a bit humiliating on my part! Unfortunately I can't seem to get over this last hurdle. Everyone's help is greatly appreciated and tbh I wouldn't have gotten this far without it :D I am trying to multiply that number by 100 but it always returns -100.

Nick

Go Up