60元成本打造esp8266四足机器人

一、材料介绍

1.18650电池2个每个3元

我用的电池是普通18650,买的旧笔记本电池拆出来的。实际使用下来感觉四足机器人需要的电流不大,不用像我一样买18650,容量不是太小的电池都可以,而且没有必要用两节,我这是为了看起来整齐。

3875a16ddca049d5ab5eb0385918e206.jpg

2.18650电池盒2个每个1元

根据你所用的电池决定,如果不用18650电池的话可以不要这个电池盒。

3. esp8266(nodemcu)10元

我使用的是比较常见的开发板,只要是esp8266都可以用,不必要追求某个型号。如果想自己画板子的话也可以用esp12那种模组。

3d4d5aa904f44325a4a20e6dfcb1b5d0.jpg

4. pca9685舵机扩展板

淘宝上的pca9685都比较贵,这是我当时能找到的最便宜的。不知道现在还有没有卖,也可自己去找找有没有价格更低的。

ca0ce49807784f24adc28fa7e84d6b85.jpg

5.升压板

叠加签到红包以后1.25元,我的方法是将两节18650并联后升压到5v,其实一节也可以。主要是将电池的3.7v升到5v,用来驱动舵机板。

c81d56126d8f46d5a26d9583b100f0b7.jpg

6.3d打印

我不是很了解市面上3d打印的价格,因为我自己买了台打印机,所以这部分价格没有算进去。之前230包邮在闲鱼买的打印机,pla耗材是22块钱1千克。打印这个四足机器人总共也没用多少克材料,对我自己来说几乎没什么成本。

7. sg90舵机8个每个3.5元

舵机价格还是比较贵的,我的方法是用芭芭农场3元红包购买,这样可以3.5元买到。正常价格应该在5元左右吧。舵机必须要使用180度的,只有180度的舵机才可以固定角度,360度的舵机只能控制方向和旋转速度。

5f574fb70ecc492b8e01efb6943b7e33.jpg

二、代码

#include <ESP8266WiFi.h>
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
 
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
 
const char* ssid = "WIFI名称";     
const char* password = "WIFI密码"; 
 
WiFiServer server(80);  //http的服务端口
 
void setup() {
  pinMode(16, OUTPUT);  //用于连接Wi-Fi的LED指示灯
  digitalWrite(16, LOW);
  Serial.begin(115200);
  pwm.begin();
  pwm.setPWMFreq(60); //伺服电机以60hz刷新率工作
  delay(1000);
 
  //连接到无线网络
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print("-");
  }
  Serial.println("");
  Serial.println("WiFi connected");
 
  //启动服务器
  server.begin();
  Serial.println("Server started");
 
  //打印IP地址
  Serial.print("Use this URL to connect: ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.println("/");
 
  digitalWrite(16, HIGH);
}
 
void loop() {
  //检查客户端是否已连接
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  //等到客户端发送一些数据
  Serial.println("new client");
  while (!client.available()) {
    delay(1);
  }
 
  //阅读请求的第一行
  String request = client.readStringUntil('\r');
  Serial.println(request);
  client.flush();
 
  //匹配请求
  if (request.indexOf("/S") != -1) {
    sleep();
  }
  if (request.indexOf("/W") != -1) {
    normal();
  }
  if (request.indexOf("/F") != -1) {
    normal();
    forward();
    forward();
    forward();
    forward();
  }
  if (request.indexOf("/B") != -1) {
    normal();
    backward();
    backward();
    backward();
    backward();
  }
  if (request.indexOf("/L") != -1) {
    normal();
    left();
    left();
  }
  if (request.indexOf("/R") != -1) {
    normal();
    right();
    right();
  }
  if (request.indexOf("/H") != -1) {
    normal();
    hello();
  }
 if (request.indexOf("/C") != -1) {
    normal();
    come();
  }
  //返回响应
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println(""); 
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head>");
  client.println("<style>");
  client.println(".button{");
/*----------网页设计----------*/
  client.println("background-color: #4CAF50; /* GREEN */");
  client.println("width: 48%;");
  client.println("border: none;");
  client.println("color: white;");
  client.println("padding: 50px 40px;");
  client.println("text-align: center;");
  client.println("text-decoration: none;");
  client.println("display: inline-block;");
  client.println("font-size: 50px;");
  client.println("margin: 4px 2px;");
  client.println("cursor: pointer;");
  client.println("border-radius: 12px;");
  client.println("}");
 
  client.println("</style>");
  client.println("</head>");
  client.println("<body bgcolor=black>");
 
  client.println("<button class=\"button\" onclick=\"window.location.href='/F';\">前进</button>");
  client.println("<button class=\"button\" onclick=\"window.location.href='/B';\">后退</button>");
  client.println("<br></br>");
  client.println("<button class=\"button\" onclick=\"window.location.href='/L';\">左转</button>");
  client.println("<button class=\"button\" onclick=\"window.location.href='/R';\">右转</button>");
  client.println("<br></br>");
  client.println("<button class=\"button\" onclick=\"window.location.href='/S';\">睡觉</button>");
  client.println("<button class=\"button\" onclick=\"window.location.href='/W';\">正常</button>");
  client.println("<br></br>");
  client.println("<button class=\"button\" onclick=\"window.location.href='/H';\">你好</button>");
  client.println("<button class=\"button\" onclick=\"window.location.href='/C';\">来啊</button>");
  client.println("</body>");
  client.println("</html>");
 
  delay(1);
  Serial.println("Client disconnected");
  Serial.println("");
}
 
/*----------动作设计----------*/
 
// |   7  |             |   6  |
//  ----- -----   ----- -----
//       |  3   | |  2   |
//        -----   -----
//       |   1  | |  0   |
//  ----- -----   ----- -----
// |  5   |             |  4   |
 
void sleep() 
{
  pwm.setPWM(4, 0, 280);
  delay(100);
  pwm.setPWM(5, 0, 280);
  delay(100);
  pwm.setPWM(6, 0, 280);
  delay(100);
  pwm.setPWM(7, 0, 280);
  delay(100);
  pwm.setPWM(0, 0, 510);
  delay(100);
  pwm.setPWM(1, 0, 100);
  delay(100);
  pwm.setPWM(2, 0, 100);
  delay(100);
  pwm.setPWM(3, 0, 510);
}
 
void normal() 
{
  pwm.setPWM(0, 0, 370);
  delay(100);
  pwm.setPWM(1, 0, 190);
  delay(100);
  pwm.setPWM(2, 0, 190);
  delay(100);
  pwm.setPWM(3, 0, 370);
  delay(100);
  pwm.setPWM(4, 0, 510);
  delay(100);
  pwm.setPWM(7, 0, 100);
  delay(100);
  pwm.setPWM(6, 0, 510);
  delay(100);
  pwm.setPWM(5, 0, 100);
}
 
void left()
{
  pwm.setPWM(4, 0, 370);
  delay(100);
  pwm.setPWM(0, 0, 510);
  delay(100);
  pwm.setPWM(4, 0, 510);
  delay(100);
  pwm.setPWM(6, 0, 370);
  delay(100);
  pwm.setPWM(2, 0, 280);
  delay(100);
  pwm.setPWM(6, 0, 510);
  delay(100);
  pwm.setPWM(7, 0, 190);
  delay(100);
  pwm.setPWM(3, 0, 510);
  delay(100);
  pwm.setPWM(7, 0, 100);
  delay(100);
  pwm.setPWM(5, 0, 190);
  delay(100);
  pwm.setPWM(1, 0, 280);
  delay(100);
  pwm.setPWM(5, 0, 100);
  delay(100);
  pwm.setPWM(0, 0, 370);
  pwm.setPWM(2, 0, 190);
  pwm.setPWM(3, 0, 370);
  pwm.setPWM(1, 0, 190);
}
 
void right()
{
  pwm.setPWM(5, 0, 190);
  delay(100);
  pwm.setPWM(1, 0, 100);
  delay(100);
  pwm.setPWM(5, 0, 100);
  delay(100);
  pwm.setPWM(7, 0, 190);
  delay(100);
  pwm.setPWM(3, 0, 280);
  delay(100);
  pwm.setPWM(7, 0, 100);
  delay(100);
  pwm.setPWM(6, 0, 370);
  delay(100);
  pwm.setPWM(2, 0, 100);
  delay(100);
  pwm.setPWM(6, 0, 510);
  delay(100);
  pwm.setPWM(4, 0, 370);
  delay(100);
  pwm.setPWM(0, 0, 190);
  delay(100);
  pwm.setPWM(4, 0, 510);
  delay(100);
  pwm.setPWM(1, 0, 190);
  pwm.setPWM(3, 0, 370);
  pwm.setPWM(2, 0, 190);
  pwm.setPWM(0, 0, 370);
}
 
void forward()
{ 
  pwm.setPWM(5, 0, 190);
  delay(50);
  pwm.setPWM(1, 0, 100);
  delay(50);
  pwm.setPWM(5, 0, 100);
  delay(50);
  pwm.setPWM(4, 0, 370);
  delay(50);
  pwm.setPWM(0, 0, 510);
  delay(50);
  pwm.setPWM(4, 0, 510);
  delay(50);
  pwm.setPWM(6, 0, 370);
  delay(50);
  pwm.setPWM(2, 0, 280);
  delay(50);
  pwm.setPWM(6, 0, 510);
  delay(50);
  pwm.setPWM(7, 0, 190);
  delay(50);
  pwm.setPWM(3, 0, 280);
  delay(50);
  pwm.setPWM(7, 0, 100);
  delay(50);
  pwm.setPWM(0, 0, 370);
  pwm.setPWM(1, 0, 190);
  pwm.setPWM(2, 0, 190);
  pwm.setPWM(3, 0, 370);
}
 
void backward()
{ 
  pwm.setPWM(7, 0, 190);
  delay(50);
  pwm.setPWM(3, 0, 510);
  delay(50);
  pwm.setPWM(7, 0, 100);
  delay(50);
  pwm.setPWM(6, 0, 370);
  delay(50);
  pwm.setPWM(2, 0, 100);
  delay(50);
  pwm.setPWM(6, 0, 510);
  delay(50);
  pwm.setPWM(5, 0, 190);
  delay(50);
  pwm.setPWM(1, 0, 280);
  delay(50);
  pwm.setPWM(5, 0, 100);
  delay(50);
  pwm.setPWM(4, 0, 370);
  delay(50);
  pwm.setPWM(0, 0, 280);
  delay(50);
  pwm.setPWM(4, 0, 510);
  delay(50);
  pwm.setPWM(3, 0, 370);
  pwm.setPWM(2, 0, 190);
  pwm.setPWM(1, 0, 190);
  pwm.setPWM(0, 0, 370);
}
 
void hello()
{
  pwm.setPWM(0, 0, 510);
  delay(100);
  pwm.setPWM(4, 0, 100);
  delay(500);
  pwm.setPWM(4, 0, 190);
  delay(500);
  pwm.setPWM(4, 0, 100);
  delay(500);
  pwm.setPWM(4, 0, 190);
  delay(500);
  pwm.setPWM(4, 0, 100);
  delay(500);
  pwm.setPWM(4, 0, 510);
}
 
void come()
{
  pwm.setPWM(0, 0, 280);
  delay(100);
  pwm.setPWM(4, 0, 100);
  delay(500);
  pwm.setPWM(4, 0, 190);
  delay(500);
  pwm.setPWM(4, 0, 100);
  delay(500);
  pwm.setPWM(4, 0, 190);
  delay(500);
  pwm.setPWM(4, 0, 100);
  delay(500);
  pwm.setPWM(4, 0, 510);
}

三、原理介绍

1.PWM

因为使用了pca9685舵机驱动板,所以这里使用的是Adafruit_PWMServoDriver库驱动sg90舵机,原理是通过PWM来控制舵机角度,动作主要是靠PWM来写的。舵机0-180度对应的PWM数值写在表格里了,这里取的是近似值,自己进行微调也可以。

角度PWM数值
0100
45190
90280
135370
180510

3.舵机号

图中的舵机号与代码中的舵机号是对应的,比如代码中的pwm.setPWM(4, 0, 370),就是将4号脚置于135度。

645f53c217c04a7b84c7ef778a154984.png

3.舵机角度

蓝色角度对应的是4、5、6、7脚,黄色对应的是0、1、2、3脚。这里的角度范围表示舵机能运动的范围以及最大角度。比如当4、6号脚为0度时向上,而5、7脚0度时向下,反之当4、6号脚为180度时向下,而5、7脚180度时向上。

a28a30c406ab4faab5099715ee71762d.png

4. 操作页面

操作页面有用小程序的也有用软件的,我这里使用的是网页,用esp8266作为网络服务器,按钮使用html写的。这部分的讲解可以看看b站太极创客esp8266,讲的非常详细,本文所用的代码和太极创客所讲的有很多重合。

855ffdec312e4408ada4c02f3c0b9827.jpeg

 四、组装教程

1.程序写入esp8266

打开Arduino,将代码复制进去,然后安装Adafruit_PWMServoDriver库。

810243cdda9049318e5dfe1ffa96063f.png

 将需要连接的WIFI或者热点填写进去

4fc322303e644d61be9c34139c11f2bb.png

选择nodemcu开发板,具体设置如下。 

ac5bd3d4b4d54d6386df3b4c7220fd7c.png

上传esp8266以后打开串口监视器,波特率选择115200。可以看到此时最后一行显示一个网址,每个人的都会不一样,不要输入我的,输入自己的网址。

4ffcfdc4a4d24ff49a48b1125f435e43.png

 用手机浏览器或者电脑浏览器打开,就会显示出操作界面。

855ffdec312e4408ada4c02f3c0b9827.jpeg

2.供电连接

将电池连接到升压板输入端,升压板输出端连接舵机拓展板电源,这样就把电池的3.7V升到5V。注意正负极不要接反了,升压板使用前要先旋转几十圈再用,用万用表检测升压板输出电压是否达到5V。

6417af71e4df4d6eba996881d394efa2.jpeg

3.esp8266连接

esp8266通过i2c和舵机拓展板通信,使用杜邦线连接。esp8266的供电由舵机拓展板提供,不需要再额外供电。

esp8266舵机拓展板
VINV+
3.3VVCC
GNDGND
D2SDA
D1SCL

4.安装舵机和3d打印件

在这里说明一下3d打印与舵机尺寸的问题。很多人说我的模型尺寸有问题,其实不是我的模型尺寸错误,仔细看下图舵机附带的舵机臂,可以看到下面的比上面的大,这是因为下面的舵机臂是我近期才买的,上面的舵机臂是我很久以前买的,应该是生产厂家更改了尺寸,所以新版本比旧版本尺寸大,而淘宝卖家没有区分新旧,是新旧版本随机发,所以买到的舵机臂尺寸可能大也可能小。

我用在四足机器人上的是很久以前买的舵机,所以我的模型是小尺寸的。如果你是最近购买的舵机那么就有可能出现尺寸不符合的问题,不要再说模型尺寸错误了,这是生产厂家的问题。

解决的办法有两种,第一种是买小尺寸的舵机臂,第二种是更改模型尺寸(我已经上传新版SG90模型到网盘)。但是目前来说两种办法都不太好解决,正如我所说这是生产厂家的问题,所以目前无论是淘宝卖家还是建模的人都没有区分大小尺寸,毕竟谁会想到一个sg90舵机带的零件会出现两种尺寸。

3d打印件应该跟图片中一样,安装所用的螺丝用舵机自带的就行,不用额外购买。

6fdc081a5d9a462cbf222420e9ae6c47.jpeg

如下图把舵机自带的塑料件安装上去,每个腿安装两个。

12757449cec84b7b8fa613b5ec0fcbd6.jpeg

用舵机自带的螺丝如下图拧上去 ,其他的也一样。一共是4个腿,用8个螺丝。

55bca52df65e430fa18d06387b7c0a80.jpeg

把四个舵机安装到支架上, 注意线的方向全是向外,用舵机自带的螺丝安装。一共需要8个螺丝,这里只安装4个就够了,不然螺丝会不够用。

30143729463349af940a5aaafcc3a162.jpeg

 将另外4个舵机如下图安装,注意方向不要错了。每个腿需要安装2个螺丝,这里只安装1个,不然螺丝不够用。

ec3b1319af8d4bfcb76570d2a577df09.jpeg

5.调整角度

想要正确的安装必须先调整舵机的角度,否则角度不对会伤害舵机。如下图所示,是舵机号所对应的接口。

57c132c3dd0746fca8218e70eeda1a49.png

如下图所示是0、1、2、3号舵机

73ccb9fa10274e90b575f93f9c1128eb.png

 先将电源、esp8266、0、1、2、3、舵机拓展板都连接上。

32a369ca3a4d41148ee06f7bc7615460.jpeg

进入操作页面点击睡觉 

b6393388efb840d49e67a3c8e5240e8b.jpeg

等舵机动作后按照下图的摆放方式将4个腿安装上,并且用舵机自带的螺丝固定,安装过程中要保持通电,尽量按照90度直角安装,如果有倾斜也没关系,这是因为舵机齿轮精度以及安装精度不够,后期可以通过调整代码修正。

9bd9ea198abb49f2b14d6a020bb9180f.jpeg

 再将4、5、6、7号舵机安装上去,重复上面的操作。等待舵机动作后不要断电安装。

da1f97be028142789a6492672820329a.png

如下图所示安装完成,尽量保持水平, 如果有不水平的后期可以通过代码调整。

9439a59bd29045ef8891f1d39faebe61.jpeg

6. 整理线束

我用的是轧带,价格非常便宜,一块多就可以买500条。先用轧带把电池盒固定住。

a615164f32004a52a7e87167c8c64981.jpeg

 再用轧带把机器人头顶上的线都固定住,这样看起来是不是整齐很多了。

1a0696f3a7034181ad85d2dea7646125.jpeg

五、总结

虽然制作的是四足机器人,但是我认为核心不在机器人上,而是esp8266作为网络服务器使用。如果有了解过b站上太极创客的esp8266讲解就会发现,我所用到的代码除了动作这一部分,很多都是太极创客里使用的例子代码。

我为什么说核心是esp8266而不是机器人的原因,代码中写的动作函数不过是几个pwm调整舵机角度再加几个延时函数,如果仔细处理确实能形成各式各样的动作,但是并没有太大的学习意义。而网络服务那部分的代码算是esp8266的精华所在了,学完太极创客的视频再制作这个四足机器人的话算是完成课后作业了,可以复习一下学过知识。或者说对这部分代码有不理解的人可以看看太极创客的视频,一方面可以了解每一条代码的作用,另一方面对于学习esp8266也非常有帮助。

对于初学者来说这个四足机器人拿去当一个课设或者低级的毕设还凑合,并不是什么高大上的东西。我之所以写出来这篇文章是因为发现网络上关于这个四足机器人的知识太少了,都是成品展示而没有教程,很多人也想了解一下,于是我写出这篇教程希望能帮到一些人。其实很多四足机器人都大同小异,都是pwm的原理,只是用到的开发板、库、函数不同。

我这里使用的是esp8266+舵机拓展板,实际上直接使用esp8266也可以,只是我为了方便加上了舵机拓展板,你甚至可以买一个esp12模组自己画板子做最小系统然后用GPIO直接输出pwm,这样集成度比较高,可以用固定在机器人上。也可以用esp8266+Arduino nano,依然是pwm控制舵机,只不过控制舵机的是Arduino。

最后分享一下3d打印文件,这个是我在T站上找的成品文件,打开以后是切片软件用的,而不是建模的模型。打开以后共5个文件,实际上需要9个零件,除了“身体”部分打印1个,其他的都要打印2个。

链接:https://pan.baidu.com/s/1tMynUvNBgorOKMaqctmovg?pwd=2a9g 
提取码:2a9g

因为我经常3d打印所以用的很多模型都是在T站上找的,我会给出网站链接,有兴趣的自己去看看吧,有各种各样的机器人模型以及其他的模型,网站打开进入会比较慢。

Thingiverse - Digital Designs for Physical Objects

六、结果演示

  • 280
    点赞
  • 1429
    收藏
    觉得还不错? 一键收藏
  • 188
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 188
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值