接下来可以说是本教程的核心内容了,不可能在一篇文章中讲完,首先讲一个比较初级的程序。树莓派可以接收同一个局域网上电脑的连接,并且电脑键盘上发出的前后左右的控制信号通过网络发向树莓派后,树莓派再经过串口发向Arduino,对电机进行控制。
树莓派需要实现的程序分为两部分,一个是Socket服务器,另一个是串口写入的代码。涉及到多线程知识。
客户端程序作为Socket客户端连入树莓派,然后通过pygame库获取键盘命令后把运动指令发往树莓派。
树莓派的程序稍微复杂些,首先主循环是监听客户端连入,连入后用另一个线程对从客户端发来的数据进行处理,把指令用串口下发给Arduino。当指令涉及到超声波读取时,树莓派用另一个线程去监听串口收到的数据,这个数据就是距离数据(为了尽量简化,下面的代码范例中不含超声波读取部分,完整部分参见后面教程中的最终程序)。
下面贴上部分代码:
首先是运行于小车树莓派中的程序:
#!/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 pause(): print "pause" 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: pause() ### 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()
接下来是电脑控制端运行的程序:
#!/usr/bin/env python import socket import time import pygame import cv2.cv as cv import 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; 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 Stop() { digitalWrite(9,LOW); digitalWrite(10,LOW); digitalWrite(5,LOW); digitalWrite(6,LOW); }
