Go Down

Topic: Reading serial binary data (Read 23169 times) previous topic - next topic

brian15co

Hey guys, I have finally solved the issue of controlling a servo with serial communication. The PC (Simulink) is sending a 16 bit integer in binary format that is the desired servo position in degrees. Thanks to PaulS and Zoomkat for all the help :smiley-mr-green:.

The serial timing issue was solved by eliminating the Serial.flush command (commented out in the code)


Thanks again Forum,
Brian

Code: [Select]
// Control the small blue servo
// Brian Leach
// april 12 2011
// integer value from simulink. use the signed 16 bit integer from simulink with servo.write
// Simulink is sending a value (in degrees) to position the servo.

#include <Servo.h>

Servo blue;

int ang; // create integer to hold servo angle
int new_ang = 90;
int old_ang = 90;
byte b[2]; // byte array

void setup() {
blue.attach(5, 1025, 1975); // servoName.attach(pin, min, max)
        Serial.begin(38400); // begin serial @ 38400 bits/sec
       
        pinMode(8,OUTPUT); // debug lights. red no serial
        pinMode(9,OUTPUT); // debug light green yea serial
        pinMode(6,OUTPUT); // output 6 LED
        //pinMode(5,OUTPUT); // output 5 servo
        byte homey = 90;
        blue.write(homey);  // set servo to mid-point
        delay(1000);;
}

void loop() {
 
  //Serial.flush(); // clear the serial buffer before reading new data *** this was the problem. clearing data unnecessarily
  memset(b, '\0', 2);
  boolean tsv = false; // boolean to decide if the servo should be sent commands
  int angval = 0; // integer value of angle in degrees
 
if (Serial.available() > 0) { // only loop the serial structure if its serialing

          digitalWrite(8,LOW);  // red off // light green if serial data, red if NO serial 
          digitalWrite(9,HIGH); // green on

          char inbyte = '\0'; // null?
          int timeout = 1000; // sets timeout to wait 1 second for a number
          long startTime = millis(); // now is the start time
          //delay(1); // try a delay
          while (millis() - startTime < timeout && inbyte != '*') { // this is the header character in the Simulink bloc. the loop waits for it
             inbyte = Serial.read(); // change the inbyte to the waiting byte
          }
 
          if (inbyte == '*') { // this means its the start of a number
             
             tsv = true; // this might eventually be an error check
             startTime = millis(); // start time is now
             
             while (millis() - startTime < timeout && Serial.available() < 3) { // allow 2 at least bytes to fill the buffer
             }
           
             for (int i=0; i<2; i++) {
                b[i] = Serial.read();
             }
             
             int angval2 = b[0]+b[1]*256; // converts the two bytes to an integer. thanks to Zoomkat for this solution   
             int new_ang = angval2; // sets the angle value for this loop
             
             if (old_ang != new_ang) { // if new angle equals old angle don't write anything
                if (tsv == true) {
               
                  int angLED = (angval2/180)*255; // prepare for the PWM signal
                  // int angLEDpwm = abs(angLED); // absolute value for PWM LED // truncated?
                  // check if the value looks write
             
                  analogWrite(6,angLED); // debug
                  blue.write(angval2); // write servo?
                  old_ang = angval2; // reset?
                  Serial.print(angLED);
               
                }
             }
             //delay(.5);
          }
       }
       

        else {
          digitalWrite(8,HIGH); // red ON
          digitalWrite(9,LOW); // green OFF
          analogWrite(6,0); // servo lite OFF
        }
        delayMicroseconds(2);
}
       
     

viscousflow

#16
Apr 22, 2011, 02:49 am Last Edit: Apr 22, 2011, 06:47 am by viscousflow Reason: 1
Hey, I tried your code to run my motors and all it does is go straight to 100% and saturates. What I'm trying to do is run my usb throttle to send numerical values to my edf. My setup is throttle at (0-100%)*Motor bandwidth + deadzone in milliseconds. In other words it should start from deadzone and throttle from 0 to 100%. I sent it through a signed int16 block, then a saturation block (with inherited datatype) then to serial send. I basically coped and pasted your code and modified it for writeMicroseconds.

Any thoughts on this?

Running Arduino Mega w/ ATMega1280

edit: The code I used is here
Code: [Select]
//The script simply reads the serial data received as throttle
//in milliseconds

#include <Servo.h>
Servo motor; //create servo object
Servo motor1; //create servo object

int new_throttle = 0;
int old_throttle = 0;
byte b[2]; // byte array

//-----------------------------
//----------Activate-----------
void activate(Servo motor,int n)
{
motor.attach(n);                  // attach motor to pin n
motor.writeMicroseconds(1000);    // write zero throttle to activate
delay(1000);
}

void setup()
{
 // activate motor first
 activate(motor,3); // forward motor 3
 activate(motor,4); // forward motor 1
 
 //connect to the computer
 Serial.begin(38400); // initialize serial ports 0 & 3
}

void loop()
{
 if (Serial.available() > 0) { // only loop the serial structure if its serialing

 int tval12 = 1280; // create integer to hold throttle value
 boolean tsv = false;
 char inbyte = '\0'; // null?
 int timeout = 20; // sets timeout to wait 20 milliseconds for a number
 long startTime = millis(); // now is the start time
         
  while (millis() - startTime < timeout && inbyte != '*') { // this is the header character in the Simulink block. the loop waits for it
    inbyte = Serial.read(); // change the inbyte to the waiting byte
  }
         
  //reading data now
  if (inbyte == '*') { // this means its the start of a number
         
    tsv = true; // this might eventually be an error check
    startTime = millis(); // start time is now
         
    while (millis() - startTime < timeout && Serial.available() < 3) { // allow 2 at least bytes to fill the buffer
    }
     
    for (int i=0; i<2; i++) {
      b[i] = Serial.read();
    }
           
    int tval2 = b[0]+b[1]*255;
    int new_throttle = tval2; // sets the throttle value for this loop
           
    if (old_throttle != new_throttle) { //if throttle has changed write new one
      if (tsv == true) {
       
        //saturtate thrust at max (2000ms)
        if (new_throttle>= 2000)
        {
          new_throttle = 2000;
        }
        //Serial.print(new_throttle);
        motor.writeMicroseconds(new_throttle); // write motor
        motor1.writeMicroseconds(new_throttle); // write motor
        old_throttle = new_throttle; //save last value
           
      }
    }
  }
}
}


Go Up