用树莓派制作智能小车

用树莓派制作智能小车

DarkBull's Blog  2014-06-02  4164 阅读
 

    难得周末有空,折腾了一下智能不车。

    道具:树莓派,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" />
        </span><span class="pln">智能小车控制平台</span><span class="tag" style="color:rgb(128,0,0);">
         type="text/javascript" src=""/static/jquery.min.js">
    
    
    
         id="cav_dir" width="400" height="400" style="background-color: #eeeeee">
        您的浏览器不支持。
        
         id="spn">hello
         src="http://192.168.1.20:8090/?action=stream" />

         type="text/javascript">
        $(function() {
            var c=document.getElementById("cav_dir");
            var cxt=c.getContext("2d");
            
            var r = 200

            cxt.beginPath();
            cxt.fillStyle="rgba(0, 255, 0, 0.5)";
            cxt.arc(r, r, r, 0, Math.PI*2, false);
            cxt.closePath();

            cxt.lineWidth = 2
            cxt.strokeStyle = "'rgba(255,0,0,0.5)';
            cxt.moveTo(0, r - 1)
            cxt.lineTo(2 * r, r - 1)
            cxt.moveTo(r - 1, 0)
            cxt.lineTo(r - 1, 2 * r)
            cxt.stroke()

            cxt.fill();

            function run(event) {
                event = event || window.event
                event.preventDefault()
                var x = event.touches[0].clientX - r
                var y = event.touches[0].clientY - r
                var oInp = document.getElementById("spn");
                oInp.innerHTML = '(' + x + ',' + y + ')'
                if (x * x + y * y < r * r) {
                    $.post('/?x=' + x + '&y=' + y + '&r=' + r)
                }
            }

            function stop(event) {
                event = event || window.event
                event.preventDefault()
                $.post('?x=0&y=0&r=' + r)
            }

            c.addEventListener('touchstart',run, false);
            c.addEventListener('touchmove',run, false);
            c.addEventListener('touchend',stop, false);

        })
        
        
    

后台代码:

#!/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()

你可能感兴趣的:(private)