Arduino - Motor position control

This article will show how to control position of motor shaft: return shaft to original position, no matter what it was turned manually before
Fig1. Motor with shaft indication


Movie. Result of project

Hardware needed:
1. Motor with Encoder
2. H-bridge PCB
3. Arduino Pro mini
4. UART PCB
5. Computer (with Visual Studio)

Step 1. Hardware connection
This article doesn't mention about detail connection, it is based on previous article which can be found at this link
Fig2. General view of connection

Step 2. Code works at Arduino




Arduino will store position of motor. Returning to original position as soon as signal "start" received (from Visual Studio)
Key point of program is calculating position of encoder exactly
Fig3. Encoder of motor
To calculate exactly encoder even it is rotating forward or backward many time, without loss of pulse, it's better to read rising/falling edge of encoder.
void loop() {
  if (stringComplete) {
    // clear the string when COM receiving is completed
    mySt = "";  //note: in code below, mySt will not become blank, mySt is blank until '\n' is received
    stringComplete = false;
  }

  //receive command from Visual Studio
  if (mySt.substring(0,8) == "vs_start"){
    motor_start = true;
  }
  if (mySt.substring(0,7) == "vs_stop"){
    motor_start = false;
  }

  //find position
  if(motor_start){
    //start finding position since receive "vs_start" from Visual Studio
    analogWrite(pin_pwm,40); //set motor speed = 40/255 = 15.6%
    if(encoder_r+encoder_f < -1){
      digitalWrite(pin_fwd,1);
      digitalWrite(pin_bwd,0);
    }
    else{
      if(encoder_r+encoder_f > 1){
        digitalWrite(pin_fwd,0);
        digitalWrite(pin_bwd,1);
      }
      else{
        //stop motor if position between +1 ~ -1
        analogWrite(pin_pwm,0);   //stop motor
        digitalWrite(pin_fwd,0);  //stop motor
        digitalWrite(pin_bwd,0);  //stop motor
      }
    }
  }
  else{
    //stop finding position since receive "vs_stop" from Visual Studio
    analogWrite(pin_pwm,0);   //stop motor
    digitalWrite(pin_fwd,0);  //stop motor
    digitalWrite(pin_bwd,0);  //stop motor
  }
}

void detect_a_r() {
  m_direction = digitalRead(pin_b); //read direction of motor
  if(!m_direction){
    encoder_r += 1;   //increasing encoder at forward run
  }
  else{
    encoder_r += -1;  //decreasing encoder at backward run
  }

  attachInterrupt(digitalPinToInterrupt(pin_a), detect_a_f, FALLING); //change interrupt to Falling edge
}
void detect_a_f() {
  m_direction = digitalRead(pin_b); //read direction of motor
  if(m_direction){
    encoder_f += 1; //increasing encoder at forward run
  }
  else{
    encoder_f += -1; //decreasing encoder at backward run
  }

  attachInterrupt(digitalPinToInterrupt(pin_a), detect_a_r, RISING);  //change interrupt to Rising edge
}

The entire of code can be downloaded at this link

Step3. Code works at Visual Studio
Visual Studio program is used to send command "start" or "stop" finding original position, also show current position by chart
Fig4. Visual Studio program

#pragma endregion
private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
serialPort1->Open();
timer1->Start();
i=300;
}
private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
serialPort1->WriteLine("vs_start"); //start finding position
}
private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
serialPort1->WriteLine("vs_stop"); //stop finding position
}
private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
int len=mStr->Length;
if(mStr->Substring(0,7)=="encoder"){
position=mStr->Substring(7,len-7);
label1->Text=position;
//print motor speed into Chart
this->chart1->Series["Series1"]->Points->AddXY(i,System::Convert::ToDouble(position));
i++;
this->chart1->ChartAreas["ChartArea1"]->AxisX->Minimum=i-300; //shift x-axis
}
}
private: System::Void serialPort1_DataReceived(System::Object^  sender, System::IO::Ports::SerialDataReceivedEventArgs^  e) {
mStr=serialPort1->ReadLine();
}

The entire of code can be downloaded at this link


1 comment: