07-05-2018 08:19 AM
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 ![]()
If you have any idea, please tell me.
Quentin
Solved! Go to Solution.
07-10-2018 09:36 AM
Hi !
Whats is your question exactly ? I don't understand it 🙂
Cheers!
07-11-2018 02:43 AM
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 🙂
10-24-2018 07:35 PM
Hi This is pretty cool
How would you do it so you could control 5 motors?