Real-Time Measurement and Control

cancel
Showing results for 
Search instead for 
Did you mean: 

Labview/Arduino PWM issue

Solved!
Go to solution

Hi everyone ! 

 

I am trying to control a DC motor with an Arduino nano.

The PWM command comes from labview, is transferred by bluetooth to the Arduino nano and sent to the motor thanks to analogWrite.

I need to get datas from a sensor to use a PID controller. The data from the sensor are collected thanks to an interruption (a simple counter), processed by the arduino and sent to Labview by bluetooth. It's also easy to do and it is working.

It looks easy to do and everything is ALMOST working BUT 

 

when I try to control the motor, the PWM output from Arduino is jerky. I can't find the source of this problem.

 

 

 

Here are two little videos of the problem, the arduino code and I join the VI.

1 : View of the motors that are not working properly. You can hear the sound. like bipbipbipbip  https://www.youtube.com/watch?v=_7Zo1sEfA-U

2 : View of the oscilloscope. It the PWM output from pin 6 of arduino nano

https://www.youtube.com/watch?v=8dGwg_k5i6o

 

 volatile byte counter;
 int rpm= 0;
 int defaultVal = -1;   //will be used when labview is waiting for something and Arduino hasn't got anything to send
 long timeold;          //time value
 int interruptPin = 0, pinPWM = 6;
 String command;
 
 void setup()
 {
   pinMode ( interruptPin, INPUT );
   pinMode ( pinPWM, OUTPUT );

   counter = 0;
   Serial.setTimeout( 70 ); //to avoid waiting 1000ms between each change of the pwm value on labview
   Serial.begin ( 9600 );
   Serial.println ( "let's go" );
   attachInterrupt ( interruptPin, interruptCounter, FALLING );
   timeold = millis();
 }

 void loop()
 {
 
    if( counter >= 18 ){                  //2spins because half of the reflective parts are hidden
      detachInterrupt ( interruptPin );
      //analogWrite ( pinPWM, command.toInt() );
      /******************* TREATMENT OF THE ROTATION SPEED *******************/
                //we know that the platform made 2 spins sins we registered the time. We mow have to check the time, sustract timeold with it and we kmow how much time it took. And convert rpmilliseconds to rpminutes
      rpm = 30000 / ( millis() - timeold );
     
      /******************* GETTING READY FOR ANOTHER ROUND ******************/
      Serial.print( rpm );
      counter = 0;
      timeold = millis();  
      attachInterrupt ( interruptPin, interruptCounter, FALLING );
    }else if (millis() - timeold >= 1001){
      Serial.print( 0 );
    }
    else {
      Serial.print( defaultVal );
    }                          //Not important, just because labview is waiting to read something 


    /********************** ACTUALISING THE PWM **********************/
    command = Serial.readString(); 
    analogWrite ( pinPWM, command.toInt() );
   
 }

 void interruptCounter() { ++counter;  }

 

Thanks for reading Smiley Happy

If you have any idea, please tell me.

 

Quentin

0 Kudos
Message 1 of 4
(3,478 Views)

Hi !

 

Whats is your question exactly ? I don't understand it 🙂

 

Cheers!

0 Kudos
Message 2 of 4
(3,450 Views)
Solution
Accepted by topic author nitneuk

Hi RojoRak

My question was "Have you got any idea about where does this problem comes from ?" but you're right, it wasn't clear.

 

But I finally have the solution. The String library isn't made for transferring data like this. When I was using Serial.readString, it was reading the value but after the timeout, it was reinitialized that's why the PWM command was null periodically.

To correct it I used class char strings.

Here is the new code 

/****************** DESCRIPTION ********************
* This program is controlling the spinning platform. First, it is using the sensor to check the speed of the platform.
* Then, It gets the rpm Setpoints value from Labview. It's the speed value asked by the user
* Finally, It uses them with a PID controller to create the new PWM command for the motors
*/


/*********************************************************/
/*********************** OBJECTS *************************/
/*********************************************************/

/* ====== Objects::pwmCommand ====== */
const byte numChars = 4;  //number of chars we want to read. Here it's 3 (0,1,2,3) with the endMarker \n
char receivedChars[numChars];
const int pinPWM = 6;
int PWMVal = 0;
//static byte counter;
boolean newData = false;

/* ====== Objects::Sensor ====== */

const int pinInterrupt = 0;
int rpm = 0, countInterrupt = 0;
int defaultVal = -1;  //will be used when labview is waiting for something and Arduino hasn't got anything to send
long timer;


/* ====== Objects::PID ====== */


/*********************************************************/
/*********************** FUNCTIONS ***********************/
/*********************************************************/

/* ====== Functions::PW M====== */

void pwmControl(int pin, int pwm){
  if(newData == true){
    //Serial.println(receivedChars);
    newData = false;
    analogWrite(pin, pwm);
  }
}

void reception(){
  static byte counter = 0;
  char endMarker = 'p', rc;
  
  while(Serial.available() > 0 && newData == false){
    rc = Serial.read();
    if( rc != endMarker ){
      receivedChars[counter] = rc;
      ++counter;
      if(counter >= numChars){  //just in case
        counter = numChars - 1;
      }
    }
    else{
      receivedChars[counter] = '\0';  //if we received the endMarker, we can end the string and get ready for another round
      counter = 0;
      newData = true;
      
    }
  }
}

int convert(int val){
  if(PWMVal < 0 ) return 0;
  else if(PWMVal >255){
    return 255;
  }
  else return val;
}

/*======Functions::Sensor======*/


 void interruptCounter() { ++countInterrupt; }

 void compute(){
   if( countInterrupt >= 18 ){                  //2rotations because half of the reflective parts are hidden
      detachInterrupt ( pinInterrupt );//useless
      
                //we know that the platform made 2 spins sins we registered the time. We mow have to check the time, sustract timer with it and we kmow how much time it took. And convert rpmilliseconds to rpminutes
      rpm = 30000 / ( millis() - timer );
      
      Serial.print( rpm );
      countInterrupt = 0;
      timer = millis();   
      attachInterrupt ( pinInterrupt, interruptCounter, FALLING );
    }else if (millis() - timer >= 1001){//if the platform is not moving
      Serial.print( 0 );
    }
    else {//we have to send something to labview. He is waiting for us. We can't disappoint him else he'll timeout error
      Serial.print( defaultVal );
    }                    
  
 }
 
/************************************************************/
/************************** MAIN ****************************/
/************************************************************/

void setup() {

  /*PWM control settings*/
  pinMode(pinPWM, OUTPUT);
  
  
  /*PID settings*/

  /*General Settings*/
  Serial.begin(9600);
  Serial.println("Okay.\nLet's go !");
  Serial.setTimeout( 100 ); //to avoid waiting 1000ms between each change of the pwm value on labview
  
  /*Sensor/interrupt settings*/
  pinMode ( pinInterrupt, INPUT );
  attachInterrupt ( pinInterrupt, interruptCounter, FALLING );
  timer = millis();
}

void loop(){
  compute();
  reception();
  PWMVal = convert(atoi(receivedChars));
  pwmControl(pinPWM, PWMVal);
}

I will also upload the Labview program. It may help someone

 

Cheers 🙂

Message 3 of 4
(3,446 Views)

Hi This is pretty cool

 

How would you do it so you could control 5 motors?

0 Kudos
Message 4 of 4
(3,264 Views)