Raspberry Pi开发之旅-WIFI遥控小车

一、简单介绍树莓派的GPIO口

上图是树莓派2代的接口(不同型号接口会有差异),我们就以此为例来说下这些接口。

1、GPIO介绍

GPIO 英文全称是:General-purpose input/output 通用型之输入输出的简称,其接脚可以供使用者由程控自由使用,PIN脚依现实考量可作为通用输入(GPI)或通用输出(GPO)或通用输入与输出(GPIO)。通过这些GPIO口,我们可以控制很多第三方的寄存器设备,简单来说我们可以通过这些I/O口控制一些芯片的电路、读取传感器的数值等。

2、所需材料

 材料名称 数量
树莓派2代板子(包含电源、数据线、存储卡) 1
智能小车底盘(包含四个直流电机) 1
移动电源 1
L298N电机驱动板 1
杜邦线母对公 10
杜邦线母对母 10
无线网卡 1
4孔或6孔电池盒 1

3、安装所需软件

树莓派官方有两套GPIO的python库,分别是RPi.GPIORPIO。现在网络上许多关于树莓派GPIO文档的教程多数是RPi.GPIO,这个是老版本的库。而RPIO是用来替代前者的新版本。后面的课程我将使用RPIO这个库,来给大家演示。下面安装RPIO


1

2

sudo apt-get install python-dev python-pip

sudo pip install RPIO

二、 树莓派与L298N线路连接

1、第一步组装小车

组装底盘 分别用铜线连接两侧电机,并且保证同侧转向一致。如下图:

连接电机与L298N 将两侧侧的电机分别接入L298N的输出A和输出B,见下图:

连接L298N与树莓派 见上图逻辑输入部分有4个针脚(IN1、IN2、IN3、IN4),按照顺序分别连接到树莓派接口的11、12、16、18 四个口。见下图蓝色部分:

除了上面这些,还要将L298N的供电GND和树莓派的GPIO的6号Ground连接,形成供电回路。

连接电池盒与移动电源 将电池盒的正极连接到L298N的12V供电口,负极连接到L298N的供电GND口。完成连接后,L298N的供电GND口连接了两个线,分别是电池盒的负极和树莓派的6号Ground口。

2、测试小车

登录树莓派,vim robot.py文件:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

import RPIO as GPIO

import time

IN1 = 11

IN2 = 12

IN3 = 16

IN4 = 18

def init():

    GPIO.setmode(GPIO.BOARD)

    GPIO.setup(IN1, GPIO.OUT)

    GPIO.setup(IN2, GPIO.OUT)

    GPIO.setup(IN3, GPIO.OUT)

    GPIO.setup(IN4, GPIO.OUT)

def forward():

    GPIO.output(IN1,GPIO.HIGH)

    GPIO.output(IN2,GPIO.LOW)

    GPIO.output(IN3,GPIO.HIGH)

    GPIO.output(IN4,GPIO.LOW)

if __name__ == ‘__main__‘:

    init()

    forward()

    time.sleep(5)

    GPIO.cleanup()

保存退出后,用sudo python robot.py执行命令,小车将会向前进5秒。

备注:1、要避免静电和短路。2、接线要小心,尤其是正负极接线。

三、使用Python控制小车

1、Tornado介绍

Tornado是使用Python编写的一个强大的、可扩展的Web服务器。它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。

2、Tornado安装


1

2

3

4

5

$ curl --O https://github.com/facebook/tornado/archive/v3.1.0.tar.gz

$ tar xvzf v3.1.0.tar.gz

$ cd tornado-3.1.0

$ python setup.py build

$ sudo python setup.py install

Tornado官方并不支持Windows,但你可以通过ActivePython的PyPM包管理器进行安装,类似如下所示:


1

C:\> pypm install tornado

2、robot.py文件:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

#!/usr/bin/python

#coding: utf8

import RPIO as GPIO

import time

import sys

import threading

import tornado.ioloop

import tornado.web

import tornado.httpserver

import tornado.options

import json

tornado.options.define("port",default=8000,type=int)

IN1 = 11

IN2 = 12

IN3 = 16

IN4 = 18

stop_status = 0

last_key = ""

last_request_time = 0

def init():

    GPIO.setmode(GPIO.BOARD)

    GPIO.setup(IN1,GPIO.OUT)

    GPIO.setup(IN2,GPIO.OUT)

    GPIO.setup(IN3,GPIO.OUT)

    GPIO.setup(IN4,GPIO.OUT)

# 前进

def forward():

    global stop_status

    GPIO.output(IN1,GPIO.HIGH)

    GPIO.output(IN2,GPIO.LOW)

    GPIO.output(IN3,GPIO.HIGH)

    GPIO.output(IN4,GPIO.LOW)

    # print "forward"

    # time.sleep(0.1)

# 后退

def reverse():

    global stop_status

    GPIO.output(IN1,GPIO.LOW)

    GPIO.output(IN2,GPIO.HIGH)

    GPIO.output(IN3,GPIO.LOW)

    GPIO.output(IN4,GPIO.HIGH)

# 左转弯

def left():

    global stop_status

    GPIO.output(IN1,GPIO.LOW)

    GPIO.output(IN2,GPIO.HIGH)

    GPIO.output(IN3,GPIO.HIGH)

    GPIO.output(IN4,GPIO.LOW)

# 右转弯

def right():

    global stop_status

    GPIO.output(IN1,GPIO.HIGH)

    GPIO.output(IN2,GPIO.LOW)

    GPIO.output(IN3,GPIO.LOW)

    GPIO.output(IN4,GPIO.HIGH)

#停止

def stop_car():

    GPIO.output(IN1,False)

    GPIO.output(IN2,False)

    GPIO.output(IN3,False)

    GPIO.output(IN4,False)

    global stop_status

    stop_status = 1

#关闭GPIO接口

def close_car():

    global stop_status

    stop_status = 1

    GPIO.cleanup()

class IndexHandler(tornado.web.RequestHandler):

    def set_default_headers(self):

        self.set_header(‘Access-Control-Allow-Origin‘‘*‘)

        self.set_header(‘Access-Control-Allow-Methods‘‘POST, GET, OPTIONS‘)

        self.set_header(‘Access-Control-Allow-Headers‘‘*‘)

    def get(self):

        self.render("index.html")

    def post(self):

        global stop_status

        global last_key

        global last_request_time

        old_request_time = last_request_time

        init()

        sleep_time = 0.1

        try:

            arg = self.get_argument(‘k‘)

            new_request_time = self.get_argument(‘time‘)

            print ‘get last time‘,new_request_time

        except Exception, e:

            arg = json.loads(self.request.body)[‘k‘]

            new_request_time = json.loads(self.request.body)[‘time‘]

            print ‘json last time‘, new_request_time

        print "==new time ==", new_request_time

        print "==old time ==", old_request_time

        if(arg==‘w‘ and last_key!=‘w‘ and new_request_time >= old_request_time):

            print "forward"

            stop_status = 0

            autoThread = threading.Thread(target = forward)

            autoThread.start()

            last_key = ‘w‘

        elif(arg==‘s‘ and last_key!=‘s‘ and new_request_time >= old_request_time):

            print "reverse"

            stop_status = 0

            autoThread = threading.Thread(target = reverse)

            autoThread.start()

            last_key = ‘s‘

        elif(arg==‘a‘ and last_key!=‘a‘ and new_request_time >= old_request_time):

            print "left"

            stop_status = 0

            autoThread = threading.Thread(target = left)

            autoThread.start()

            last_key = ‘a‘

        elif(arg==‘d‘ and last_key!=‘d‘ and new_request_time >= old_request_time):

            print "right"

            stop_status = 0

            autoThread = threading.Thread(target = right)

            autoThread.start()

            last_key = ‘d‘

        elif(arg==‘stop‘ and new_request_time >= old_request_time):

            print "stop"

            last_key = "stop"

            time.sleep(0.3)

            stop_car()

        else:

            print "error"

        last_request_time = new_request_time

        self.write(arg)

    def options(self):

            pass

if __name__ == ‘__main__‘:

    tornado.options.parse_command_line()

    app = tornado.web.Application(handlers=[(r"/",IndexHandler)])

    http_server = tornado.httpserver.HTTPServer(app)

    http_server.listen(tornado.options.options.port)

    tornado.ioloop.IOLoop.instance().start()

3、index.html文件:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

<!DOCTYPE html>

<html>

<head>

        <meta charset="utf-8" />

        <title>WIFI小车客户端</title>

        <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script>

</head>

<body>

<script type="text/javascript">

        function go(k){

                var requestTime= new Date().getTime();

                $.post(‘/‘,{k:k,time:requestTime},function(){},"json");

        }

        $(function(){

                var i = null;

                window.document.onkeydown = keyDown;

                function keyDown(env){

                        env = (env) ? env : window.event;

                        if(env.keyCode==‘87‘){

                                go(‘w‘);

                        }

                        if(env.keyCode==‘83‘){

                                go(‘s‘);

                        }

                        if(env.keyCode==‘65‘){

                                go(‘a‘);

                        }

                        if(env.keyCode==‘68‘){

                                go(‘d‘);

                        }

                };

                window.document.onkeyup = keyUp;

                function keyUp(env){

                        env = (env) ? env : window.event;

                        if(env.keyCode==‘87‘){

                                go(‘stop‘);

                        }

                        if(env.keyCode==‘83‘){

                                go(‘stop‘);

                        }

                        if(env.keyCode==‘65‘){

                                go(‘stop‘);

                        }

                        if(env.keyCode==‘68‘){

                                go(‘stop‘);

                        }

                }

                $(‘.before‘).mousedown(function(){

                        = setInterval(function(){

                                go(‘w‘);

                        },100);

                });

                $(‘.left‘).mousedown(function(){

                        = setInterval(function(){

                                go(‘a‘);

                        },100);

                });

                $(‘.right‘).mousedown(function(){

                        = setInterval(function(){

                                go(‘d‘);

                        },100);

                });

                $(‘.cabk‘).mousedown(function(){

                        = setInterval(function(){

                                go(‘s‘);

                        },100);

                });

                $(‘#main span‘).mouseup(function(){

                        clearInterval(i);

                        go(‘stop‘);

                });

        });

</script>

<style type="text/css">

        #main{width: 150px;height: 150px;background: #ccc;}

        #main span{width: 50px;height: 50px;float: left;z-index: 999;}

        #main span.on2{background: #ff00ff;}

</style>

<div id="main">

        <span></span>

        <span class="on2 before"></span>

        <span></span>

        <span class="on2 left"></span>

        <span></span>

        <span class="on2 right"></span>

        <span></span>

        <span class="on2 cabk"></span>

        <span></span>

</div>

</body>

</html>

在命令行里尝试运行这个程序以测试输出:


1

$ sudo python robot.py

在本地浏览器中打开http://localhost:8000,或者其他计算机使用浏览器中打开http://PI的IP:8000/

四、远程控制小车

ionic环境搭建

安装ionic


1

npm install -g cordova ionic

克隆小车客户端代码


1

git clone https://github.com/jingzhaoyang/AutoClient.git

编译代码


1

2

3

4

5

6

#添加平台

ionic platform add android

#编译android的apk安装包

ionic build android

#启动android模拟器

ionic emulate android

在build目录有编译好的apk文件,可以直接在Android平台直接使用。并且通过终端控制小车。

时间: 2024-12-23 13:58:55

Raspberry Pi开发之旅-WIFI遥控小车的相关文章

Raspberry Pi开发之旅-发送邮件记录时间及IP

由于我使用树莓派的场景大多数是在没有显示器.只用terminal连接它的情况下,所以,它的IP地址有时会在重启之后变掉(DHCP的),导致我无法通过terminal连接上它.然后我又要很麻烦地登录路由器的管理界面里,去看它被分配到的新IP是什么,然后用terminal重连,太麻烦了,不是么?作为一个树莓派玩家,这种麻烦简直是无法接受的! 为了解决这个问题,我让Pi开机的时候,自动向我指定的Email发送一封邮件,告诉我它此次开机时的IP地址. 步骤: 开机时执行一个脚本,检测网络可用性→网络通畅

Raspberry Pi开发之旅-同步时间

使用htpdate同步时间 由于树莓派板子上没有 RTC 硬件和电池,因此树莓派上的系统时间重启是保存不了的.网上已经有人想到应对 NTP 被防火墙封掉类似的需求了,开源的 htpdate 命令直接使用 HTTP 协议来进行系统时间同步,项目主页在这里: https://github.com/iridium77/htpdate htpdate 的原理也非常简单,直接解析 HTTP 协议头中的服务器时间信息,然后设置本地时间,我们来看百度返回的 HTTP 头: HTTP/1.1 200 OK Da

Raspberry Pi开发之旅-实现云平台监控

一.基本设置 1 sudo raspi-config 移动到第五项"Enable Camera",回车进入,按tab键切换到"Enable"回车确认.回到主菜单,tab键切换到"Finish"回车确认.树莓派会自动重启. 或者执行命令手动关机 1 sudo shutdown -h now 警告!!!!!!!!!!!!!!!!!!!!!!!!!绝对不可以带着电源的情况下插入摄像头,如果带电操作,十之八九你的摄像头会GG,博主血泪教训.而且摄像头GG

Raspberry Pi开发之旅-空气温湿度检测(DHT11)

一.首先,简单介绍下DHT11: DHT11是一个温湿度传感器,分为3个接口,分别为:VCC, DATA, GND  引脚号 名称 类型 说明 1 VCC 电源 +级,输入3V-5.5V 2 DATA 数据输出 输出引脚 3 GND 接地 接地引脚 之前看网上说,需要在DHT11VCC和DATA之间加一个电阻,经试验完全不需要. 二.引脚连接: 1.VCC接上3V,可以选择1口或者17口 2.DATA接上GPIO口,我选的是GPIO4,第7口 3.GND接上接地口,我选的是第14口 三.Pyth

Raspberry Pi开发之旅-远程监控

1.安装辅助工具 1 2 sudo apt-get install libjpeg8-dev sudo apt-get install cmake 2.编辑源文件 1 2 sudo git clone <a href="https://github.com/jacksonliam/mjpg-streamer" target="_blank">https://github.com/jacksonliam/mjpg-streamer<br><

Raspberry Pi开发之旅-土壤湿度检测

一.土壤传感器 传感器四个针脚:  针脚 含义 AO 模拟信号输出 DO 数字信号输出 GND 电源负极 VCC 电源正极 二.接线 YL-38和YL69 之间直接用2根母对母线连接. YL-38和树莓派之间VCC接1号针脚,GND接6号针脚,DO接11号针脚. 我们把VCC接到树莓派的DC3.3v输出上,我用的是PIN 01,GND接在任何一个接地端口上,我用的是PIN 06,DO输出接任何一个空闲的GPIO端口,我用的是11.如果不清楚树莓派端口布局的朋友可以参考这张图: 电源连通之后,电源

将树莓派Raspberry Pi设置为无线路由器(WiFi热点AP,RTL8188CUS芯片)

本文是基于在某东购买的usb无线网卡(RTL8188CUS芯片)来制作无线热点.本来想制作一个一键脚本.只是先把实现的过程记录下来. 參考文章 Turn Your Raspberry Pi Into a WiFi Hotspot with Edimax Nano USB EW-7811Un (RTL8188CUS chipset) Why won't dnsmasq's DHCP server work when using hostapd? 1.更新系统,安装须要的软件 我们首先须要更新系统.

【树莓派】【转】将树莓派Raspberry Pi设置为无线路由器(WiFi热点AP,RTL8188CUS芯片)

下文为转载,文章转自:http://wangye.org/blog/archives/845/,仅供本次学习实践参考. 最近又开始折腾起Raspberry Pi来了,因为某处上网需要锐捷拨号,于是我就想能不能让我的树莓派代劳,当然首先要将其改造为路由器,默认自带的网口作为WAN口,我们还缺一个网口,木有办法,只好占用一个USB口,接上一个USB网卡,网上的USB转RJ45网线口的适配器比较少,价格也不便宜,于是就考虑干脆将其改造成无线路由,也符合时下高端大气上档次的标准. 准备工作,当然要先去购

最简单的RASPBERRY PI wifi配置

Setting up Wifi with the Command Line  SIMON MONK This tutorial works best if your router is broadcasting the SSID. Make sure you have "Broadcast SSID" set up on your router! This may not work with "private" SSID setups Setting up WiFi