Maya and Arduino

Hi Guys… let me preface with I am a Arduino noob, and a serial communications noob… I am just hacking my way thru things.

I work in Maya software from autodesk, and have been working on an interface between it and my robots. I know there is already “ServoTools for Maya” but that one is limited by servos being hard coded into the arduino sketch.
I have written a node in maya/python that is a lot more open than servoTools. I have it working with my Robotis USB2Dynamixel now, and I am trying to add the same kind of functionality to an arduino controlled robot.

Basically what I need is to be able to send a start byte to the arduino, then a servo ID (pin number for arduino) then the value that the servo needs to be.

This is what I have so far… I ripped some of the SerialLCD stuff because I have a matrix orbital LK204-24 connected to my arduino mega for debugging readout.

arduino code

int mode = 0;              // where we are in the frame
unsigned char id = 0;      // id of servo
int pwmSend;

void setup()
{
  Serial.begin(38400);
  Serial1.begin(19200);
clearLCD();

//       Turn OFF the block cursor    
//       Note that setting both block and underline 
//       cursors may give unpredictable results. 
           Serial1.print(254, BYTE);
           Serial1.print(84, BYTE);               

//       Turn ON the underline cursor
         Serial1.print(254, BYTE);
         Serial1.print(74, BYTE);               
              
}

//  MAIN CODE

void loop()
{ 
  cursorHome();  
  Serial1.print("WFSB");//waiting for start byte
//not using cursorSet cause it doesnt work, just resets position to 1,1
  cursorRight();cursorRight();cursorRight();cursorRight();

   Serial1.print("ID is ");
   newLine();

while(Serial.available() > 0){
        // We need to 0xFF at start of packet
        if(mode == 0){         // start of new packet
            if(Serial.read() == 0xFF){
                mode = 2;
                newLine();
                Serial1.print("GSB");//Got Start Byte
                 cursorRight();cursorRight();cursorRight();cursorRight();cursorRight(); 
            }
  }else if(mode == 2){   // next is index of servo
            id = Serial.read();    
            if(id != 0xFF)
                mode = 3; 
                Serial1.print(id);
                 newLine();
                      }
    else if(mode == 3){   // next byte is length
      if(Serial.read() == 0xFF){
            pwmSend = Serial.read();
            mode = 4;
            Serial1.print("got pwm ");
            Serial1.print(pwmSend);
          }
        }
  // print text to the current cursor position
               // start a new line
}

}




//  LCD  FUNCTIONS-- keep the ones you need. 

// clear the LCD
void clearLCD(){
  Serial1.print(12, BYTE);
}


// start a new line
void newLine() { 
  Serial1.print(10, BYTE); 
}


// move the cursor to the home position
void cursorHome(){
  Serial1.print(254, BYTE);
  Serial1.print(72, BYTE);
}


// move the cursor to a specific place
// e.g.: cursorSet(3,2) sets the cursor to x = 3 and y = 2
void cursorSet(int xpos, int ypos){  
  Serial1.print(254, BYTE);
  Serial1.print(71, BYTE);               
  Serial1.print(xpos);   //Column position   
  Serial1.print(ypos); //Row position 
} 


// backspace and erase previous character
void backSpace() { 
  Serial1.print(8, BYTE); 
}


// move cursor left
void cursorLeft(){    
  Serial1.print(254, BYTE); 
  Serial1.print(76, BYTE);   
}


// move cursor right
void cursorRight(){
  Serial1.print(254, BYTE); 
  Serial1.print(77, BYTE);   
}


// set LCD contrast
void setContrast(int contrast){
  Serial1.print(254, BYTE); 
  Serial1.print(80, BYTE);   
  Serial1.print(contrast);   
}


// turn on backlight
void backlightOn(int minutes){
  Serial1.print(254, BYTE); 
  Serial1.print(66, BYTE);   
  Serial1.print(minutes); // use 0 minutes to turn the backlight on indefinitely   
}


// turn off backlight
void backlightOff(){
  Serial1.print(254, BYTE); 
  Serial1.print(70, BYTE);   
}

here is the python code that sends the serial data to the arduino

def moveServo(servo, angle):
    ''' A function for setting the servo number and its angle.
    
    Example:
    >>> servo.move(1,180)'''
    if (0 <= angle <= 180):
        if angle != lastAngle[servo -1]:
            ser.write(0xFF)
            ser.write(chr(servo))
            ser.write(0xFF)
            ser.write(chr(angle))
            ser.write(chr(13))
            lastAngle[servo -1] = angle
            #print "running serial write"
            #print "servo " + str(servo) + " " + str(angle)
    else:
            print "Servo angle must be an integer between 0 and 180.\n"
    return lastAngle[servo -1]

the ser.write(chr(13)) was a test to see if sending a different character would be easier

anyone have any insight on how I can get this to work?
I thought I was close but am getting stuck :frowning:

Your script always sends 5 bytes - 0xFF, ServoNumber, 0xFF, ServoPosition, 13. You could, in loop(), do nothing until Serial.available() returned a value greater than or equal to 5:

if(Serial.available() >= 5)
{
   int sop = Serial.read();
   int servoNum = Serial.read();
   int mop = Serial.read();
   int servoPos = Serial.read();
   int eop = Serial.read();

   if(sop == 0xFF && mop == 0xFF && eop == 13)
   {
      // Got a valid packet. Position servo servoNum to position servoPos
   }
}

anyone have any insight on how I can get this to work?

You didn't explain how it isn't working, so other than the suggestion above, sorry, no.

It isnt working as the arduino doesnt seem to be receiving the data.

I added some debugging to the code that prints to my lcd to see whats going on, and nothing comes thru. I did have another line in there that just printed to the LCD when it was inside the serial.read loop and it printed that, so the debugging to the lcd works.

Here is what I have.

void loop()
{ 
 // cursorHome();  
 // Serial1.print("WFSB");//waiting for start byte
//not using cursorSet cause it doesnt work, just resets position to 1,1
//  cursorRight();cursorRight();cursorRight();cursorRight();

  // Serial1.print("ID is ");
   //newLine();

if(Serial.available() >= 5)
{
   int sop = Serial.read();
   if(sop == 0xFF){Serial1.print("got start byte");}
   int servoNum = Serial.read();
   int mop = Serial.read();
   if(mop == 0xFF){Serial1.print("got id byte");}
   int servoPos = Serial.read();
   int eop = Serial.read();
   if(eop == 0xFF){Serial1.print("got end byte");}

   if(sop == 0xFF && mop == 0xFF && eop == 13)
   {
      // Got a valid packet. Position servo servoNum to position servoPos
      Serial1.print("Got ID and PWM");
      Serial1.print(servoNum);
      Serial1.print(" ");
      Serial1.print(servoPos);
   }
}
}

Nothing comes up on the LCD.. so either "if(mop == 0xFF){Serial1.print("got id byte");}" isnt qualifying, or the arduino isnt receiving the data. Is that correct?

Nothing comes up on the LCD.. so either "if(mop == 0xFF){Serial1.print("got id byte");}" isnt qualifying, or the arduino isnt receiving the data. Is that correct?

Yes.

Try adding this to loop():

Serial1.print("Bytes available: ");
Serial1.print(Serial.available());

See if any values other than 0 are ever printed.

ok I added that..

void loop()
{ 
 // cursorHome();  
 // Serial1.print("WFSB");//waiting for start byte
//not using cursorSet cause it doesnt work, just resets position to 1,1
//  cursorRight();cursorRight();cursorRight();cursorRight();

  // Serial1.print("ID is ");
   //newLine();

if(Serial.available() >= 5)
{
  Serial1.print("Bytes available: ");
  Serial1.print(Serial.available());
   int sop = Serial.read();
   if(sop == 0xFF){Serial1.print("got start byte");}
   int servoNum = Serial.read();
   int mop = Serial.read();
   if(mop == 0xFF){Serial1.print("got id byte");}
   int servoPos = Serial.read();
   int eop = Serial.read();
   if(eop == 0xFF){Serial1.print("got end byte");}

   if(sop == 0xFF && mop == 0xFF && eop == 13)
   {
      // Got a valid packet. Position servo servoNum to position servoPos
      Serial1.print("Got ID and PWM");
      Serial1.print(servoNum);
      Serial1.print(" ");
      Serial1.print(servoPos);
   }
}
}

the LCD prints out

"bytes available: " then a number that changes.. I saw numbers from 5 to 13, doesnt mean those are the only numbers.. just means those are the only ones I saw

That means that serial data is getting through. So, print the values on the LCD that are in sop, mop, and eop. I'm guess that they are not 0xFF, 0xFF, and 13.

PaulS: That means that serial data is getting through. So, print the values on the LCD that are in sop, mop, and eop. I'm guess that they are not 0xFF, 0xFF, and 13.

I am going to change the first bytes being sent.. I think it is actually getting 0xFF across cause when I try to print sop to teh screen which should be 0xFF, the screen blinks.. it just so happens that 0xFF is the code you send to the Matrix Orbital screen to tell it to be ready for a command like to turn backlight on or off lol.. so I think its getting the right thing 0xFF

Ok, so I changed them all to 13, and they seem to work fine like that. I think there is some miscommunication when using 0xFF, or just that type of data.. after 13 worked, I tried sending 0xFE and it didnt work.

The difference I see is when I send the 13 from python, I am sending like this

ser.write(chr(13))

when I try to send 0xFF or 0xFE I send it with no chr

ser.write(0xFF)

in the arduino I am trying to qualify like this

if(eop == 0xFF)
if(eop == 13)

So do I need to do something in the arduino code to tell it that 0xFF is not just characters?

It may well be that the Python code has issues with non-ASCII characters (those with values above 127). There is no real reason to use them as delimiters for numeric data. Sending ‘<’, some number, ‘;’, another number, and ‘>’ would work just as well. On the Arduino, you can test for the character being ‘<’, ‘>’, or ‘;’ and print them, too. Much easier to understand what is happening if you use ASCII separators, in my opinion.

PaulS:
It may well be that the Python code has issues with non-ASCII characters (those with values above 127). There is no real reason to use them as delimiters for numeric data. Sending ‘<’, some number, ‘;’, another number, and ‘>’ would work just as well. On the Arduino, you can test for the character being ‘<’, ‘>’, or ‘;’ and print them, too. Much easier to understand what is happening if you use ASCII separators, in my opinion.

I just realized something… I was thinking that couldnt be it… cause I am sending 0xFF from a different part of the python code to the robotis dynamixels, and that works. I send it as a big packet also (its ho you send commands to the AX12s).
So I went and coppied the code to paste it here… and I AM using chr(0xFF) to send… not sending jsut 0xFF lol so I will switch it to that for the arduino side also

def setReg(ID,reg,values):
    if values != lastAngle:
        length = 3 + len(values)
        checksum = 255-((ID+length+AX_WRITE_DATA+reg+sum(values))%256)          
        ser.write(chr(0xFF)+chr(0xFF)+chr(ID)+chr(length)+chr(AX_WRITE_DATA)+chr(reg))
        for val in values:
            ser.write(chr(val))
        ser.write(chr(checksum))
    return lastAngle