ESP32使用Servo模擬連點器程式

 
前陣子有需要一個可以自動點擊的機器來測試按鍵功能,除了上網找了連點器外,也有想要自己用Arduino自己做,於是先用線上模擬做看看~
 
主要功能: 三個伺服馬達模擬按鍵動作,0度時預備位置,180度按下按鍵位置,S1按完等T1,換S2,再等T2換S3,S3按完等T3,循環回S1
 
接線圖使用TinkerCAD 畫的,點擊連結應該是可以連上,是可以用Arduino模擬的
https://www.tinkercad.com/things/f2HlzRbvnyX-servo?sharecode=dLKIbUcxdHLiVvP8Reyzi1M5i1_wu5nTLnJ8-nhg9u0

模擬完,我用ESP32改寫,使用OneButton.h處理按鍵彈跳,按鍵有下拉電阻
OneButton button1(ButStr, false);  //  要用false搭配下拉電阻,上拉改true
Servo 函數庫我是使用ESP32_Servo.h ,(http://bit.ly/2tmQLCz),超圖解ESP32 趙老師推薦
其中,可能我用的Servo比較會抖,0度時抖的很嚴重,所以把角度都改縮小(10-170度)就不會抖了
 
 
 
完整程式如下:
 
//ESP32用腳改用  VR , 34,35,36 , LED 18,開始 16,停17,Servo 25,26,27
//Servo 常在0,180度抖,所以都轉到10~170就好

#include <ESP32_Servo.h>
#include <OneButton.h>
Servo myS1 , myS2 , myS3; //建立3個SERVO物件
int servoDelay1, servoDelay2, servoDelay3;    // VR給的時間
int ButOn =0 , ButOff =0 , status =0 ,OnLed =18;
int VR1 =34, VR2 =35, VR3=36, ButStr =16, ButStop =17 ;
int S1Pin = 25, S2Pin = 26, S3Pin = 27;
unsigned long previousMillis = 0;
unsigned long startTime = 0;
int state = 0; // 0: idle, 1: S1, 2: S2, 3: S3
int ADC_Max = 4096;    // This is the default ADC max value on the ESP32 (12 bit ADC width);
                        // this width can be set (in low-level oode) from 9-12 bits, for a
                        // a range of max values of 512-4096

OneButton button1(ButStr, false);  //true按下為低電平,false按下為高電平(按鈕接 +, 輸入腳和下拉電阻, -)
OneButton button2(ButStop, false);


void setup()
{
  Serial.begin(115200);
  while (!Serial) {
      // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.println("Starting TwoButtons...");
  pinMode(VR1, INPUT);
  pinMode(VR2, INPUT);
  pinMode(VR3, INPUT);
  //pinMode(ButStr, INPUT);  // 啟動
  //pinMode(ButStop, INPUT);  // 停止
  pinMode(OnLed, OUTPUT); //運行LED燈
  myS1.attach(S1Pin, 500, 2400);    // 會抖到卡住
  myS2.attach(S2Pin, 500, 2400);
  myS3.attach(S3Pin, 500, 2400);
 
  button1.attachClick(click1);
  button2.attachClick(click2);
 
  myS1.write(10);    // 歸零
  myS2.write(10);    // 歸零
  myS3.write(10);    // 歸零
  // 初始化狀態變量
  state = 0; // 初始狀態為 idle
  startTime = millis(); // 記錄程式啟動時間
 
}

void loop()
{
 
  servoDelay1 = map(analogRead(VR1),0 ,ADC_Max, 1 ,12);  // T1設1~16秒
  servoDelay2 = map(analogRead(VR2),0 ,ADC_Max, 1 ,12); // T1設1~8秒
  servoDelay3 = map(analogRead(VR3),0 ,ADC_Max, 1 ,12); // T1設1~4秒
  Serial.print("T1=");
  Serial.println(servoDelay1);
  Serial.print("T2=");
  Serial.println(servoDelay2);
  Serial.print("T3=");
  Serial.println(servoDelay3);
 
 
  button1.tick();
  button2.tick();
  ServoMotion();
  delay(10);
}

void ServoMotion() {
  unsigned long currentMillis = millis();
  if (status == 1) {
    switch (state) {
      case 0:
        // 啟動S1,先轉到180度再轉回0度,然後開始計時
        if (currentMillis - startTime >= servoDelay1 * 1000) {
          state = 1;
          startTime = currentMillis;
          Serial.println("MyS1 Servo ON");
          myS1.write(170);
          unsigned long moveStartTime = millis();
          while (millis() - moveStartTime < 500) {
            // 等待100ms
          }
          myS1.write(10);
          startTime = millis(); // 更新起始時間
        }
        break;
      case 1:
        // 啟動S2
        if (currentMillis - startTime >= servoDelay2 * 1000) {
          state = 2;
          startTime = currentMillis;
          Serial.println("MyS2 Servo ON");
          myS2.write(170);
          unsigned long moveStartTime = millis();
          while (millis() - moveStartTime < 500) {
            // 等待100ms
          }
          myS2.write(10);
          startTime = millis(); // 更新起始時間
        }
        break;
      case 2:
        // 啟動S3
        if (currentMillis - startTime >= servoDelay3 * 1000) {
          state = 0;
          startTime = currentMillis;
          Serial.println("MyS3 Servo ON");
          myS3.write(170);
          unsigned long moveStartTime = millis();
          while (millis() - moveStartTime < 500) {
            // 等待100ms
          }
          myS3.write(10);
          startTime = millis(); // 更新起始時間
        }
        break;
    }
  } else {
    // 停止狀態,重置所有伺服馬達和計時器用OneButton後這都可以拿掉了
    //myS1.write(10);
    //myS2.write(10);
    //myS3.write(10);
    state = 0;
    //startTime = 0;
  }
}

void click1() {
  Serial.print("Button 1 click, value1 = ");
  status=1; //  執行循環
  digitalWrite(OnLed, HIGH);  //運行燈 亮
  Serial.println("Start Motion");
  //ServoMotion();
}

void click2() {
  Serial.println("Button 2 click.");
  status=0 ;  //  停止循環
  digitalWrite(OnLed, LOW); //運行燈 減
  Serial.println("Stop Motion");
  myS1.write(10);
  myS2.write(10);
  myS3.write(10);
  startTime = 0;
}


下圖是我用Arduino IDe編輯的程式片段

 
下面是實際用麵面包板測試程式影片,感謝收看
 

 

程式編輯心得:
1 .使用millis(),比delay()好,不會因暫停而影響input
2.函數庫還是老樣子,用順就不要更新,OneButton 和wifManager真是好東西,下次我要再加進去
3.變數名、數量可以再改善一下
4.當遇到困難時除了上網找解答,翻一下超圖解ESP32、Arduino,趙老師都幫你想好了
5.Gemini和Codeium是寫程式的好幫手,但是語法以外的錯誤還是要自己去查

 
 本文同時發表於 :
這封郵件來自 Evernote。Evernote 是您專屬的工作空間,免費下載 Evernote

留言

這個網誌中的熱門文章

FansTracker APP 粉絲追蹤

DuplicateSlayerPro副本刪檔神器

i-Rocks K85R 極光藍 機械鍵盤