[Yinglish] Arduino + SG90 + Motor130 + IR

Author Avatar
MonsterX 6月1日 发布 | 06月05日最后更新
  • 在其它设备中阅读本文章

由于我的辣鸡 Arduino mini 风扇 项目居然进校“启航杯”决赛了,得去答辩(实际上似乎只有极极极少一部分项目被淘汰了,决赛全校入选了 近两百 465 份作品),不得不再整理一遍所有代码,加上最新的关于解决舵机摇头问题的思路, 爱装 13 的 (不,我不是,我没有)我尝试用 嘤语 英语写了这篇文章。说实话,风扇我都快拆的只剩零件了…

* 如果你实在不想看这篇辣鸡英语博文,你可以看看 中文版 吖,希望能帮到你…

 

In this article, I will show you how to use the Arduino microcontroller to make a small fan with shaking head and infrared remote control functions. This is also the first time I have tried to write something in English. I will try to use some simple words to make the article easy to understand (the fact is that I don't remember complicated vocabulary and grammatical structure.Hahaha...)
To start this project, we need to prepare some materials firstly. These materials have been used many times in my old blog posts, and if you look through my previous blog posts then you won't be unfamiliar with them.

  • A piece of Arduino board, which we use to control all other components.
  • A 130 motor, and we use it to make the fan run.
  • A servo(SG90), to control the fan shaking its head.
  • A J16409 infrared sensors, to receive infrared signals.
  • A ULN2003 motor drive module, used to drive the 130 motors described earlier. The current generated by the Arduino I/O port is too small to drive the motor, and we need to use this to amplify the current. Maybe we can zoom in with transistor, too.
  • A key switch, to manually control the fan.
  • Some DuPont lines.
  • If we need to run this fan out of the computer (power the fan with a rechargeable Polaroid), we need an extra 9V booster line.

 

Contents
Module 1 : Motor130
Module 2 : Servo
Module 3 : Infrared remote control
Overall

 

 

Module 1 : Motor130

Template

A basic example might be like this. In this example, we connect the motor to the 9th pin and use the code to make the motor run at maximum speed for 1s and then stop for 1s .

const int MotorPIN = 9;
void setup() {
    pinMode(MotorPIN, OUTPUT);
}
void loop() {
    digitalWrite(MotorPIN, HIGH);
    delay(5000);
    digitalWrite(MotorPIN, LOW);
    delay(5000);
    
    // Use PWM to implement the above code.
    analogWrite(MotorPIN, 255);
    delay(5000);
    analogWrite(MotorPIN, 0);
    delay(5000);
}

Rewrite

In order to make our fan have three grades and can be adjusted, we need to retrofit the above code. We add a key switch to the circuit and connect the switch to 8th pin. And this time we used the ULN2003 motor drive module, connecting the two wires of the motor to the output port of the drive module, and connecting the input port of the module to the 5th and 6th pins of the Arduino in turn. Serial Arduino and drive module enable Arduino to power the drive module. The fan speed is cycled from 0 to 3 when the buttons are pressed in sequence. The final code might look like this:

const int motorIn1 = 5;
const int motorIn2 = 6;
const int buttonPin = 8;
const int ledPin = 13;
// Define fan speed
int fanspeed = 0;
#define rank1 150
#define rank2 200
#define rank3 250
// Some variables are used for anti-shake processing of mechanical switches.
int btState;
int lastbtState = LOW;
// The time measured in milisecounds will quickly become a bigger number,
// which can't be stored in an int.
long lastDebounceTime = 0;
long debounceDelay = 50;

void setup() {
    // Set the LED motors as OUTPUT and botton as INPUT.
    pinMode(buttonPin,INPUT);
    pinMode(ledPin,OUTPUT);
    pinMode(motorIn1,OUTPUT);
    pinMode(motorIn2,OUTPUT);
    Serial.begin(9600);
}
 
void loop() {
    // Read the state of the switch.
    int reading = digitalRead(buttonPin);
    // If the button state is different from last time, reset the debouncing timer.
    if (reading != lastbtState) {
        lastDebounceTime = millis();
    }
    // Debounce treatment.
    if ((millis() - lastDebounceTime) > debounceDelay) {
        if (reading != btState) {
            btState = reading;
            if (btState == HIGH) {
                // Toggle the LED if the new button state is HIGH.
                digitalWrite(ledPin,HIGH);
                // Controll the fan speed.
                fanspeed = fanspeed + 1;
                if (fanspeed >= 4) {
                    fanspeed = 0;
                }
            }
            else
                digitalWrite(ledPin,LOW);
        }
    }
    // Save the reading and through the loop next time.
    lastbtState = reading;

    // Fan speed is divided into different grades.
    switch (fanspeed) {
        case 1:
            // When fanspeed=1 set the rotate speed of the motor as rank1=150.
            analogWrite(motorIn1, 0);
            analogWrite(motorIn2, rank1);
            break;
        case 2:
            // When fanspeed=2 set the rotate speed of the motor as rank2=200.
            analogWrite(motorIn1, 0);
            analogWrite(motorIn2, rank2);
            break;
        case 3:
            // When fanspeed=1 set the rotate speed of the motor as rank3=250.
            analogWrite(motorIn1, 0);
            analogWrite(motorIn2, rank3);
            break;
        default:
            // In default situation set the rotate speed of the motor as 0.
            analogWrite(motorIn1, 0);
            analogWrite(motorIn2, 0);
            break;
    }
}

Now we can control the fan switch and speed through the push button switch, and the LED will light up when the switch is pressed.

 

Module 2 : Servo

We need to introduce an additional library Servo.h before using this servo.

The Servo library supports up to 12 motors on most Arduino boards and 48 on the Arduino Mega. On boards other than the Mega, use of the library disables analogWrite() (PWM) functionality on pins 9 and 10, whether or not there is a Servo on those pins. On the Mega, up to 12 servos can be used without interfering with PWM functionality; use of 12 to 23 motors will disable PWM on pins 11 and 12.
Arduino - Servo

Template

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards
 
int pos = 0;    // variable to store the servo position
 
void setup() {
    myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}
 
void loop() {
    for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
        // in steps of 1 degree
        myservo.write(pos);              // tell servo to go to position in variable 'pos'
        delay(15);                       // waits 15ms for the servo to reach the position
    }
    for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
        myservo.write(pos);              // tell servo to go to position in variable 'pos'
        delay(15);                       // waits 15ms for the servo to reach the position
    }
}

Rewrite

We need two states of the servo, one is to keep the rotation, the other is to keep stopping. Okay, let the servo keep moving while the motor is running. This is really hard for me. Because I think the motor is running by relying on the loop() function to execute the analogWrite(); statement over and over again. The servo swing needs to execute the for() statement continuously. But Arduino only executes one statement at a time! So I tried to discard the for() structure. Since loop() can be executed cyclically, then...

// Define a variable control servo switch.
int servoSwitch = 0;
 
// Define a variable to control the angle of each step of the servo, and reverse each time it reaches 180º or 0º.
int anglestep = 10;
 
void loop() {
 
    /* ... */
 
    switch (servoSwitch) {
        case 1:
            angle = angle + anglestep;
            myservo.write(angle);
            delay(50);
            if (angle == 180 || angle == 0)
                anglestep = -anglestep;
            break;
        case 0:
            angle = myservo.read();
            break;
    }
}

 

Module 3 : Infrared remote control

Now we need to use infrared sensors to receive infrared signals to control the fan. The library IRremote.h is necessary. Read the official website description before using this library. Download this library files from GitHub and unzip it under the folder ./Arduino_ROOT/Library/.

Template

#include <IRremote.h>
 
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
 
void setup() {
    Serial.begin(9600);
    // In case the interrupt driver crashes on setup, give a clue
    // to the user what's going on.
    Serial.println("Enabling IRin");
    irrecv.enableIRIn(); // Start the receiver
    Serial.println("Enabled IRin");
}
 
void loop() {
    if (irrecv.decode(&results)) {
        Serial.println(results.value, HEX);
        irrecv.resume(); // Receive the next value
    }
    delay(100);
}

Rewrite

Now we need to implement the function: Process the corresponding variable in the fan program after matching to the correct encoding. We use a 21-key remote control to transmit infrared signals. The decoded code from different remote controllers may be different. You can google what you need or try it out with examples.
In the infrared module my final code is like this:

#include <IRremote.h>
 
const int irReceiverPin = 11;
 
IRrecv irrecv(irReceiverPin);
decode_results results;
 
void setup() {
 
    /* ... */
 
    Serial.begin(9600);
    irrecv.enableIRIn();
}
 
void loop() {
 
    /* ... */
 
    if (irrecv.decode(&results)) {
        /* 
        Serial.print("Detail Information: irCode:");
        Serial.print(results.value, HEX);
        Serial.print(",bits:");
        Serial.println(results.bits);
        */
         
        switch (results.value) {
            case 0xFF22DD:
                Serial.println("Button |<< had been pressed.");
                fanspeed = fanspeed - 1;
                if (fanspeed <= 0) {
                    fanspeed = 0;
                    servoSwitch = 0;
                    angle = myservo.read();
                }
                Serial.println("Finished.");
                break;
            case 0xFF02FD:
                Serial.println("Button >>| has been pressed.");
                fanspeed = fanspeed + 1;
                if (fanspeed >= 3) {
                    fanspeed = 3;
                }
                Serial.println("Finished.");
                break;
            case 0xFF629D:
                Serial.println("Button CH has been pressed.");
                fanspeed = 0;
                servoSwitch = 0;
                angle = myservo.read();
                Serial.println("Finished.");
                break;
            case 0xFF30CF:
                Serial.println("Button 1 has been pressed.");
                fanspeed = 1;
                Serial.println("Finished.");
                break;
            case 0xFF18E7:
                Serial.println("Button 2 has been pressed.");
                fanspeed = 2;
                Serial.println("Finished.");
                break;
            case 0xFF7A85:
                Serial.println("Button 3 has been pressed.");
                fanspeed = 3;
                Serial.println("Finished.");
                break;
            case 0xFFE21D:
                Serial.println("Button CH+ has been pressed.");
                if (fanspeed != 0) {
                    servoSwitch = 1;
                    Serial.println("Start servo. Finished.");
                }
                else
                    Serial.println("Start failed, start fan firstly.");
                break;
            case 0xFFA25D:
                Serial.println("Button CH- has been pressed.");
                servoSwitch = 0;
                angle = myservo.read();
                Serial.println("Finished.");
                break;
        }
         
        delay(600);
        /* Serial.println("Delay is end, try to reset the irReceiver."); */
        while (!irrecv.isIdle());
        irrecv.resume();
        /* Serial.println("Reset Success!"); */
        delay(500);
    }
}

 

Overall

Final code

If you understand the above code, congratulations, the final code will look like this:

#include <IRremote.h>
#include <Servo.h>
 
const int motorIn1 = 5;
const int motorIn2 = 6;
const int buttonPin = 8;
const int irReceiverPin = 11;
const int ledPin = 13;
 
int fanspeed = 0;
#define rank1 150
#define rank2 200
#define rank3 250
int btState;
int lastbtState = LOW;
long lastDebounceTime = 0;
long debounceDelay = 50;
 
Servo myservo;
int servoSwitch = 0;
int angle = 90;
int anglestep = 1;                           // Here is where you need to customize.
 
IRrecv irrecv(irReceiverPin);
decode_results results;
 
void setup() {
    pinMode(buttonPin,INPUT);
    pinMode(ledPin,OUTPUT);
    pinMode(motorIn1,OUTPUT);
    pinMode(motorIn2,OUTPUT);
    myservo.attach(3);
    Serial.begin(9600);
    irrecv.enableIRIn();
}
 
void loop() {
    // Key switch module code
    int reading = digitalRead(buttonPin);
    if (reading != lastbtState) {
        lastDebounceTime = millis();
    }
    if ((millis() - lastDebounceTime) > debounceDelay) {
        if (reading != btState) {
            btState = reading;
            if (btState == HIGH) {
                digitalWrite(ledPin,HIGH);
                fanspeed = fanspeed + 1;
                if (fanspeed >= 4) {
                    fanspeed = 0;
                    servoSwitch = 0;
                    angle = myservo.read();
                }
            }
            else
                digitalWrite(ledPin,LOW);
        }
    }
    lastbtState = reading;
    
    // Infrared remote control module code
    if (irrecv.decode(&results)) {
        /* 
        Serial.print("Detail Information: irCode:");
        Serial.print(results.value, HEX);
        Serial.print(",bits:");
        Serial.println(results.bits);
        */
        switch (results.value) {
            case 0xFF22DD:
                Serial.println("Button |<< had been pressed.");
                fanspeed = fanspeed - 1;
                if (fanspeed <= 0) {
                    fanspeed = 0;
                    servoSwitch = 0;
                    angle = myservo.read();
                }
                Serial.println("Finished.");
                break;
            case 0xFF02FD:
                Serial.println("Button >>| has been pressed.");
                fanspeed = fanspeed + 1;
                if (fanspeed >= 3) {
                    fanspeed = 3;
                }
                Serial.println("Finished.");
                break;
            case 0xFF629D:
                Serial.println("Button CH has been pressed.");
                fanspeed = 0;
                servoSwitch = 0;
                angle = myservo.read();
                Serial.println("Finished.");
                break;
            case 0xFF30CF:
                Serial.println("Button 1 has been pressed.");
                fanspeed = 1;
                Serial.println("Finished.");
                break;
            case 0xFF18E7:
                Serial.println("Button 2 has been pressed.");
                fanspeed = 2;
                Serial.println("Finished.");
                break;
            case 0xFF7A85:
                Serial.println("Button 3 has been pressed.");
                fanspeed = 3;
                Serial.println("Finished.");
                break;
            case 0xFFE21D:
                Serial.println("Button CH+ has been pressed.");
                if (fanspeed != 0) {
                    servoSwitch = 1;
                    Serial.println("Start servo. Finished.");
                }
                else
                    Serial.println("Start failed, start fan firstly.");
                break;
            case 0xFFA25D:
                Serial.println("Button CH- has been pressed.");
                servoSwitch = 0;
                angle = myservo.read();
                Serial.println("Finished.");
                break;
        }
        delay(600);
        /* Serial.println("Delay is end, try to reset the irReceiver."); */
        while (!irrecv.isIdle());
        irrecv.resume();
        /* Serial.println("Reset Success!"); */
    }
    
    // Fan control
    switch (fanspeed) {
        case 1:
            analogWrite(motorIn1, 0);
            analogWrite(motorIn2, rank1);
            break;
        case 2:
            analogWrite(motorIn1, 0);
            analogWrite(motorIn2, rank2);
            break;
        case 3:
            analogWrite(motorIn1, 0);
            analogWrite(motorIn2, rank3);
            break;
        default:
            analogWrite(motorIn1, 0);
            analogWrite(motorIn2, 0);
            break;
    }
    
    // Servo control
    switch (servoSwitch) {
        case 1:
            myservo.write(angle);
            delay(15);                       // Here is where you need to customize.
            angle = angle + anglestep;
            if (angle == 160 || angle == 20) // Here is where you need to customize.
                anglestep = -anglestep;
            break;
        case 0:
            angle = myservo.read();
            break;
    }
}
 

I still need to say a little more here. To make your fan run smoothly, you need to customize some options. The first one is a variable anglestep ,the other is the delay time generated by the function delay();. I added some comment to the overall code and hope that will help you. Another tip is that you should pay attention to how the motor is connected to the servo. Don't simply tie them together, you need some cushioning to alleviate the effects of motor vibration on the servo.

Finished product performance

 Placeholder

 

Hahaha… In fact, some parts of this article used translation to write. Another purpose of my writing this article is to help myself learn English. So that I can read English science and technology literature conveniently later. As we all know, translation always goes wrong, so, if there's anything wrong in the article, please point out! Thanks a lot!

本文链接:https://monsterx.cn/Microchips/Arduino-SG90-Motor130-IR.html
本站文章除特殊说明外全部由 MonsterX 原创发布,未经允许禁止以任何形式转载。
如果您发现以上内容含有任何引起不适/侵犯权利/违反法律的内容,请立即 联系站长 进行处理。

选择表情


    Nroy
    Nroy  2019-06-01, 11:48

    瞧瞧这是给人看的东西吗?(用啥英语啊) 24.png

      MonsterX
      MonsterX  2019-06-01, 11:56

      看国外的博客用英文写感觉好有意思哦哈哈哈 16.png 我当然也要玩一玩啦略略略 147.png