第1步:准备
步骤2:代码结构
我将代码划分为这些文件,我将一一解释:
aum2.py
l298ndrive.py
remotecontrol.py
utils.py
在接下来的步骤中,我将一步一步地解释这些文件
第3步:aum2.py
这是应用程序的主要入口点,包含机器人类
import rpi.gpio as gpio
from twisted.internet import reactor, task
import l298ndrive
import remotecontrol
import logging
import utils
logging.basicconfig(level=logging.warn)
log = logging.getlogger(‘aum2’)
enablemotors = true # motors can be disabled for testing with this
runfrequency = 1 # the frequency on wich the main task will be ran
class aum2(object):
def __init__(self):
log.debug(“initializing aum2 robot.。.”)
# configuration
self.port = 5555 # port to open so the remote can connect
gpio.setmode(gpio.board)
# configure min and max servo pulse lengths
# keep in mind these are not pins but servo outs
self.motors = l298ndrive.l298ndrive(10, 11, 12, 13, 14, 15, enablemotors)
self.rc = remotecontrol.remotecontrol(self.port)
def processremotecommand(self, cmd):
(vr, vl) = utils.joysticktodiff(cmd.x, cmd.y, -9.8, 9.8, -4095, 4095)
self.motors.setspeeds(int(vr), int(-vl))
def run(self):
print(“running.。.”)
def start(self):
self.rc.start(self.processremotecommand)
l = task.loopingcall(self.run)
l.start(runfrequency) # run will be called with this frequency
# gather our code in a main() function
def main():
robot = aum2()
robot.start()
reactor.run()
# standard boilerplate to call the main() function to begin
# the program.
if __name__ == ‘__main__’:
main()
有些我要对此文件发表评论的要点:
我正在使用扭曲库来协调来自udp的远程控制订单服务器(将在相应的源文件中显示)和机器人的主要run方法。如您所见,该方法现在什么也不做,但是其想法是在其中添加代码以使机器人更具自治性。
processremotecommand 方法将是
开始方法是在我配置需要协调的两件事时:监听
第4步:remotecontrol.py
此文件包含两个类,即remotecontrol类, rccommand类
import logging
import traceback
from twisted.internet.protocol import datagramprotocol
from twisted.internet import reactor
import utils
log = logging.getlogger(‘remotecontrol’)
class remotecontrol(datagramprotocol):
def __init__(self, port):
self.port = port
def start(self, oncommandreceived):
log.debug(“initializing remotecontrol.。.”)
self.oncommandreceived = oncommandreceived
reactor.listenudp(self.port, self)
def datagramreceived(self, data, addr):
try:
log.debug(“received %r from %s” % (data, addr))
command = rccommand(data)
self.oncommandreceived(command)
except (keyboardinterrupt, systemexit):
raise
except:
traceback.print_exc()
class rccommand(object):
# timestamp [sec], sensorid, x, y, z, sensorid, x, y, z, sensorid, x, y, z
# 890.71558, 3, 0.076, 9.809, 0.565, 。..
def __init__(self, message):
self.x = 0
self.y = 0
self.z = 0
self.values = message.split(“,”)
if len(self.values) 》= 5 and self.values[1].strip() == “3”:
self.x = -float(self.values[3].strip())
self.y = -float(self.values[2].strip())
self.z = float(self.values[4].strip())
log.debug(“x={} y={} z={}”.format(self.x, self.y, self.z))
else:
log.warn(“invalid message: {}”.format(message))
同样是remotecontrol类,它使用扭曲的框架来侦听运行wireless imu应用的android手机发送的udp程序包。此应用程序发送具有以下结构的消息:
890.71558, 3、0.076、9.809、0.565 ,4,-0.559、0.032,-0.134、5 -21.660,-36.960, -28.140
我只对上面突出显示的消息部分感兴趣,这就是传感器id 3 ,以及加速度计提供的三个测量值( 0.076、9.809、0.565 )。
您可以在代码中看到,类 rccommand 将此消息的有用参数转换为机器人所需的x和y值,其中
x 是从前到后的轴,而
y 则是从一侧到另一侧。
我也有z轴的代码,但是我暂时不使用它。
步骤5:l298ndrive.py
这是负责控制电动机的文件。为此,它将命令发送到16伺服驱动器,该驱动器连接到l298n电动机驱动器。我想我可能会在我构建的每个raspberry pi机器人上重用该类。它确实很简单,并且不需要复杂的处理即可完成它的工作。
import adafruit_pca9685
import logging
import math
import utils
log = logging.getlogger(‘l298ndrive’)
class l298ndrive(object):
def __init__(self, ena, in1, in2, in3, in4, enb, enabled):
log.debug(“initializing l298drive.。.”)
self.minpwm = 0
self.maxpwm = 4095
self.ena = ena
self.in1 = in1
self.in2 = in2
self.in3 = in3
self.in4 = in4
self.enb = enb
self.enabled = enabled
if enabled:
self.enable()
def enable(self):
self.enabled = true
# initialise the pca9685 using the default address (0x40)。
self.pwm = adafruit_pca9685.pca9685()
self.setspeeds(0, 0)
def disable(self):
self.enabled = false
self.setspeeds(0, 0)
# initialise the pca9685 using the default address (0x40)。
self.pwm = none
def setspeeds(self, rspeed, lspeed):
self.setspeed(1, rspeed)
self.setspeed(2, lspeed)
def setspeed(self, motor, speed):
pwm = int(math.fabs(speed))
log.info(“motor: {} speed: {} pwm: {}”.format(motor, speed, pwm))
if motor == 1:
if speed 》= 0:
if self.enabled:
self.pwm.set_pwm(self.in1, 0, 0)
self.pwm.set_pwm(self.in2, 0, self.maxpwm)
else:
if self.enabled:
self.pwm.set_pwm(self.in1, 0, self.maxpwm)
self.pwm.set_pwm(self.in2, 0, 0)
if self.enabled:
self.pwm.set_pwm(self.ena, 0, pwm)
else: # motor == 2
if speed 》= 0:
if self.enabled:
self.pwm.set_pwm(self.in3, 0, 0)
self.pwm.set_pwm(self.in4, 0, self.maxpwm)
else:
if self.enabled:
self.pwm.set_pwm(self.in3, 0, self.maxpwm)
self.pwm.set_pwm(self.in4, 0, 0)
if self.enabled:
self.pwm.set_pwm(self.enb, 0, pwm)
可以看出,代码的主要部分在setspeed(self,motor,speed)方法中,该方法接收要配置的电动机编号(1 =右,2 =左),并告诉伺服驱动器如何处理与该电动机关联的引脚。
也许应该给出一些解释以了解我为什么要执行我的工作
l298n电机驱动器
使用6个引脚驱动两个电机:
ena 用来告诉速度(使用pwm),我们要使电动机启动1。通电后,告诉驾驶员电动机1应该沿一个方向移动(in2应该处于关闭状态)
in2 通电时,告诉驾驶员电动机1应当沿相反方向移动(in1应该处于关闭状态)
in3 通电时,告知驾驶员电机2应该沿一个方向移动(in4应该关闭)
in4 告诉驾驶员,电动机2应该沿相反方向移动(in4应该关闭)
enb 用于告诉速度(使用pwm),我们希望电动机转动
所以在我们的例子中,因为我对所有引脚都使用了伺服驱动器(只有其中两个需要pwm):
当我做到这一点:
self.pwm.set_pwm(self.in1, 0, 0)
我真的是在告诉伺服驱动器,在所有pwm期间,该引脚(in1)应该为off,(所以我将该引脚设为off)
当我这样做时:
self.pwm.set_pwm(self.in1, 0, self.maxpwm)
我实际上是在告诉伺服驱动器,在所有pwm周期中,该引脚(in1)应该处于on位置(所以我将其打开
然后,当我这样做时:
self.pwm.set_pwm(self.ena, 0, pwm)
我使用真正的pwm引脚,并使用速度参数设置我所要求的脉冲。
步骤6:utils.py
最后,这是最后的平安。它不包含类,但是我认为我会在其他地方重用的所有有用功能。
import math
import logging
log = logging.getlogger(‘utils’)
def map(v, in_min, in_max, out_min, out_max):
# check that the value is at least in_min
if v 《 in_min:
v = in_min
# check that the value is at most in_max
if v 》 in_max:
v = in_max
return (v - in_min) * (out_max - out_min) // (in_max - in_min) + out_min
def joysticktodiff(x, y, minjoystick, maxjoystick, minspeed, maxspeed):
# if x and y are 0, then there is not much to calculate.。.
if x == 0 and y == 0:
return (0, 0)
# first compute the angle in deg
# first hypotenuse
z = math.sqrt(x * x + y * y)
# angle in radians
rad = math.acos(math.fabs(x) / z)
# and in degrees
angle = rad * 180 / math.pi
# now angle indicates the measure of turn
# along a straight line, with an angle o, the turn co-efficient is same
# this applies for angles between 0-90, with angle 0 the coeff is -1
# with angle 45, the co-efficient is 0 and with angle 90, it is 1
tcoeff = -1 + (angle / 90) * 2
turn = tcoeff * math.fabs(math.fabs(y) - math.fabs(x))
turn = round(turn * 100, 0) / 100
# and max of y or x is the movement
mov = max(math.fabs(y), math.fabs(x))
# first and third quadrant
if (x 》= 0 and y 》= 0) or (x 《 0 and y 《 0):
rawleft = mov
rawright = turn
else:
rawright = mov
rawleft = turn
# reverse polarity
if y 《 0:
rawleft = 0 - rawleft
rawright = 0 - rawright
# minjoystick, maxjoystick, minspeed, maxspeed
# map the values onto the defined rang
rightout = map(rawright, minjoystick, maxjoystick, minspeed, maxspeed)
leftout = map(rawleft, minjoystick, maxjoystick, minspeed, maxspeed)
log.debug(“x={} y={}, rout={}, lout={}”.format(x, y, rightout, leftout))
return (rightout, leftout)
这里只有两种方法,第一种是从地图功能的arduino。它将指定输入限制(in_min,in_max)内的值(v)转换为输出范围(out_min,out_max)内的相应值。
我为输入值添加了限制,所以我只接受av,位于in_min和in_max之内。
我拥有的另一个函数( joysticktodiff )稍微复杂一点,但是其目的是从输入的操纵杆对转换值,以达到差动驱动机器人左右电机所需的速度。此输出已交付,已转换为指定为参数的速度范围。
您可以在我的博客中找到有关此部分的更多详细信息
步骤7:更多图片
这里还有aum2机器人的更多图片
今年一季度京东方持续稳居全球半导体显示龙头地位
FCI推出多端口和单端口RJ45模块插座连接器
鲁大师2023年Q1手机报告:魅族 20 PRO沉默中爆发,登顶整机流畅度榜单!
剖析电池包的直接降价空间有多少
2018年全球智能音箱Q3出货量达2270万台,中国成最大赢家
基于RaspberryPi Zero W的机器人的制作
NV080D语音芯片在加热器上的应用方案
曙光云计算集团为工业互联网应用奠定了良好的基础
保险丝原理
符合AEC Q-200标准的SMD系列产品PTC热敏电阻
负氧离子检测仪如何监测,它的特点是什么
AWS的新款DeepRacer Evo是一款AI驱动的模型车任务艰巨
国产最良心机器,即将发布新机,配置高于三星S8!
值得买的蓝牙耳机有哪些,真无线蓝牙耳机的推荐
Verizon将与诺基亚合作创建私人5G设备
led芯片失效原理
华为openEuler商用版本操作系统发布,加速鲲鹏相关技术的应用
芯明天压电扫描台应用于红外热成像扫描
电信网络系统的雷电防护和屏蔽处理措施
手机旺季降临需求回暖,摄像头产能利用率或逐季提升