Python 物联网入门指南(八)(2)

简介: Python 物联网入门指南(八)

Python 物联网入门指南(八)(1)https://developer.aliyun.com/article/1507342

寻找极限

机械臂套件在 eBay 或亚马逊上相对容易获得。这并不难组装,需要几个小时来准备。一些机械臂套件可能不会随舵机一起发货,如果是这样,你可能需要单独订购。我建议选择与舵机捆绑在一起的套件,因为如果你选择单独订购舵机,可能会出现兼容性问题。

正如你所知,这些舵机将使用 PWM 工作,控制它们也不难。所以,让我们直接开始并看看我们能做些什么。一旦你组装好了机械臂套件,将舵机的线连接如下:


现在,首先,我们需要知道我们机器人上连接的每个舵机的最大物理极限是什么。有各种各样的技术可以做到这一点。最基本的方法是进行物理测量。这种方法可能很好,但你将无法充分利用舵机电机的全部潜力,因为在测量时会有一定程度的误差。因此,你放入舵机的值将略小于你认为它可以达到的值。第二种方法是手动输入数据并找出确切的角度。所以,让我们继续用第二种方法做事情,并上传以下代码:

import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) GPIO.setup(14,GPIO.OUT) GPIO.setup(16,GPIO.OUT) GPIO.setup(18,GPIO.OUT) GPIO.setup(20,GPIO.OUT) GPIO.setup(21,GPIO.OUT) GPIO.setup(22,GPIO.OUT)
  GPIO.setwarnings(False) pwm1 = GPIO.PWM(14, 50) pwm2 = GPIO.PWM(16, 50) pwm3 = GPIO.PWM(18, 50) pwm4 = GPIO.PWM(20, 50) pwm5 = GPIO.PWM(21, 50) pwm6 = GPIO.PWM(22, 50)
  pwm1.start(0) pwm2.start(0) pwm3.start(0) pwm4.start(0) pwm5.start(0) pwm6.start(0)  def cvt_angle(angle):     dc = float(angle/90) + 0.5
    return dc  while 1:
 j = input('select servo')  if j == 1: i = input('select value to rotate')
  pwm1.ChangeDutyCycle(cvt_angle(i))
 time.sleep(2)
  pwm1.ChangeDutyCycle(cvt_angle(90)) elif j ==2:  i = input('select value to rotate')   pwm2.ChangeDutyCycle(cvt_angle(i))
 time.sleep(2) pwm2.ChangeDutyCycle(cvt_angle(90))   elif j ==3:   i = input('select value to rotate') pwm3.ChangeDutyCycle(cvt_angle(i))
 time.sleep(2) pwm3.ChangeDutyCycle(cvt_angle(90))  elif j ==4:  i = input('select value to rotate')
  pwm4.ChangeDutyCycle(cvt_angle(i))
 time.sleep(2) pwm4.ChangeDutyCycle(cvt_angle(90))  elif j ==5:  i = input('select value to rotate')
  pwm5.ChangeDutyCycle(cvt_angle(i))
 time.sleep(2) pwm5.ChangeDutyCycle(cvt_angle(90))  elif j ==6:  i = input('select value to rotate')   pwm6.ChangeDutyCycle(cvt_angle(i))
 time.sleep(2) pwm6.ChangeDutyCycle(cvt_angle(90)) }

现在,让我们看看这段代码在做什么。这段代码看起来可能相当复杂,但它所做的事情非常简单。

j = input('select servo from 1-6')

使用前面的代码行,我们正在为用户打印从 1-6 选择舵机的语句。当用户输入舵机的值时,这个值被存储在一个名为j的变量中:

if j == 1: i = input('select value to rotate')
  pwm1.ChangeDutyCycle(cvt_angle(i))
 time.sleep(2) pwm1.ChangeDutyCycle(cvt_angle(90))  

这里的if条件检查j的值。如果在这一行中,j=1,那么它将运行与舵机编号1对应的代码。在这段代码中,第一行将打印选择要旋转的值。完成后,程序将等待用户输入。一旦用户输入任何值,它将被存储在一个名为I的变量中。然后,使用cvt_angle(i)函数,用户输入的值将被转换为相应的占空比值。这个占空比值将被获取到pwm1.ChangeDutyCycle()参数中,从而给予机器人你想要的特定关节角度。由于time.sleep(2)函数,舵机将等待到下一行。之后,我们使用pwm1.ChangeDutyCycle(cvt_angle(90))这一行,这将把它带回到 90 度。

你可能会问,为什么我们要这样做?这是一个非常重要的原因。假设您已经给它一个超出其物理极限的命令。如果是这种情况,那么舵机将继续尝试朝那个方向移动,不管发生什么。然而,由于物理限制,它将无法继续前进。一旦发生这种情况,然后在几秒钟内,您将看到蓝烟从舵机中冒出,表明它的损坏。问题在于,制造这种类型的错误非常容易,损失是非常明显的。因此,为了防止这种情况,我们迅速将其带回到中心位置,这样它就不会有任何烧毁的可能性。

现在,根据前面的代码,通过机器人对舵机 1-6 执行相同的操作。现在你知道发生了什么,是时候拿起笔和纸开始给舵机赋予角度值了。请记住,这段代码的最终目标是找出最大限制。因此,让我们从 90 度开始做起。在每一侧给它一个值,直到你能够接受的值。在纸上列出清单,因为我们将需要它用于下一段代码。

使机器人安全

在本章的前一部分中,通过我们的多次尝试,我们已经能够找到每个舵机的最大位置。现在是时候使用这些值了。在本章中,我们将为舵机编程其绝对最大值。在这个程序中,我们将确保舵机永远不需要超出两侧的定义参数。如果用户给出超出它的值,那么它将选择忽略用户输入,而不是造成自身损坏。

那么,让我们看看如何完成它。在程序的某些部分,数字值已经用粗体标出。这些是您需要用本章前面记录的值替换的值。例如,对于舵机 1,记录下的值是23170,作为每一侧的最大值。因此,代码的更改将从if a[0] < 160 and a[0] > 30变为ifa[0] < 170 and a[0] > 23。同样,对于每个舵机,必须遵循相同的程序:

import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) GPIO.setup(14,GPIO.OUT) GPIO.setup(16,GPIO.OUT) GPIO.setup(18,GPIO.OUT) GPIO.setup(20,GPIO.OUT) GPIO.setup(21,GPIO.OUT) GPIO.setup(22,GPIO.OUT)
  GPIO.setwarnings(False) pwm1 = GPIO.PWM(14, 50) pwm2 = GPIO.PWM(16, 50) pwm3 = GPIO.PWM(18, 50) pwm4 = GPIO.PWM(20, 50) pwm5 = GPIO.PWM(21, 50) pwm6 = GPIO.PWM(22, 50)
  pwm1.start(cvt_angle(90)) pwm2.start(cvt_angle(90)) pwm3.start(cvt_angle(90)) pwm4.start(cvt_angle(90)) pwm5.start(cvt_angle(90)) pwm6.start(cvt_angle(90))
def cvt_angle(angle):
    dc = float(angle/90) + 0.5
    return dc
while True:
    a = raw_input("enter a list of 6 values")
    if a[0] < 160 and  a[0] > 30:
        pwm1.ChangeDutyCycle(cvt_angle(a[0]))
    if a[1] < 160 and  a[1] > 30:  pwm2.ChangeDutyCycle(cvt)angle(a[1]))
    if a[0] < 160 and  a[0] > 30: pwm3.ChangeDutyCycle(cvt_angle(a[2]))    if a[0] < 160 and  a[0] > 30: pwm4.ChangeDutyCycle(cvt_angle(a[3]))    if a[0] < 160 and  a[0] > 30: pwm5.ChangeDutyCycle(cvt_angle(a[4]))    if a[0] < 160 and  a[0] > 30: pwm6.ChangeDutyCycle(cvt_angle(a[5]))}

现在,在这段代码中,我们做了一些非常基础的事情。您可以放心地说,我们所做的一切就是将ChangeDutyCycle()函数放在一个if语句中。这个if语句将决定舵机是移动还是保持在原位。对一些人来说,将这个程序放在一个特殊的部分似乎很天真。但是,请相信我,不是这样的。这个语句现在将作为以后每个程序的一部分。为了检查通过这个if语句传递给舵机的最终值,必须检查为舵机移动编写的所有代码;因此,对代码的基本可视化是非常必要的。

现在解释完毕,是时候给出不同的命令并查看它们是否在安全工作限制内工作了。

编写多个帧

在上一章中,我们已经学习了如何确保机器人在安全限制下工作的基础知识。在本章中,我们将看看如何使机器人能够在点击按钮的同时执行不同的活动,而不是逐个输入值。

为了做到这一点,我们需要了解一些高级运动概念。每当您观看任何视频或玩任何视频游戏时,您一定会遇到“每秒帧数”(FPS)这个术语。如果您还没有听说过这个术语,那么让我为您解释一下。现在制作的每个视频实际上都是由静止图像制成的。这些静止图像是由摄像机捕捉的,每秒点击 25-30 次。当这些图像以与它们被捕捉的速率相同的速率在屏幕上播放时,它形成了一个平滑的视频。

同样,在机器人中,我们也有帧的概念。然而,这些帧不是图像,而是机器人必须遵循的多个步骤。在一个简单的机器人程序中,可能只有两个帧,即初始帧和最终帧。这两个帧将对应于初始位置或最终位置。

然而,在现实世界中,这并不总是可能的,因为当机器人直接从初始位置到最终位置时,它会沿着特定的路径运动,并具有特定的曲率。然而,在这条路径上可能会有障碍物,或者这条路径可能不是所需的,因为需要遵循的路径可能是另一条。因此,我们需要帧。这些帧不仅定义了机器人从初始位置到最终位置的运动,而且将这两个位置之间的过渡分解为多个步骤,使机器人遵循所需的路径。

这可以被称为帧编程,在本章中我们将介绍。要记住的一件事是,帧数越多,机器人的运行就越平稳。你还记得我们看到的闭路电视录像吗?我们可以说它不够平滑,而且有很多抖动。这是由于闭路电视摄像头的低帧率造成的。它们不是以 30FPS 工作,而是以 15FPS 工作。这是为了减少视频的存储空间。然而,如果你看到最新的视频,有一些游戏和视频的帧率比正常的要高得多。我们最新的摄像头有 60FPS 的工作,使视频更加平滑和愉快。机器人也是如此。帧数越多,运动就越平滑和可控。但是,请确保不要过度使用。

现在,要从一个位置移动到另一个位置,我们将不得不在一开始就放入每个舵机的角度值。一旦获取,它将自动开始逐个执行这些值。为此,请继续编写以下代码:

import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) GPIO.setup(14,GPIO.OUT) GPIO.setup(16,GPIO.OUT) GPIO.setup(18,GPIO.OUT) GPIO.setup(20,GPIO.OUT) GPIO.setup(21,GPIO.OUT) GPIO.setup(22,GPIO.OUT)
  GPIO.setwarnings(False) pwm1 = GPIO.PWM(14, 50) pwm2 = GPIO.PWM(16, 50) pwm3 = GPIO.PWM(18, 50) pwm4 = GPIO.PWM(20, 50) pwm5 = GPIO.PWM(21, 50) pwm6 = GPIO.PWM(22, 50)
  pwm1.start(0) pwm2.start(0) pwm3.start(0) pwm4.start(0) pwm5.start(0) pwm6.start(0)
def cvt_angle(angle):
    dc = float(angle/90) + 0.5
    return dc
prev0 = 90
prev1 = 90
prev2 = 90
prev3 = 90
prev4 = 90
prev5 = 90 
while True:
    a = raw_input("enter a list of 6 values for motor 1")
    b = raw_input("enter a list of 6 values for motor 2")
    c = raw_input("enter a list of 6 values for motor 3")
    d = raw_input("enter a list of 6 values for motor 4")
    e = raw_input("enter a list of 6 values for motor 5")
    f = raw_input("enter a list of 6 values for motor 6")
    for i in range(6):
        if a[i] > 10 and a[i]< 180 :  
            pwm1.ChangeDutyCycle(cvt_angle(a[i]))
        if b[i] > 10 and b[i] < 180:
  pwm2.ChangeDutyCycle(cvt_angle(b[i]))
        if c[i] > 10 and c[i] < 180:
 pwm3.ChangeDutyCycle(cvt_angle(c[i]))
        if d[i] > 10 and d[i] < 180:
 pwm4.ChangeDutyCycle(cvt_angle(d[i]))
        if e[i] > 10 and e[i] < 180:
 pwm5.ChangeDutyCycle(cvt_angle(e[i]))
        if f[i] > 10 and f[i] < 180:
 pwm6.ChangeDutyCycle(cvt_angle(f[i])) 

在这个程序中,你可以看到我们复制了以前的程序并进行了一些非常小的改动。所以,让我们看看这些改动是什么:

a = raw_input("enter a list of 6 values for motor 1")
    b = raw_input("enter a list of 6 values for motor 2")
    c = raw_input("enter a list of 6 values for motor 3")
    d = raw_input("enter a list of 6 values for motor 4")
    e = raw_input("enter a list of 6 values for motor 5")
    f = raw_input("enter a list of 6 values for motor 6")

在这里,我们正在为每个舵机获取输入值并将其存储在不同的列表中。对于舵机 1,将使用列表a;类似地,对于舵机 2,将使用b,依此类推直到f。在代码的前面几行中,机器人将提示用户填写电机 1的六个帧值。然后,它将要求电机 2的六个值,以此类推直到电机 6

for i in range(6):

给舵机提供 PWM 的整个程序都集中在这个 for 循环中。这个循环将检查i的值并每次递增。i的值将从1开始,循环将运行并递增i的值直到达到6

if a[i] > 10 and a[i]< 180 :  
            pwm1.ChangeDutyCycle(cvt_angle(a[i]))

在程序的这一行中,列表中包含的值是基于1的值进行排序的。因此,第一次它将读取a[1]的值,这将对应于列表a[]的第一个值。这个值应该在安全工作范围内,因此使用if循环。如果在安全工作范围内,那么if条件中的程序将执行,否则不会执行。在if循环内,我们有一个简单的语句:pwm1.ChangeDutyCycle(cvt_angle(a[I]))。这将简单地取a[1]的值并将其转换为相应的 PWM 值,并将其提取到ChangeDutyCycle()函数中,这将改变舵机 1 的 PWM。

对于其余的舵机也制作了类似的程序,从舵机 1 到舵机 6。因此,所有这些都将逐一读取其对应列表中的值,并根据用户编程的方式改变舵机的角度。此外,随着循环的执行,i的值将增加,从而使程序读取列表中提取的不同值。列表中舵机的每个值将对应一个不同的帧,从而使机器人通过它。

所以继续玩一些有趣的东西,让你的机器人做一些很棒的动作。只要小心对待它!

Python 物联网入门指南(八)(3)https://developer.aliyun.com/article/1507344

相关实践学习
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
相关文章
|
10月前
|
SQL 关系型数据库 数据库
Python SQLAlchemy模块:从入门到实战的数据库操作指南
免费提供Python+PyCharm编程环境,结合SQLAlchemy ORM框架详解数据库开发。涵盖连接配置、模型定义、CRUD操作、事务控制及Alembic迁移工具,以电商订单系统为例,深入讲解高并发场景下的性能优化与最佳实践,助你高效构建数据驱动应用。
1087 7
|
11月前
|
测试技术 开发者 Python
Python单元测试入门:3个核心断言方法,帮你快速定位代码bug
本文介绍Python单元测试基础,详解`unittest`框架中的三大核心断言方法:`assertEqual`验证值相等,`assertTrue`和`assertFalse`判断条件真假。通过实例演示其用法,帮助开发者自动化检测代码逻辑,提升测试效率与可靠性。
652 1
|
API 数据安全/隐私保护 开发者
Python自定义异常:从入门到实践的轻松指南
在Python开发中,自定义异常能提升错误处理的精准度与代码可维护性。本文通过银行系统、电商库存等实例,详解如何创建和使用自定义异常,涵盖异常基础、进阶技巧、最佳实践与真实场景应用,助你写出更专业、易调试的代码。
398 0
|
IDE 开发工具 数据安全/隐私保护
Python循环嵌套:从入门到实战的完整指南
循环嵌套是Python中处理多维数据和复杂逻辑的重要工具。本文通过实例讲解嵌套循环的基本用法、常见组合、性能优化技巧及实战应用,帮助开发者掌握其核心思想,避免常见错误,并探索替代方案与进阶方向。
781 0
|
10月前
|
Cloud Native 算法 API
Python API接口实战指南:从入门到精通
🌟蒋星熠Jaxonic,技术宇宙的星际旅人。深耕API开发,以Python为舟,探索RESTful、GraphQL等接口奥秘。擅长requests、aiohttp实战,专注性能优化与架构设计,用代码连接万物,谱写极客诗篇。
1968 1
Python API接口实战指南:从入门到精通
|
Python
Python字符串格式化利器:f-strings入门指南
Python字符串格式化利器:f-strings入门指南
653 80
|
10月前
|
存储 Java 调度
Python定时任务实战:APScheduler从入门到精通
APScheduler是Python强大的定时任务框架,通过触发器、执行器、任务存储和调度器四大组件,灵活实现各类周期性任务。支持内存、数据库、Redis等持久化存储,适用于Web集成、数据抓取、邮件发送等场景,解决传统sleep循环的诸多缺陷,助力构建稳定可靠的自动化系统。(238字)
1684 1
|
11月前
|
调度 数据库 Python
Python异步编程入门:asyncio让并发变得更简单
Python异步编程入门:asyncio让并发变得更简单
519 5
|
11月前
|
数据采集 存储 XML
Python爬虫入门(1)
在互联网时代,数据成为宝贵资源,Python凭借简洁语法和丰富库支持,成为编写网络爬虫的首选。本文介绍Python爬虫基础,涵盖请求发送、内容解析、数据存储等核心环节,并提供环境配置及实战示例,助你快速入门并掌握数据抓取技巧。

推荐镜像

更多