难得周末有空,折腾了一下智能不车。
道具:树莓派,usb无线网卡,L298N电机驱动板,usb移动电源一个,两块手机电板(串联组成7.2v的电源供小车驱动),智能小车底盘,杜邦线若干,橡皮筋若干,电脑一台
原理:通过树莓派的gpio接口,控制电机驱动及速度,实现小车的前进后退,变向。
电机通过L298N驱动,其中电路图为:
小车的电机驱动需要外接电源,不可从树莓派的gpio口取电,gpio口只提供5v的电压,驱动电机够吃力的,轻者造成树莓派死机,重者直接把树莓派烧掉~~ 手头上刚好有几前买过的一只山寨机的两块电板,刚好拿来,串联成一个7.2v的电源。
车轮的速度可以通过pmw控制,随便找两个gpio口,连接到驱动电板的ena、enb,控制,非常方便。
小车的控制,我走的是http,在树莓派上运行一个tornado进程,在手机上通过触控控制。如果左轮的速度>右轮,则右转,反之左转。web界面很简单,如下图,点到哪里,得到一个相对于圆心的点,根据点到圆心的x,y轴距离,算出小车左右轮的速度,从而通过pwm控制小车。界面使用了html5的canvas。本来在小车上装了个摄像头,通过mjpg-stream把图像实时显示在网页上,无奈摄像头太差,就不加了。下次要买个nb点的摄像头。
越来越赖了,直接贴源码,作个标记,下次继续完善:加个机械臂,装一大堆传感器。
前台代码:
xmlns="http://www.w3.org/1999/xhtml">
http-equiv="Content-Type" content="text/html; charset=UTF-8" />
智能小车控制平台
id="spn">hello
src="http://192.168.1.20:8090/?action=stream" />
后台代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: darkbull
# @Date: 2014-05-31 10:02:21
# @Last Modified by: darkbull
# @Last Modified time: 2014-06-02 15:29:20
"""Web控制树莓派小车
"""
import tornado.web
import tornado.ioloop
import codecs
import RPi.GPIO as GPIO
import time
import atexit
import math
atexit.register(GPIO.cleanup)
GPIO.setmode(GPIO.BCM)
IN1 = 17
IN2 = 22
IN3 = 23
IN4 = 24
# 左边轮速度控制
PWM_L = 8
PWM_R = 7
GPIO.setup(IN1, GPIO.OUT, initial=False)
GPIO.setup(IN2, GPIO.OUT, initial=False)
GPIO.setup(IN3, GPIO.OUT, initial=False)
GPIO.setup(IN4, GPIO.OUT, initial=False)
GPIO.setup(PWM_L, GPIO.OUT, initial=False)
GPIO.setup(PWM_R, GPIO.OUT, initial=False)
pwm_l = GPIO.PWM(PWM_L, 50)
pwm_l.start(0)
pwm_r = GPIO.PWM(PWM_R, 50)
pwm_r.start(0)
def front():
GPIO.output(IN1, True)
GPIO.output(IN2, False)
GPIO.output(IN3, True)
GPIO.output(IN4, False)
def back():
GPIO.output(IN1, False)
GPIO.output(IN2, True)
GPIO.output(IN3, False)
GPIO.output(IN4, True)
# def left():
# # GPIO.output(IN1, False)
# # GPIO.output(IN2, True)
# GPIO.output(IN1, False)
# GPIO.output(IN2, False)
# GPIO.output(IN3, True)
# GPIO.output(IN4, False)
# def right():
# # GPIO.output(IN1, True)
# # GPIO.output(IN2, False)
# GPIO.output(IN1, False)
# GPIO.output(IN2, False)
# GPIO.output(IN3, False)
# GPIO.output(IN4, True)
def stop():
GPIO.output(IN1, False)
GPIO.output(IN2, False)
GPIO.output(IN3, False)
GPIO.output(IN4, False)
def run(x, y, r):
"""小车运行
"""
if x * x + y * y > r * r:
return
speed_min = 15
speed_max = 100
speed_delta = speed_max - speed_min
# y轴为小车的运行方向,速度以y轴的值为基准
if y < 0:
back()
elif y > 0:
front()
else:
stop()
return
t = abs(y) * 100.0 / r
if t < 20: # 电压太小,驱动不起来
t = 20
d = math.atan2(x, y) * 180 / math.pi
if x < 0: # 往左边偏, 右轮的速度比左轮快
t2 = t * (abs(90 + d) / 90)
pwm_r.ChangeDutyCycle(t)
pwm_l.ChangeDutyCycle(t2)
elif x > 0: # 往右边偏, 左边的速度比右轮快
t2 = t * (abs(90 - d) / 90)
pwm_l.ChangeDutyCycle(t)
pwm_r.ChangeDutyCycle(t2)
print x, y, t, t2
class CarController(tornado.web.RequestHandler):
def get(self):
with codecs.open('webcar.html', 'r', encoding='utf-8') as fp:
self.write(fp.read())
def post(self):
r = int(self.get_argument('r'))
x = int(self.get_argument('x'))
y = int(self.get_argument('y'))
run(x, y, r)
self.write('ok')
if __name__ == '__main__':
app = tornado.web.Application([('/', CarController)], static_path='static', debug=True)
app.listen(18080)
tornado.ioloop.IOLoop.instance().start()