https://github.com/jamesshao8/smart_car
smart_car
How to install:
- download the raspberry image for with pre-installed respeaker drivers: https://pan.baidu.com/s/1bprWJr5 password:t1m7
- copy gcc_phat.py included in this repository to the folder in voice engine where there is a file with the same name
- find the setup.py and type "sudo python setup.py install"
- you will also need to install opencv and arduino, they can all be installed through apt-get
Then all the libraries from 3rd party has been installed. Below is the steps for my own program:
- download the smart_arduino.ino to the arduino uno
- then run smart_raspberry.py on raspberry pi
Here's the video when running http://v.youku.com/v_show/id_XMzQwNzYzMjYyMA==.html
For hardware assembly, please refer to my blog: http://blog.csdn.net/shukebeta008/article/month/2018/02
如何安装:
- 下载预先安装的respeaker驱动程序的镜像: https ://pan.baidu.com/s/1bprWJr5密码:t1m7
- 将此存储库中包含的gcc_phat.py复制到语音引擎中具有相同名称的文件的文件夹中
- 找到setup.py并输入“sudo python setup.py install”
- 你还需要安装opencv和arduino,它们都可以通过apt-get安装
然后安装了第三方的所有库。以下是我自己的程序的步骤:
- 将smart_arduino.ino下载到arduino uno
- 然后在raspberry pi上运行smart_raspberry.py
这是运行http://v.youku.com/v_show/id_XMzQwNzYzMjYyMA==.html时的视频
代码:
元器件材料清单:
树莓派 *1
arduino UNO or Nano *1
L298N电机驱动模块 *1
前后轮马达 各1
转向马达 *1
7.2V锂电池 (电机驱动供电)
充电宝 5V 2A (树莓派)
手机USB线
USB-typeB
快换接头 *1
杜邦线
超声波
USB摄像头
越野车底盘
接线:
树莓派 :
microUSB - 5V 2A充电宝
USB - USB摄像头
USB - arduino UNO(树莓派给UNO板供电)
树莓派GPIO - respeaker模块
arduino UNO L298N电机驱动模块
5 IN1
6 IN2
9 IN3
10 IN4
GND GND
VIN +5V
arduino UNO 超声波模块
5V VCC
8 (EchoPin, INPUT)
7 (TrigPin, OUTPUT)
GND GND
UNO接USB供电,输出电流比较弱,可能无法驱动电机,需要 5V输入 端口,独立供电,
5V输入 UNO
GND GND
+5V VIN
A 前后轮马达(两个合一供电)
OUT1 马达 正极+ 红线
OUT 2 马达 负极- 黑线
B 转向马达
OUT3 马达 正极+ 红线
OUT 4 马达 负极- 黑线
主电源 7.2V锂电池
+12V 正极+
GND 负极-
2:驱动直流电机
|
如果要做电机调速,还可以让Arduino输出PWM波,而不是恒定的5V电平,达到控制速度的效果(本项目暂时没有用)。
原理图:
使用Protues进行Arduino仿真——Blink
https://blog.csdn.net/youshenmebutuo/article/details/76692332
https://www.cnblogs.com/hyper99/p/Arduino-UNO-fang-zhen-kai-fa-huan-jing-she-zhi-he-.html
CAD Circuits thinker 在线仿真
代码:
(主要本例为越野底盘,前后轮由5、6控制正反转,转向由9、10控制左右)
正转 反转 左转 右转 左后 右后
5 高 低 高 高 低 低
6 低 高 低 低 高 高
9 低 低 高 低 高 低
10 低 低 低 高 低 高
arduino:
int led = 13;
//float duration;
//float distance;
//int srfPin = 8;
const int TrigPin = 7; //发出超声波
const int EchoPin = 8; //收到反射回来的超声波
float cm; //因为测得的距离是浮点型的
void setup()
{
Serial.begin(9600);
pinMode(led, OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(TrigPin, OUTPUT);
pinMode(EchoPin, INPUT);
}
void loop()
{
delay(100); // wait for a second
if (Serial.available()>0)
{
char cmd = Serial.read();
Serial.print(cmd);
Serial.println();
switch (cmd)
{
case '1':
Forward();
break;
case '2':
Back();
break;
case '3':
Turn_left();
break;
case '4':
Turn_right();
break;
case '6':
Measure();
break;
case '7':
Turn_left_Back();
break;
case '8':
Turn_right_Back();
break;
case '9':
Stop();
default:
Stop();
}
}
}
void Forward()
{
digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,LOW);
}
void Back()
{
digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
}
void Turn_right()
{
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
digitalWrite(5,HIGH);
digitalWrite(6,LOW);
}
void Turn_left()
{
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,LOW);
}
void Turn_left_Back()
{
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
}
void Turn_right_Back()
{
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
}
void Stop()
{
digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
}
void Measure()
{
/*
pinMode(srfPin, OUTPUT);
digitalWrite(srfPin, LOW);
delayMicroseconds(2);
digitalWrite(srfPin, HIGH);
delayMicroseconds(10);
digitalWrite(srfPin, LOW);
pinMode(srfPin, INPUT);
duration = pulseIn(srfPin, HIGH);
distance = duration/58;
Serial.println(distance);
delay(50); */
digitalWrite(TrigPin, LOW); //低高低电平发一个短时间脉冲去TrigPin
delayMicroseconds(2); // delayMicroseconds在更小的时间内延时准确
digitalWrite(TrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(TrigPin, LOW); //通过这里控制超声波的发射
cm = pulseIn(EchoPin, HIGH) / 58.0; //将回波时间换算成cm
cm = (int(cm * 100.0)) / 100.0; 保留两位小数
Serial.print("Distance:");
Serial.print(cm);
Serial.print("cm");
Serial.println();
delay(50);
}
树莓派:
#!/usr/bin/env python
import socket
import sys
import threading
import random
import os
import time
import struct
import serial
#import cv
#import Image,StringIO
port_serial="/dev/ttyACM0"
sl = serial.Serial(port_serial,9600)
HOST = "0.0.0.0"
PORT = 9004
SOCK_ADDR = (HOST, PORT)
exit_now = 0
def exit_signal_handle(sig,stack_frame):
global exit_now
print "EXIT sig"
exit_now = 1
class serial_thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
self.running = True
while self.running:
try:
data=sl.readline()
print data
except:
print sys.exc_info()
def stop(self):
self.running = False
def forward():
print "forward"
string="1"
sl.write(string)
def reverse():
print "reverse"
string="2"
sl.write(string)
def pivot_left():
print "left"
string="3"
sl.write(string)
def pivot_right():
print "right"
string="4"
sl.write(string)
def stop():
print "stop"
string="0"
sl.write(string)
def net_input(command):
global laser_index_vertical
global laser_index_horizontal
if command == 1:
forward()
elif command == 2:
reverse()
elif command == 3:
pivot_left()
elif command == 4:
pivot_right()
elif command == 0:
stop()
###
class SocketClientObject(object):
def __init__(self, socket, address ):
self.socket = socket
self.address = address
###
class ClientThread(threading.Thread):
def __init__(self, client_object):
threading.Thread.__init__(self)
self.client_object = client_object
def run(self):
self.running = True
while self.running:
data = self.client_object.socket.recv(1024)
print ">> Received data: ", data, " from: ", self.client_object.address
if(data=='0'):
net_input(0)
elif(data=='1'):
net_input(1)
elif(data=='2'):
net_input(2)
elif(data=='3'):
net_input(3)
elif(data=='4'):
net_input(4)
elif(data=='5'):
break
print "client_quit"
self.client_object.socket.close()
def stop(self):
self.running = False
###
def main():
ser_th = serial_thread()
ser_th.start()
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(SOCK_ADDR)
sock.listen(5)
while exit_now == 0:
# accept connections from outside
(clientsocket, address) = sock.accept()
print " Accept client: ", address
# now do something with the clientsocket
# in this case, we'll pretend this is a threaded server
ct = ClientThread(SocketClientObject(clientsocket, address))
ct.start()
except:
print "#! EXC: ", sys.exc_info()
#sock.close()
#ser_th.stop()
#ser_th.join()
print "THE END! Goodbye!"
###
if __name__ == "__main__":
main()
PC端 控制程序::
#!/usr/bin/env python
import socket
import time
import pygame
import cv2.cv as cv
import PIL.Image, StringIO
import threading
import cv2
import numpy as np
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('192.168.1.10',9004))
pygame.init()
W, H = 320, 240
screen = pygame.display.set_mode((W, H))
clock = pygame.time.Clock()
running = True
command_to_send=0
command_last=0
laser_control = False
while running:
command_last=command_to_send
for event in pygame.event.get():
if event.type == pygame.QUIT:
command_to_send=5
running = False
elif event.type == pygame.KEYUP:
command_to_send=0
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
command_to_send=1
elif event.key == pygame.K_DOWN:
command_to_send=2
elif event.key == pygame.K_LEFT:
command_to_send=3
elif event.key == pygame.K_RIGHT:
command_to_send=4
if(command_to_send!=command_last):
sock.send(str(command_to_send))
clock.tick(50)
sock.close()
if __name__ == '__main__':
main()
小车arduino中运行的代码(只包含控制部分,不含超声波):
int led = 13;
void setup()
{
Serial.begin(9600);
pinMode(led, OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
}
void loop()
{
//digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(100); // wait for a second
//digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
//delay(1000); // wait for a second
if (Serial.available()>0)
{
char cmd = Serial.read();
Serial.print(cmd);
switch (cmd)
{
case '1':
Serial.println("Forward");
Forward();
break;
case '2':
Serial.println("Back");
Back();
break;
case '3':
Serial.println("Left");
Turn_left();
break;
case '4':
Serial.println("Right");
Turn_right();
break;
case '7':
Serial.println("left_Back");
Turn_left_Back();
break;
case '8':
Serial.println("right_Back");
Turn_right_Back();
break;
default:
Stop();
}
}
}
void Forward()
{
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,LOW);
}
void Back()
{
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
}
void Turn_right()
{
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
digitalWrite(5,HIGH);
digitalWrite(6,LOW);
}
void Turn_left()
{
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
}
void Turn_left_Back()
{
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
}
void Turn_right_Back()
{
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
}
void Stop()
{
digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
}
实物接线图:
具体操作:
1、UNO 通过USB连接电脑,打开.ino后缀的arduino文件,编译检查,上传烧录;
2、断开USB连接,进行断电接线;
3、先进行USB端口+UNO控制,超声波有数据返回,马达只是发出吱吱声并未转动,单个马达测试,低速转动,轻轻捏轴就能止动,用电压表测得L298N电机驱动模块 OUT1、OUT2输出电压为2V;刚开始还以为是程序出错或模块漏电,经排查后推断可能是供电不足,面包板5V电源输入后,测试马达加速运转,用L298N电机驱动模块 5V输入 端口供电后,马达正常转动。
左右转向测试过程中,已经break,车子停止,但马达扔低速运转,发出吱吱声,随优化下程序,虽然默认stop状态,但启动之后,增加case '9',可以通过COM串口 强制停止 Stop();实验证明,测试过程中随时终止马达运转,非常有效;
接下来arduino板子通过USB与树莓派连接通信:、
参考链接:
Arduino与树莓派间的通信实践
https://blog.csdn.net/ydogg/article/details/53307365
树莓派与arduino通信
https://blog.csdn.net/u011577439/article/details/51762076
树莓派与arduino通过USB进行通信 具体操作:
1、安装需要的库搭建环境:(GPIO库、arduino库、serial、minicom)本例已经安装好GPIO库,还没安装的按上述参考链接自行安装;
安装serial,用于串口或者USB通信
sudo apt-get install python-serial
安装串口调试工具
sudo apt-get install minicom
安装arduino库
sudo apt-get install arduino
2、将Arduino用USB线连接到树莓派的USB,在树莓派中输入
ls /dev/tty*
3、看有没有ttyUSB0或者ttyUSB1生成,如果两者没有连接是不会自动生成这个文件的,看到说明两者可以通讯了。(本例UNO 通过USB连接树莓派,并没有看到ttyACM0。)
查看有没有ttyACM0 这个文件(注只有在两个硬件USB互连的情况下才会有这个。如果两者没有连接是不会有的) 最新的系统一般都会自动生成。看到ttyACM0就说明二者可以通讯了 接下来上测试代码。(两个硬件USB互连的情况,具体选择,根据自己的链接方式来判断吧)
4、根据实际的端口情况修改树莓派代码;本例通过 ls /dev/tty* ,查看到ttyUSB0;
代码修改:把默认的 ttyACM0 改为 ttyUSB0 即可;
5、在树莓派上运行测试:
sudo python2 /home/pi/Desktop/smart_car-master/pi_part.py
运行后进入“假死”状态,其实是在等待PC端接入;
PC端环境搭建链接:
6、在PC端上运行控制端程序PC.py:
python /home/python/Desktop/PC.py
树莓派上看到接入信息:
PC端点击 pygame window,按 方向键 上下左右 控制:
树莓派端响应:
树莓派+arduino+小车测试流程:
1、确认arduino与小车各硬件连接正常后,L298N接入7.2V电池;USB自带供电太鸡肋,小车不能正常启动;
2、UNO通过USB链接树莓派;5V 2A充电器USB连接树莓派供电;
3、ssh进入树莓派,启动测试程序:
sudo python2 /home/pi/Desktop/smart_car-master/pi_part.py
4、打开虚拟机PC端,启动PC.py进入键盘控制:
python /home/python/Desktop/PC.py
5、鼠标点击 pygame控制窗口,按 上下左右 键进行控制;
7、关闭 pygame窗口,PC端程序自动退出,树退出莓派端程序提示用户端退出;
Ctrl+c接收树莓派端程序,完成测试:
整车测试:
千万不要用越野车底盘做智能小车,丑到它爸都不承认是亲生的,重心过高,7.2V锂电池+5V 2A充电宝,太重太高,跑起来往一边侧,根本无法体验越野性能,还是用正常4个减速电机的底盘比较稳妥。