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.
motor_position (main function)
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
}
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
Visual Studio (main function)
#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();
}
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
Great Article
ReplyDeleteInternet of Things Final Year Project
Final Year Project Centers in Chennai