使用ESP32+舵機+螢石攝像頭制作一個遠程逗貓棒

準備的工具:
1.Arduino IDE :https://www.arduino.cc(下載安裝)
2.一臺云主機(包含域名)
3.一個螢石云攝像頭(一定要螢石云的)
4.ESP32開發(fā)板
5.S3003舵機
6.杜邦線若干
7.逗貓棒
8.Arduino舵機庫:https://github.com/arduino-libraries/Servo
9.一個能用的DDNS

預(yù)覽地址:http://pan.myzhazha.xyz:11452

首先嵌言,下載安裝Arduino IDE并安裝
打開Arduino IDE選擇文件>首選項>附加開發(fā)板管理器網(wǎng)址 右側(cè)的小圖標
填入https://dl.espressif.com/dl/package_esp32_index.json

添加ESP32開發(fā)板地址

然后選擇工具>開發(fā)板>開發(fā)板管理器


開發(fā)板管理器

等它下載完索引之后在搜索框輸入ESP32然后安裝


搜索ESP32

把下載好的Arduino舵機庫文件夾復(fù)制到電腦C:\Users\用戶名\Documents\Arduino\libraries\文件夾下赤套,然后重新打開Arduino IDE

舵機庫

打開Arduino IDE之后把預(yù)設(shè)的代碼刪除访递,把以下代碼復(fù)制到Arduino IDE里鞍时、
注意把wifi名稱和密碼改為你自己的

#include <WiFi.h>

const int servoPin = 13;  /* 設(shè)置控制舵機信號引腳為D13 */

const char* ssid = "WIFI-SSID"; /* 你的wifi名稱懂版,不能為中文 */
const char* password = "password"; /*你的wifi密碼 */

int dutyCycle = 0;
//int position1 = 0;

/* Setting PWM properties */
const int PWMFreq = 50;
const int PWMChannel = 0;
const int PWMResolution = 8;
const int MAX_DUTY_CYCLE = (int)(pow(2, PWMResolution) - 1);

WiFiServer espServer(80); /* Instance of WiFiServer with port number 80 */
/* 80 is the Port Number for HTTP Web Server */

/* A String to capture the incoming HTTP GET Request */
String request;

void setup()
{  
  Serial.begin(115200);
  ledcSetup(PWMChannel, PWMFreq, PWMResolution);
  /* Attach the LED PWM Channel to the GPIO Pin */
  ledcAttachPin(servoPin, PWMChannel);
  ledcWrite(PWMChannel, dutyCycle);

  Serial.print("\n");
  Serial.print("Connecting to: ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA); /* Configure ESP32 in STA Mode */
  WiFi.begin(ssid, password); /* Connect to Wi-Fi based on the above SSID and Password */
  while(WiFi.status() != WL_CONNECTED)
  {
    Serial.print("*");
    delay(100);
  }
  Serial.print("\n");
  Serial.print("Connected to Wi-Fi: ");
  Serial.println(WiFi.SSID());
  delay(100);
  /* The next four lines of Code are used for assigning Static IP to ESP32 */
  /* Do this only if you know what you are doing */
  /* You have to check for free IP Addresses from your Router and */
  /* assign it to ESP32 */
  /* If you are comfortable with this step, */
  /* please un-comment the next four lines and make necessary changes */
  /* If not, leave it as it is and proceed */
  //IPAddress ip(192,168,1,6);   
  //IPAddress gateway(192,168,1,1);   
  //IPAddress subnet(255,255,255,0);   
  //WiFi.config(ip, gateway, subnet);
  delay(2000);
  Serial.print("\n");
  Serial.println("Starting ESP32 Web Server for Servo Control...");
  espServer.begin(); /* Start the HTTP web Server */
  Serial.println("ESP32 Servo Web Server Started");
  Serial.print("\n");
  Serial.print("The URL of ESP32 Servo Web Server is: ");
  Serial.print("http://");
  Serial.println(WiFi.localIP());
  Serial.print("\n");
  Serial.println("Use the above URL in your Browser to access ESP32 Servo Web Server\n");
}
void loop()
{
  WiFiClient client = espServer.available(); /* Check if a client is available */
  if(!client)
  {
    return;
  }

  Serial.println("New Client!!!");
  boolean currentLineIsBlank = true;
  while (client.connected())
  {
    if (client.available())
    {
      char c = client.read();
      request += c;
      Serial.write(c);
        /* If you've gotten to the end of the line (received a newline */
        /* character) and the line is blank, the http request has ended, */
        /* so you can send a reply */
      if (c == '\n' && currentLineIsBlank)
      {
        client.println("HTTP/1.1 200 OK");
        client.println("Content-type:text/html");
        client.println("Connection: close");
        client.println();

        client.println("<!DOCTYPE html>");
        client.println("<html>");
        
        client.println("<head><meta charset='utf8'\name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
        client.println("<link rel=\"icon\" href=\"data:,\">");

        /* CSS Styling for Text and Slider */
        
        client.println("<style>body { font-family: \"Courier New\"; margin-left:auto; margin-right:auto; text-align:center;}");
        
        client.println(".slidecontainer { width: 100%;}");
        client.println(".slider { -webkit-appearance: none;");
        client.println("width: 30%; height: 20px; background: #d3d3d3;");
        client.println("outline: none; opacity: 0.7; -webkit-transition: .2s; transition: opacity .2s;}");
        client.println(".slider:hover { opacity: 1; }");

        client.println(".slider::-webkit-slider-thumb { -webkit-appearance: none;");
        client.println("appearance: none; width: 15px; height: 28px;");
        client.println("border-radius: 30%; background: #4CAF50; cursor: pointer;}");
        client.println(".slider::-moz-range-thumb { width: 25px; height: 25px; background: #4CAF50; cursor: pointer;}</style>");
        
        client.println("<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>");
        /*Actual Web Page */
        client.println("</head><body><h2>逗貓棒??</h2>");
        client.println("<p>在線逗貓棒</p>");
        
        client.println("<input type=\"range\" min=\"0\" max=\"90\" class=\"slider\" id=\"servoRange\" onchange=\"servo(this.value)\"/>");
        client.println("<p>角度: <span id=\"servoPos\"></span></p>");
        client.println("<script>");
        client.println("var slider = document.getElementById(\"servoRange\");");
        client.println("var output = document.getElementById(\"servoPos\");");
        client.println("output.innerHTML = slider.value;");
        client.println("slider.oninput = function(){output.innerHTML = this.value;}");
        client.println("$.ajaxSetup({timeout:1000}); function servo(angle) { ");
        client.println("$.get(\"/servovalue=\" + angle); {Connection: close};}</script>");
                
        client.println("</body></html>");   
        
        /* The request will be in the form of 
         * GET /servovalue=143 /HTTP/1.1*/
        if(request.indexOf("GET /servovalue=") != -1)
        {
          int position1 = request.indexOf('='); /* Find out the position of '=' in the request string */
          String angleStr = request.substring(position1+1); /* Next 2/3 characters inform the desired angle */
          int angleValue = angleStr.toInt();
          dutyCycle = map(angleValue, 0, 180, 5, 32);
          ledcWrite(PWMChannel, dutyCycle); 
        }
        client.println();
        break;
      }

        if(c == '\n')
        {
          currentLineIsBlank = true;
        }
        else if(c != '\r')
        {
          currentLineIsBlank = false;
        }
        //client.print("\n");
    }
  }
 
  delay(1);
  request = "";
  //client.flush();
  client.stop();
  Serial.println("Client disconnected");
  Serial.print("\n");
}

然后選擇文件-保存响疚,隨便保存到一個位置
保存后選擇
工具>開發(fā)板>ESP32 Arduino>ESP32 Dev Module
此時把ESP32模組插上電腦并裝好串口驅(qū)動自赔,然后在工具>端口選擇你的ESP32模組所在的端口號
然后點擊圖中的圖標進行固件編譯上傳


上傳

在下方的窗口等待進度完成驹碍,完成后斷開USB連接并插到充電頭上(舵機啟動時可能會造成電腦USB損壞)


上傳完成

此時把你的舵機的VCC端連接到ESP32模組的VIN引腳怀伦,GND連接到GND引腳脆烟,舵機信號引腳連接到D13引腳

強烈建議舵機使用獨立供電!否則容易燒毀ESP32模組的電源電路

登錄你的路由器后臺空镜,查看連接的設(shè)備浩淘,找到名為espressif的設(shè)備,看一下IP地址是多少吴攒,然后在瀏覽器里輸入該IP地址并訪問张抄,就進入到了舵機的控制頁面

舵機控制

此時點擊滑動條查看舵機是否轉(zhuǎn)動,轉(zhuǎn)動說明正常洼怔,不轉(zhuǎn)動檢查線路連接是否錯誤

然后把該ESP32模組的頁面使用DDNS和端口映射署惯,映射到公網(wǎng),注意端口不要太辛土ァ(最好10000以上)

新建一個文本文件极谊,把以下內(nèi)容復(fù)制進去

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link rel="icon" href="data:,">
<style>
body { font-family: "Courier New"; margin-left:auto; margin-right:auto; text-align:center;}
.slidecontainer { width: 720px;}
.slider { -webkit-appearance: none;
width: 61%; height: 20px; background: #d3d3d3;
outline: none; opacity: 0.7; -webkit-transition: .2s; transition: opacity .2s;}
.slider:hover { opacity: 1; }
.slider::-webkit-slider-thumb { -webkit-appearance: none;
appearance: none; width: 15px; height: 28px;
border-radius: 30%; background: #4CAF50; cursor: pointer;}
.slider::-moz-range-thumb { width: 25px; height: 25px; background: #4CAF50; cursor: pointer;}

</style>
<script src="./js/jquery-3.6.0.min.js"></script>
<title>逗貓棒</title>
<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://#/hm.js?0f723813e10da06579f73257eab9cb6a";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script>

</head>
<body>  
    <h2>逗貓棒??</h2>
    <tr>
      <td width="720" align="center" valign="middle"><p>
               
<iframe
  src="https://open.ys7.com/ezopen/h5/iframe?url=ezopen://open.ys7.com/D07329191/1.live&autoplay=1&audio=1&accessToken=at.3fv362axceoqng5u2dwh6ook9s0ab0o2-7hz4j5eple-1gktksc-liaffjlcm&templete=0"
  width="720"
  height="405"
  id="ysopen"
  allowfullscreen
>
</iframe>
    <p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p>
    <span style=""><strong>實時畫面(延時1s</strong></span>)</p>
         
<input type="range" min="0" max="90" class="slider" id="servoRange" onchange="servo(this.value)">

<p>角度: <span id="servoPos">78</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;開放時間:周一~周六 上午9:00~12:00&nbsp; 下午 14:00~18:00&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;更多逗貓玩法正在開發(fā)中,敬請期待...&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</p>
<p>在線逗貓棒by:小渣渣</p>
<script>
var slider = document.getElementById("servoRange");
var output = document.getElementById("servoPos");
    output.innerHTML = slider.value;
    slider.oninput = function(){output.innerHTML = this.value;}
    $.ajaxSetup({timeout:1000}); function servo(angle) { 
    $.get("http://pan.myzhazha.xyz:23641/servovalue=" + angle); {Connection: close};}

</script>  
      </td>
    </tr>
  
</body>
</html>

將準備好的螢石攝像頭綁定手機并在攝像頭設(shè)置里關(guān)閉視頻加密
關(guān)閉后訪問螢石云開放平臺注冊成為個人開發(fā)者
螢石云開放平臺地址:https://open.ys7.com/
注冊成共后進入左側(cè)的我的賬號>應(yīng)用信息>創(chuàng)建應(yīng)用
應(yīng)用名稱隨便寫
行業(yè)寵物關(guān)愛
勾選:我已購買軟件安岂,無需自行開發(fā)
軟件名稱隨便寫

應(yīng)用信息

然后進入我的資源>設(shè)備列表轻猖,此時應(yīng)該能看到綁定的攝像頭,點擊右側(cè)的監(jiān)控地址
在打開的頁面選擇:前往輕應(yīng)用視頻學(xué)習(xí)了解


前往輕應(yīng)用視頻學(xué)習(xí)了解

在打開的頁面選擇下方的選擇設(shè)備


選擇設(shè)備

按照要求填入信息
建議播放類型改為預(yù)覽域那,清晰度流暢咙边,播放器模板選擇極簡版
提交后右側(cè)會出現(xiàn)代碼示例,把iframe標簽里的代碼復(fù)制并替換到剛才的index.html文件里的iframe標簽里
注意:此處的AccessToken的值每7天螢石云開放平臺會自動更改一次次员,所以每到7天請自行更改败许,或者自己寫腳本進行自動更改,螢石云開放平臺有詳細的接口調(diào)用文檔

iframe標簽

!替換](https://upload-images.jianshu.io/upload_images/4596711-a12e822a50a5a0f4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/720)

注意此處要把width的值改為720淑蔚, height的值改為405

然后把index.html文件的此處的地址改為你的ESP32模組的地址DDNS映射之后的域名+端口


域名+端口

下載該js文件
鏈接:https://pan.baidu.com/s/1uRNTodbiLCislj-t7YVk0A
提取碼:2333

在你的WEB服務(wù)器里創(chuàng)建一個文件夾專門放置該網(wǎng)頁市殷,把上面網(wǎng)盤里的文件下下載并解壓,在網(wǎng)頁文件夾里創(chuàng)建js文件夾刹衫,把jquery-3.6.0.min.js文件上傳進去醋寝,再把index.html文件上傳到與js文件夾同一目錄
上傳完成后使用瀏覽器打開你的WEB服務(wù)器地址查看能否正常訪問搞挣,攝像頭畫面是否正常加載,舵機控制是否正常
(最好使用手機+數(shù)據(jù)流量來驗證)

所有功能都正常就把逗貓棒綁在舵機上面并把舵機和攝像頭安裝在合適的位置
我是使用3D打印打印了一個舵機支架綁在了桌子腿上

模型
支架

3D模型下載鏈接
鏈接:https://pan.baidu.com/s/1XZFJNT7_v9iZkD0l1SiTQA
提取碼:2333

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末音羞,一起剝皮案震驚了整個濱河市柿究,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌黄选,老刑警劉巖蝇摸,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異办陷,居然都是意外死亡貌夕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門民镜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啡专,“玉大人,你說我怎么就攤上這事制圈∶峭” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵鲸鹦,是天一觀的道長慧库。 經(jīng)常有香客問我,道長馋嗜,這世上最難降的妖魔是什么齐板? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮葛菇,結(jié)果婚禮上甘磨,老公的妹妹穿的比我還像新娘。我一直安慰自己眯停,他們只是感情好济舆,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著莺债,像睡著了一般滋觉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上九府,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天椎瘟,我揣著相機與錄音覆致,去河邊找鬼侄旬。 笑死,一個胖子當(dāng)著我的面吹牛煌妈,可吹牛的內(nèi)容都是我干的儡羔。 我是一名探鬼主播宣羊,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼汰蜘!你這毒婦竟也來了仇冯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤族操,失蹤者是張志新(化名)和其女友劉穎苛坚,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體色难,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡泼舱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了枷莉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娇昙。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖笤妙,靈堂內(nèi)的尸體忽然破棺而出冒掌,到底是詐尸還是另有隱情,我是刑警寧澤蹲盘,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布股毫,位于F島的核電站,受9級特大地震影響召衔,放射性物質(zhì)發(fā)生泄漏皇拣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一薄嫡、第九天 我趴在偏房一處隱蔽的房頂上張望氧急。 院中可真熱鬧,春花似錦毫深、人聲如沸吩坝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钉寝。三九已至,卻和暖如春闸迷,著一層夾襖步出監(jiān)牢的瞬間嵌纲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工腥沽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逮走,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓今阳,卻偏偏與公主長得像师溅,于是被迫代替她去往敵國和親茅信。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容