Go Down

Topic: multiple variables from Max to Serial.read() (Read 5151 times) previous topic - next topic

eelke

Hello dear people,

First of all, I'm still not that advanced with the arduino language, but we're starting to get along. Last week I have been trying to think of a way to read multiple datastreams from max/msp into the arduino, based upon the same principle that is explained in here: first sending an identifier and then the value.

I tried doing this in a couple of ways, for instance with trying to figure out how to deal with arrays in arduino's language. Didn't really work out.
Now I just realized something while sitting outside in the sun, but I can't check it because my arduino isn't with me.

Is it true that Serial.read() reads and then erases the first int character it receives?

So to say, is it possible to get something like this to work?:

Code: [Select]
char id;
int val = 0;
int ledPin1 = 2;
int ledPin2 = 3;

void setup(){
  Serial.begin(9600);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

void loop(){
  //this would only check if there are 2 bytes available, would this work??
  if (Serial.available() > 1){
     //this sets the identifier and checks it
    id = Serial.read();
     if (id == 'X')){
        //this would be the next integer: the value
        val = Serial.read();  
        if (val == 0){
            digitalWrite(ledPin1, LOW);
        }
        else {
            digitalWrite(ledPin1, HIGH);
        }
     }
     else if (id == 'Y')){
        val = Serial.read();
        if (val == 0){
            digitalWrite(ledPin2, LOW);
        }
        else {
            digitalWrite(ledPin2, HIGH);
        }
     }
  }
}


This example code only plays with leds, but that is not important. It would for me work with servo's that get their destination value from max: the val variable in here. (Max, ironically, gets controlled from an old atari2600 joystick that I've attached to the arduino itself, but I need Max to play with the values so a direct control through arduino is impossible ;))

tof

I am workin on something similar.
2 suggestions:
A- Use "while (Serial.available() > 1)" instead of "if (Serial.available() > 1)" (or the buffer could overflow)
B- send ascii values for the integers instead of sending the raw numbers. This will give you more resolution and will ensure that "X" or "Y" do not get confused with the raw numbers.

You can check my work in progress on my Message lib here (it works): http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1149986873

From max you can send something like: "servo 5 1560" followed by a carriage return
The Message lib will split the message so you can interpret it as three elements: servo,5 (pin 5) and 1560 (ms)

Tom
Thomas Ouellet Fredericks

eelke

very nice! I'll try this out tomorrow and post my results, thanks :)

eelke

I couldn't really figure out what to do with all the codes you wrote, so I didnt get to use them.

However, I did get my code to work, partly. It seems there is a maximum of 3 units that I can use.
The following is my complete code. It is supposed to work completely, but it only does if I either comment out the //servo 0:, //servo 1:, //servo 2: or //led0: part. If I dont (comment one out) the patch goes crazy and sends a constant mess of variables to max.

Code: [Select]
// :::pins:::

//INPUT PINS
int UP = 2; //wit -joystick up
int RP = 3; //bruin -joystick right
int DP = 4; //blauw -joystick down
int LP = 5; //groen -joystick left
int KP = 6; //oranje -joystick button
int sP = 0; //slider
int rP = 9; //red button
int gP = 8; //green button

//OUTPUT PINS
int Se0 = 13; //servo0 etc
int Se1 = 7;
int Se2 = 10;
int led0 = 12;

// ::servo variables:::
int minPulse = 500;   // minimum positie
int maxPulse = 2500;  // maximum positie

int val0 = 0;
int val1 = 0;
int val2 = 0;
int val3 = 0;

int lastRead0;  // remember the previous input
int lastRead1;
int lastRead2;
int lastRead3;

int id;

// :::functions:::

void moveServo(int servoPin, int inputVal); //servo's bewegen
void maxSend(char letter, int pin); //knoppen doorsturen naar max
int simVal(int val1, int val2);

void setup() {

 pinMode(LP, INPUT);
 pinMode(UP, INPUT);
 pinMode(RP, INPUT);
 pinMode(DP, INPUT);
 pinMode(KP, INPUT);
 pinMode(rP, INPUT);
 pinMode(gP, INPUT);
 pinMode(Se0, OUTPUT);
 pinMode(Se1, OUTPUT);
 pinMode(Se2, OUTPUT);
 pinMode(led0, OUTPUT);

 moveServo(Se0, minPulse); // Startpositions
 moveServo(Se1, minPulse);
 moveServo(Se2, minPulse);
 
 digitalWrite(led0, HIGH);

 beginSerial(9600);
}

void loop() {
 //knoppen data doorgeven:::
 maxSend('L', LP);
 maxSend('R', RP);
 maxSend('D', DP);
 maxSend('U', UP);
 maxSend('K', KP);
 maxSend('g', gP);
 maxSend('r', rP);

 //data vanuit max:::
 while (Serial.available() > 1){
   id = Serial.read();
   Serial.println(id);
   //servo 0:
   if (id == 'W') {
     val0 = Serial.read();  
     if ( !(simVal(val0,lastRead0))) {
       moveServo( Se0, val0 );
     }
     lastRead0 = val0;
   }
   //servo 1:
   if (id == 'X') {
     val1 = Serial.read();  
     if ( !(simVal(val1,lastRead1))) {
       moveServo( Se1, val1 );
     }
     lastRead1 = val1;
   }
   //servo 2:
   if (id == 'Y') {
     val2 = Serial.read();  
     if ( !(simVal(val2,lastRead2))) {
       moveServo( Se2, val2 );
     }
     lastRead2 = val2;    
   }
   /*
   //led0:
   if (id == 'Z'){
     val3 = Serial.read();
     if ( !(simVal(val3,lastRead3))){
       if (val3 =='1'){
         digitalWrite(led0, HIGH);
       }
       else{
         digitalWrite(led0, LOW);
       }
     }
     lastRead3 = val3;
   }
   */
 }
 delay(10);
}

void moveServo( int servoPin, int inputVal){
 //moving the servo's to the selected value with microsecond function
 int val;
 val = (inputVal * 20) + 500;
 digitalWrite(servoPin, HIGH);  
 delayMicroseconds(val);      
 digitalWrite(servoPin, LOW);  
 //delay(20);
}

void maxSend(char letter, int pin){
 Serial.print(letter);
 Serial.println(digitalRead(pin));
}  

int simVal( int val1, int val2 ) {
 int difference;
 difference = val1 - val2;
 if (abs(difference) < 2){
   return 1;
 }
 else{
   return 0;
 }
}


Anyone got *any* idea what's going wrong here?

tof

Okay, had some time to check your code.
I think the main problem was that you are using two encodings of the serial data: ascii encoding and raw bytes (no encoding).

I also slimmed the size of the code and added a functin to make sure the servos get updated every 20 ms.
WARNING: the code is getting big, add one line of code and it might crack!

Here is the ARDUINO code:
Code: [Select]
// :::pins:::

//targetLoopDelay() vars
unsigned long previousmillis;
int delaytime;

//INPUT PINS
#define UP 2 //wit -joystick up
#define RP 3 //bruin -joystick right
#define DP 4 //blauw -joystick down
#define LP 5 //groen -joystick left
#define KP 6 //oranje -joystick button
//#define sP 0; //this is confusing... do not use digital pin 0 as it is tied to the serial line
#define rP 9 //red button
#define gP 8 //green button

//OUTPUT PINS
//int Se0 = 13; //I preffer to use pin 13 for a LED as it has an internal current resistor
#define  Se0 12        
#define  Se1 7
#define  Se2 10
//int led0 = 12;
#define  led0 13



char lastRead0;  // remember the previous input
char lastRead1;
char lastRead2;

char id;
char data = 0;

// :::functions:::

// move servo takes values that range from 0 to 255
void moveServo( char servoPin, char inputVal){
 //moving the servo's to the selected value with microsecond function
 int val;
 val = (inputVal * 4) + 1000;
 digitalWrite(servoPin, HIGH);  
 delayMicroseconds(val);      
 digitalWrite(servoPin, LOW);  
 //delay(20);
}

int simVal( char val1, char val2 ) {
 char difference;
 difference = val1 - val2;
 if (abs(difference) < 2){
   return 1;
 }
 else{
   return 0;
 }
}

void targetLoopDelay(int target_time) {

 delaytime = millis() - previousmillis;
 if (delaytime < target_time) delay(target_time - delaytime);

 previousmillis = millis();

}

void messagestart(char letter) {
 Serial.print(letter,BYTE);
}

void messagedata(char value) {
 Serial.print(32,BYTE);
 Serial.print(value,DEC);
}

void messageend() {
 Serial.println();
}

void setup() {


 pinMode(LP, INPUT);
 pinMode(UP, INPUT);
 pinMode(RP, INPUT);
 pinMode(DP, INPUT);
 pinMode(KP, INPUT);
 pinMode(rP, INPUT);
 pinMode(gP, INPUT);

 pinMode(Se0, OUTPUT);
 pinMode(Se1, OUTPUT);
 pinMode(Se2, OUTPUT);
 pinMode(led0, OUTPUT);

 moveServo(Se0, 0); // Startpositions
 moveServo(Se1, 0);
 moveServo(Se2, 0);

 digitalWrite(13, HIGH);

 beginSerial(9600);

 previousmillis = millis(); //targetLoopDelay() init
}

void loop() {
 //knoppen data doorgeven:::

 messagestart('b');
 messagedata(digitalRead(LP));
 messagedata(digitalRead(RP));
 messagedata(digitalRead(DP));
 messagedata(digitalRead(UP));
 messagedata(digitalRead(KP));
 messagedata(digitalRead(gP));
 messagedata(digitalRead(rP));
 messageend();


 //data vanuit max:::
 // loop and do if there is one or more  PAIRS of bytes
 while ((Serial.available() > 1)){

   id = Serial.read();
   data = Serial.read();

   //servo 0:
   if (id == 0) {  
     if ( !(simVal(data,lastRead0))) {
       moveServo( Se0, data );
     }
     lastRead0 = data;
   }
   //servo 1:
   if (id == 1) {

     if ( !(simVal(data,lastRead1))) {
       moveServo( Se1, data );
     }
     lastRead1 = data;
   }
   //servo 2:
   if (id == 2) {

     if ( !(simVal(data,lastRead2))) {
       moveServo( Se2, data );
     }
     lastRead2 = data;    
   }

   //led0:
   if (id == 3){

     //removed simval because it made no sense here
     if (data != 0){
       digitalWrite(13, HIGH);
     }
     else{
       digitalWrite(13, LOW);
     }
   }

 }

 targetLoopDelay(20); //this is the target delay needed for the servos

}




Here is the max patch (saved as text):

Code: [Select]
max v2;
#N vpatcher 20 96 667 639;
#P window setfont "Sans Serif" 9.;
#P newex 34 466 26 9109513 print;
#P newex 18 412 27 9109513 t b b;
#P newex 38 437 29 9109513 timer;
#P message 160 430 101 9109513 1 0 0 0 0 0 0;
#P newex 160 400 54 9109513 prepend set;
#P newex 161 339 58 9109513 fromsymbol;
#P newex 160 365 34 9109513 route b;
#P comment 227 70 100 9109513 0-255;
#P number 225 89 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P comment 173 45 100 9109513 0-255;
#P number 171 64 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P comment 111 25 100 9109513 0-255;
#P number 109 44 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 197 131 38 9109513 pak 2 0;
#P toggle 18 126 15 0;
#P newex 18 99 44 9109513 loadbang;
#P newex 18 149 39 9109513 metro 1;
#P newex 123 236 44 9109513 sel 10 13;
#P newex 153 270 52 9109513 zl group 64;
#P newex 141 302 151 9109513 itoa;
#P toggle 298 107 15 0;
#P newex 270 131 38 9109513 pak 3 0;
#P newex 123 203 102 9109513 serial com5 9600 8 1 0;
#P newex 143 131 38 9109513 pak 1 0;
#P newex 81 131 38 9109513 pak 0 0;
#P comment 229 202 100 9109513 Select the serial port to which you connected the Arduino;
#P comment 316 106 100 9109513 Led (#3);
#P comment 161 453 100 9109513 Buttons (b);
#P connect 12 0 13 0;
#P connect 13 0 11 0;
#P connect 21 0 26 0;
#P connect 25 0 27 0;
#P connect 26 0 25 0;
#P connect 26 1 25 1;
#P connect 15 0 3 1;
#P connect 6 0 5 0;
#P connect 11 0 5 0;
#P connect 3 0 5 0;
#P connect 4 0 5 0;
#P connect 14 0 5 0;
#P connect 5 0 10 0;
#P connect 9 0 8 0;
#P connect 10 2 9 0;
#P connect 10 1 9 0;
#P connect 22 0 21 0;
#P connect 21 0 23 0;
#P connect 23 0 24 0;
#P connect 8 0 22 0;
#P connect 17 0 4 1;
#P connect 19 0 14 1;
#P connect 7 0 6 1;
#P pop;


Tom
Thomas Ouellet Fredericks

admin

Tom

thanks a lot for your contribution.
Since I've starting to use PD to teach i've see some of your work, congratulations.


Just a little comment on the code issue... We will  release into the wild a new version of arduino which
supports processors with 16K of code... this will solve most of the problems.

Official launch I think will be at Ars Electronica but some betas will be available much earlier.

I'm porting the bootloader right now :)

massimo

eelke

tof, thank you very much! I'll be checking the working of this on monday and will tell how things went.

ccdust

this might also help
Code: [Select]
#include <avr/eeprom.h>

int adress;
int var;
int numadress;
int prekinitve;
long previousMillis = 0;        // will store last time LED was updated
long interval = 300000;  
void setup() {
   beginSerial(9600);        // use the serial port to send the values back to the computer
   Serial.println("Termometer v 1.0");
   Serial.print("Incializacija ");
   numadress=eeprom_read_byte(0);
   Serial.print("*");
   adress=numadress+1;
   Serial.print("*");
   eeprom_write_byte((unsigned char *)adress, (analogRead(0)-556)/2); // fill each address with its own value
   Serial.print("*");
   eeprom_write_byte((unsigned char *)0, adress); // fill each address with its own value
   Serial.println("*");
}

void loop()
{
 if (millis() - previousMillis > interval) {
   previousMillis = millis();   // remember the last time we blinked the LED
   numadress=eeprom_read_byte(0);
   adress=numadress+1;
   eeprom_write_byte((unsigned char *)adress, (analogRead(0)-556)/2); // fill each address with its own value
   //Serial.print("merjeno=");
   //Serial.println((analogRead(0)-556)/2);
   //Serial.print("naslov=");
   //Serial.println(adress);
   eeprom_write_byte((unsigned char *)0, adress); // fill each address with its own value
 }

 if (Serial.available() > 0) {
   if(Serial.read()==49)
     while(prekinitve < numadress+2)
     {
       var = eeprom_read_byte((unsigned char *) prekinitve);
       Serial.print("adresa[");
       Serial.print(prekinitve);
       Serial.print("]=");
       Serial.println(var);
       prekinitve++;
     }

 }
 if (prekinitve == numadress+2)
 {
   prekinitve=0;
 }
}

Go Up