擊上方“果果小師弟”,選擇“置頂/星標(biāo)公眾號”
摘要:制作這個(gè)項(xiàng)目的起因是大一下學(xué)期那會(huì)兒我通過學(xué)校圖書館里的《無線電》雜志開始接觸Raspberry Pi卡片式計(jì)算機(jī)和Arduino微控制器,其中Raspberry Pi給當(dāng)初什么都不懂的我留下了非常深刻的印象:一個(gè)信用卡大小的板子竟然可以跑帶有圖形界面的GNU/Linux操作系統(tǒng)。
在強(qiáng)烈探索欲的驅(qū)使下,我從網(wǎng)上購買了兩塊Element14的Raspberry Pi一代Model B(現(xiàn)在早已經(jīng)絕版了)板子以及其他相關(guān)配件,開始在Raspbian系統(tǒng)上自學(xué)Python和各種傳感器的使用方法,后來為了檢驗(yàn)一下自己的學(xué)習(xí)成果,于是我便花費(fèi)幾周的時(shí)間做了這個(gè)簡單的輪式機(jī)器人。雖然它涉及的原理并不復(fù)雜,但是對于那會(huì)兒剛開始接觸嵌入式的我來說,能成功搭建一個(gè)完整的機(jī)器人系統(tǒng)還是挺有挑戰(zhàn)性的。
概述簡單輪式機(jī)器人其實(shí)是一個(gè)比較傳統(tǒng)的入門級智能小車,它擁有藍(lán)牙遠(yuǎn)程遙控、超聲波避障、紅外邊緣檢測和紅外巡線(未完成)等功能,可以完成一些有趣的小實(shí)驗(yàn)。此外,簡單輪式機(jī)器人的軟件是開源的,具體代碼可以從我的GitHub倉庫上獲得。
原理硬件以下是該簡單輪式機(jī)器人的硬件系統(tǒng)連接圖:
核心主控
系統(tǒng)的硬件核心主控分別為Arduino和Raspberry Pi。其中Arduino主要負(fù)責(zé)接收紅外光電測距模塊的數(shù)據(jù),并控制裝有超聲波模塊的單軸舵機(jī)云臺(tái)的旋轉(zhuǎn);而Raspberry Pi則可通過電機(jī)驅(qū)動(dòng)模塊來完成對四個(gè)直流減速電機(jī)轉(zhuǎn)向和轉(zhuǎn)速的控制,此外它還能接收超聲波模塊和從Arduino串口發(fā)送上來的紅外光電測距模塊的數(shù)據(jù)來判斷當(dāng)前機(jī)器人的前方和兩側(cè)是否遇到障礙物,若機(jī)器人與障礙物之間的距離小于一個(gè)特定的閾值,則Arduino和Raspberry Pi會(huì)分別改變LED的顏色并啟動(dòng)蜂鳴器來發(fā)出警報(bào)。
當(dāng)然,肯定會(huì)有人問:為什么我不能僅用Raspberry Pi來作為機(jī)器人的核心主控,非要再用一個(gè)Arduino呢?其實(shí)根據(jù)本項(xiàng)目的實(shí)際需求,確實(shí)只用一個(gè)Raspberry Pi就夠了,不過對于我來說使用Arduino主要出于以下三個(gè)原因的考慮:
Raspberry Pi一代Model B板子的GPIO引腳數(shù)量只有26個(gè),就算復(fù)用一些帶有特殊功能的引腳,引腳資源依舊比較緊張。
Raspberry Pi官方提供的GPIO庫雖然含有PWM函數(shù),但是實(shí)際在控制舵機(jī)的時(shí)候可能是由于軟件模擬的PWM方波還不夠穩(wěn)定,導(dǎo)致舵機(jī)抖動(dòng)得比較厲害。
可以學(xué)習(xí)Python的串口編程。
因此,綜合以上三個(gè)方面我選擇了Arduino和Raspberry Pi雙核心主控的系統(tǒng)架構(gòu)。
外部電源
因?yàn)闀r(shí)間比較緊張,所以我沒有在電源管理上花費(fèi)太多的功夫。對于Arduino,我使用的是能裝下6個(gè)1.5V干電池的的電池盒給其供電,而對于Raspberry Pi耗電量較大的需求,我是從大學(xué)舍友那借了一個(gè)充電寶來解決問題的,不過雖然供電可以了,但是由于充電寶的重量比較大,導(dǎo)致四個(gè)輪子受壓偏大,使得遙控的精準(zhǔn)度受到了一定的影響。
電機(jī)驅(qū)動(dòng)
機(jī)器人的電機(jī)驅(qū)動(dòng)部分采用傳統(tǒng)的L293D芯片,它是一款單片集成的高電壓、高電流、四通道電機(jī)驅(qū)動(dòng)芯片,其內(nèi)部包含有兩個(gè)雙極型H橋電路,可通過設(shè)置IN1和IN2輸入引腳的邏輯電平來控制電機(jī)的旋轉(zhuǎn)方向,而EN使能引腳可連接到一路PWM上,通過調(diào)整PWM方波的占空比便可調(diào)整電機(jī)的轉(zhuǎn)速。
數(shù)據(jù)感知
為了能實(shí)現(xiàn)最基本的避障功能,我們需要為機(jī)器人配備有一些傳感器。這里我使用的傳感器為HC-SR04超聲波測距模塊和紅外光電避障模塊,其中紅外光電避障模塊具有一對紅外線發(fā)射與接收管,運(yùn)行時(shí)發(fā)射管會(huì)發(fā)射出一定頻率的紅外線,當(dāng)檢測方向遇到障礙物后,紅外線會(huì)反射回來被接收管接收,經(jīng)過比較電路處理之后,信號輸出接口會(huì)輸出一個(gè)低電平信號,這樣只要在程序中對該接口的電平進(jìn)行判斷便能得知機(jī)器人是否距離障礙物比較近。
與紅外光電避障模塊的工作原理類似,超聲波模塊能夠向空中發(fā)射超聲波信號,當(dāng)其檢測到反射回來的信號后,只需將超聲波從發(fā)射到接收所用的時(shí)間乘上聲速再除以二便能得到機(jī)器人和障礙物之間的距離,從而為之后的機(jī)器人避障做好準(zhǔn)備。
軟件Raspberry Pi庫代碼
simple_wheeled_robot_lib.py
該庫代碼實(shí)現(xiàn)了GPIO引腳初始化函數(shù)、LED燈設(shè)置函數(shù)、蜂鳴器設(shè)置函數(shù)、電機(jī)控制函數(shù)、超聲波測距函數(shù)和LCD1602顯示函數(shù),其中LCD1602顯示函數(shù)調(diào)用了Python的SMBUS庫來完成IIC數(shù)據(jù)通信,從而能將字符串顯示在屏幕上(注意:SMBUS和IIC協(xié)議之間是存在區(qū)別的,但在Raspberry Pi上兩者概念基本等同)。
import time
import smbus
import RPi.GPIO as gpio
motor_run_left = 17
motor_run_right = 10
motor_direction_left = 4
motor_direction_right = 25
led_left = 7
led_right = 8
ultrasonic_trig = 23
ultrasonic_echo = 24
servo = 11
buzzer = 18
lcd_address = 0x27
data_bus = smbus.SMBus(1)
class SimpleWheeledRobot:
def __init__(self):
gpio.setmode(gpio.BCM)
gpio.setup(motor_run_left, gpio.OUT)
gpio.setup(motor_run_right, gpio.OUT)
gpio.setup(motor_direction_left, gpio.OUT)
gpio.setup(motor_direction_right, gpio.OUT)
gpio.setup(led_left, gpio.OUT)
gpio.setup(led_right, gpio.OUT)
def set_motors(self, run_left, direction_left, run_right, direction_right):
gpio.output(motor_run_left, run_left)
gpio.output(motor_run_right, run_right)
gpio.output(motor_direction_left, direction_left)
gpio.output(motor_direction_right, direction_right)
def set_led_left(self, state):
gpio.output(led_left, state)
def set_led_right(self, state):
gpio.output(led_right, state)
def go_forward(self, seconds):
if seconds == 0:
self.set_motors(1, 1, 1, 1)
self.set_led_left(1)
self.set_led_right(1)
else:
self.set_motors(1, 1, 1, 1)
time.sleep(seconds)
gpio.cleanup()
def go_reverse(self, seconds):
if seconds == 0:
self.set_motors(1, 0, 1, 0)
self.set_led_left(0)
self.set_led_right(0)
else:
self.set_motors(1, 0, 1, 0)
time.sleep(seconds)
gpio.cleanup()
def go_left(self, seconds):
if seconds == 0:
self.set_motors(0, 0, 1, 1)
self.set_led_left(1)
self.set_led_right(0)
else:
self.set_motors(0, 0, 1, 1)
time.sleep(seconds)
gpio.cleanup()
def go_right(self, seconds):
if seconds == 0:
self.set_motors(1, 1, 0, 0)
self.set_led_left(0)
self.set_led_right(1)
else:
self.set_motors(1, 1, 0, 0)
time.sleep(seconds)
gpio.cleanup()
def go_pivot_left(self, seconds):
if seconds == 0:
self.set_motors(1, 0, 1, 1)
self.set_led_left(1)
self.set_led_right(0)
else:
self.set_motors(1, 0, 1, 1)
time.sleep(seconds)
gpio.cleanup()
def go_pivot_right(self, seconds):
if seconds == 0:
self.set_motors(1, 1, 1, 0)
self.set_led_left(0)
self.set_led_right(1)
else:
self.set_motors(1, 1, 1, 0)
time.sleep(seconds)
gpio.cleanup()
def stop(self):
self.set_motors(0, 0, 0, 0)
self.set_led_left(0)
self.set_led_right(0)
def buzzing(self):
gpio.setup(buzzer, gpio.OUT)
gpio.output(buzzer, True)
for x in range(5):
gpio.output(buzzer, False)
time.sleep(0.1)
gpio.output(buzzer, True)
time.sleep(0.1)
def get_distance(self):
gpio.setmode(gpio.BCM)
gpio.setup(ultrasonic_trig, gpio.OUT)
gpio.setup(ultrasonic_echo, gpio.IN)
gpio.output(ultrasonic_trig, False)
while gpio.input(ultrasonic_echo) == 0:
start_time = time.time()
while gpio.input(ultrasonic_echo) == 1:
stop_time = time.time()
duration = stop_time - start_time
distance = (duration * 34300) / 2
gpio.cleanup()
return distance
def send_command(self, command):
buf = command & 0xF0
buf |= 0x04
data_bus.write_byte(lcd_address, buf)
time.sleep(0.002)
buf &= 0xFB
data_bus.write_byte(lcd_address, buf)
buf = (command & 0x0F) 《《 4
buf |= 0x04
data_bus.write_byte(lcd_address, buf)
time.sleep(0.002)
buf &= 0xFB
data_bus.write_byte(lcd_address, buf)
def send_data(self, data):
buf = data & 0xF0
buf |= 0x05
data_bus.write_byte(lcd_address, buf)
time.sleep(0.002)
buf &= 0xFB
data_bus.write_byte(lcd_address, buf)
buf = (data & 0x0F) 《《 4
buf |= 0x05
data_bus.write_byte(lcd_address, buf)
time.sleep(0.002)
buf &= 0xFB
data_bus.write_byte(lcd_address, buf)
def initialize_lcd(self):
try:
self.send_command(0x33)
time.sleep(0.005)
self.send_command(0x32)
time.sleep(0.005)
self.send_command(0x28)
time.sleep(0.005)
self.send_command(0x0C)
time.sleep(0.005)
self.send_command(0x01)
except:
return False
else:
return True
def clear_lcd(self):
self.send_command(0x01)
def print_lcd(self, x, y, lcd_string):
if x 《 0:
x = 0
if x 》 15:
x = 15
if y 《 0:
y = 0
if y 》 1:
y = 1
address = 0x80 + 0x40 * y + x
self.send_command(address)
for lcd_char in lcd_string:
self.send_data(ord(lcd_char))
def move_servo_left(self):
servo_range = 13
gpio.setmode(gpio.BCM)
gpio.setup(servo, gpio.OUT)
pwm = gpio.PWM(servo, 100)
pwm.start(0)
while servo_range 《= 23:
pwm.ChangeDutyCycle(servo_range)
servo_range += 1
time.sleep(0.5)
pwm.stop()
def move_servo_right(self):
servo_range = 13
gpio.setmode(gpio.BCM)
gpio.setup(servo, gpio.OUT)
pwm = gpio.PWM(servo, 100)
pwm.start(0)
while servo_range 》= 0:
pwm.ChangeDutyCycle(servo_range)
servo_range -= 1
time.sleep(0.5)
pwm.stop()
Raspberry Pi測試代碼1
simple_wheeled_robot_run_1.py
該代碼調(diào)用了上面自己編寫的機(jī)器人代碼庫,主要實(shí)現(xiàn)了超聲波距離檢測函數(shù)和鍵盤遙控函數(shù),其中鍵盤遙控函數(shù)里面又根據(jù)所按按鍵的不同調(diào)用并組合上面代碼庫中的不同函數(shù)來完成某些特定的功能(比如機(jī)器人遇到障礙物后首先會(huì)發(fā)出警報(bào),然后再進(jìn)行相應(yīng)的規(guī)避運(yùn)動(dòng)等)。
import time
import serial
import random
import Tkinter as tk
import RPi.gpio as gpio
from simple_wheeled_robot_lib import SimpleWheeledRobot
simple_wheeled_robot = SimpleWheeledRobot()
simple_wheeled_robot.initialize_lcd()
port = “/dev/ttyUSB0”
serial_to_arduino = serial.Serial(port, 9600)
serial_from_arduino = serial.Serial(port, 9600)
serial_from_arduino.flushInput()
serial_to_arduino.write(‘n’)
def detecte_distance():
distance = simple_wheeled_robot.get_distance()
if distance 》= 20:
# Light up the green led.
serial_to_arduino.write(‘g’)
elif distance 》= 10:
# Light up the yellow led.
serial_to_arduino.write(‘y’)
elif distance 《 10:
# Light up the red led.
serial_to_arduino.write(‘r’)
simple_wheeled_robot.buzzing()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_reverse(2)
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_pivot_right(2)
# Check the distance between wall and car‘s both sides.
serial_to_arduino.write(’k‘)
data_from_arduino = serial_from_arduino.readline()
data_from_arduino_int = int(data_from_arduino)
# Car is too close to the left wall.
if data_from_arduino_int == 01:
simple_wheeled_robot.buzzing()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_right(2)
# Car is too close to the right wall.
elif data_from_arduino_int == 10:
simple_wheeled_robot.buzzing()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_left(2)
def input_key(event):
simple_wheeled_robot.__init__()
print ’Key‘, event.char
key_press = event.char
seconds = 0.05
if key_press.lower() == ’w‘:
simple_wheeled_robot.go_forward(seconds)
elif key_press.lower() == ’s‘:
simple_wheeled_robot.go_reverse(seconds)
elif key_press.lower() == ’a‘:
simple_wheeled_robot.go_left(seconds)
elif key_press.lower() == ’d‘:
simple_wheeled_robot.go_right(seconds)
elif key_press.lower() == ’q‘:
simple_wheeled_robot.go_pivot_left(seconds)
elif key_press.lower() == ’e‘:
simple_wheeled_robot.go_pivot_right(seconds)
elif key_press.lower() == ’o‘:
gpio.cleanup()
# Move the servo in forward directory.
serial_to_arduino.write(’o‘)
time.sleep(0.05)
elif key_press.lower() == ’h‘:
gpio.cleanup()
# Light up the logo.
serial_to_arduino.write(’h‘)
elif key_press.lower() == ’j‘:
gpio.cleanup()
# Turn off the logo.
serial_to_arduino.write(’j‘)
elif key_press.lower() == ’p‘:
gpio.cleanup()
# Move the servo in reverse directory.
serial_to_arduino.write(’p‘)
time.sleep(0.05)
elif key_press.lower() == ’i‘:
gpio.cleanup()
serial_to_arduino.write(’m‘)
# Enter the random run mode.
serial_to_arduino.write(’i‘)
for z in range(20):
x = random.randrange(0, 5)
if x == 0:
for y in range(30):
detecte_distance()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_forward(0.05)
elif x == 1:
for y in range(30):
detecte_distance()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_left(0.05)
elif x == 2:
for y in range(30):
detecte_distance()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_right(0.05)
elif x == 3:
for y in range(30):
detecte_distance()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_pivot_left(0.05)
elif x == 4:
for y in range(30):
detecte_distance()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_pivot_right(0.05)
data_from_arduino = serial_from_arduino.readline()
data_from_arduino_int = int(data_from_arduino)
if data_from_arduino_int == 1111:
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_forward(0.05)
if data_from_arduino_int == 1111:
simple_wheeled_robot.__init__()
simple_wheeled_robot.stop()
elif data_from_arduino_int == 0000:
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_forward(0.05)
elif data_from_arduino_int == 0100:
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_left(0.05)
elif data_from_arduino_int == 1000 or
data_from_arduino_int == 1100:
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_left(0.08)
elif data_from_arduino_int == 0010:
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_right(0.05)
elif data_from_arduino_int == 0001 or
data_from_arduino_int == 0011:
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_right(0.08)
serial_to_arduino.write(’l‘)
elif key_press.lower() == ’u‘:
gpio.cleanup()
simple_wheeled_robot.print_lcd(1, 0, ’UltrasonicWare‘)
simple_wheeled_robot.print_lcd(1, 1, ’Distance:%.lf CM‘ %
simple_wheeled_robot.get_distance())
else:
pass
distance = simple_wheeled_robot.get_distance()
if distance 》= 20:
serial_to_arduino.write(’g‘)
elif distance 》= 10:
serial_to_arduino.write(’y‘)
elif distance 《 10:
serial_to_arduino.write(’r‘)
simple_wheeled_robot.buzzing()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_reverse(2)
serial_to_arduino.write(’k‘)
data_from_arduino = serial_from_arduino.readline()
data_from_arduino_int = int(data_from_arduino)
if data_from_arduino_int == 1:
simple_wheeled_robot.buzzing()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_right(2)
elif data_from_arduino_int == 10:
simple_wheeled_robot.buzzing()
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_left(2)
try:
command = tk.Tk()
command.bind(’《KeyPress》‘, input_key)
command.mainloop()
except KeyboardInterrupt:
gpio.cleanup()
Raspberry Pi測試代碼2
simple_wheeled_robot_run_2.py
該代碼實(shí)現(xiàn)的功能比較簡單,僅測試了機(jī)器人的電機(jī)遙控和超聲波避障兩個(gè)功能。
import Tkinter as tk
import RPi.GPIO as gpio
from simple_wheeled_robot_lib import SimpleWheeledRobot
simple_wheeled_robot = SimpleWheeledRobot()
simple_wheeled_robot.initialize_lcd()
def input_key(event):
print ’Key‘, event.char
key_press = event.char
seconds = 0.05
if key_press.lower() == ’w‘:
simple_wheeled_robot.go_forward(seconds)
elif key_press.lower() == ’s‘:
simple_wheeled_robot.go_reverse(seconds)
elif key_press.lower() == ’a‘:
simple_wheeled_robot.go_left(seconds)
elif key_press.lower() == ’d‘:
simple_wheeled_robot.go_right(seconds)
elif key_press.lower() == ’q‘:
simple_wheeled_robot.go_pivot_left(seconds)
elif key_press.lower() == ’e‘:
simple_wheeled_robot.go_pivot_right(seconds)
elif key_press.lower() == ’o‘:
simple_wheeled_robot.move_servo_left()
elif key_press.lower() == ’p‘:
simple_wheeled_robot.move_servo_right()
else:
pass
distance = simple_wheeled_robot.get_distance()
simple_wheeled_robot.print_lcd(1, 0, ’UltrasonicWare‘)
simple_wheeled_robot.print_lcd(1, 1, ’Distance:%.lf CM‘ % distance)
print “Distance: %.1f CM” % distance
if distance 《 10:
simple_wheeled_robot.__init__()
simple_wheeled_robot.go_reverse(2)
try:
command = tk.Tk()
command.bind(’《KeyPress》‘, input_key)
command.mainloop()
except KeyboardInterrupt:
gpio.cleanup()
Raspberry Pi測試代碼3
simple_wheeled_robot_run_3.py
該代碼實(shí)現(xiàn)的功能與上面的測試代碼2類似,只不過圖形界面本代碼里使用的是Pygame而不是之前的Tkinter。
import sys
import pygame
from pygame.locals import *
import RPi.GPIO as gpio
from simple_wheeled_robot_lib import SimpleWheeledRobot
simple_wheeled_robot = SimpleWheeledRobot()
pygame.init()
screen = pygame.display.set_mode((800, 800))
font = pygame.font.SysFont(“arial”, 64)
pygame.display.set_caption(’SimpleWheeledRobot‘)
pygame.mouse.set_visible(0)
while True:
gpio.cleanup()
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
if event.type == KEYDOWN:
time = 0.03
if event.key == K_UP or event.key == ord(’w‘):
simple_wheeled_robot.go_forward(time)
elif event.key == K_DOWN or event.key == ord(’s‘):
simple_wheeled_robot.go_reverse(time)
elif event.key == K_LEFT or event.key == ord(’a‘):
simple_wheeled_robot.go_left(time)
elif event.key == K_RIGHT or event.key == ord(’d‘):
simple_wheeled_robot.go_right(time)
elif event.key == ord(’q‘):
simple_wheeled_robot.go_pivot_left(time)
elif event.key == ord(’e‘):
simple_wheeled_robot.go_pivot_right(time)
Arduino測試代碼
simple_wheeled_robot.ino
該代碼從邏輯上比較好理解,在setup()函數(shù)初始化引腳的模式和串口波特率后,主函數(shù)loop()會(huì)不斷地從串口中讀取字符數(shù)據(jù),并根據(jù)字符的不同進(jìn)行不同的處理工作。
int distance;
int distance_left;
int distance_right;
int motor_value;
int motor_value_a;
int motor_value_b;
int motor_value_c;
int motor_value_d;
int motor_a = 6;
int motor_b = 7;
int motor_c = 8;
int motor_d = 9;
int servo = 5;
int led = 2;
int led_red = 13;
int led_yellow = 12;
int led_green = 11;
int distance_sensor_left = 3;
int distance_sensor_right = 4;
char data;
uint16_t angle = 1500;
void setup()
{
// Set serial’s baud rate.
Serial.begin(9600);
pinMode(motor_a, INPUT);
pinMode(motor_b, INPUT);
pinMode(motor_c, INPUT);
pinMode(motor_d, INPUT);
pinMode(servo, OUTPUT);
pinMode(led , OUTPUT);
pinMode(led_red, OUTPUT);
pinMode(led_yellow, OUTPUT);
pinMode(led_green, OUTPUT);
pinMode(distance_sensor_left, INPUT);
pinMode(distance_sensor_right, INPUT);
pinMode(A0, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
}
void loop()
{
if (Serial.available()) {
switch(Serial.read()) {
// Light up the logo.
case ‘h’: {
digitalWrite(A0, HIGH);
digitalWrite(A1, HIGH);
digitalWrite(A2, HIGH);
digitalWrite(A3, HIGH);
digitalWrite(A4, HIGH);
digitalWrite(A5, HIGH);
break;
}
// Turn off the logo.
case ‘j’: {
digitalWrite(A0, LOW);
digitalWrite(A1, LOW);
digitalWrite(A2, LOW);
digitalWrite(A3, LOW);
digitalWrite(A4, LOW);
digitalWrite(A5, LOW);
break;
}
// Move the servo in forward directory.
case ‘o’ : {
angle += 50;
if (angle 》 2500) {
angle = 2500;
}
break;
}
// Move the servo in reverse directory.
case ‘p’ : {
angle -= 50;
if (angle 《 500) {
angle = 500;
}
break;
}
case ‘n’: {
digitalWrite(led, HIGH);
break;
}
case ‘m’: {
digitalWrite(led, LOW);
break;
}
case ‘g’: {
// When the distance between objects and car is far enough,
// light the green led.
digitalWrite(led_green, HIGH);
digitalWrite(led_yellow, LOW);
digitalWrite(led_red, LOW);
break;
}
case ‘y’: {
// When the distance between objects and car is near enough,
// light the yellow led.
digitalWrite(led_yellow, HIGH);
digitalWrite(led_green, LOW);
digitalWrite(led_red, LOW);
break;
}
case ‘r’: {
// When the distance between objects and car is very near,
// light the red led.
digitalWrite(led_red, HIGH);
digitalWrite(led_yellow, LOW);
digitalWrite(led_green, LOW);
break;
}
case ‘k’: {
// Return distance sensor‘s state between objects and car.
distance_left = digitalRead(distance_sensor_left);
distance_right = digitalRead(distance_sensor_right);
distance = distance_left * 10 + distance_right ;
Serial.println(distance, DEC);
break;
}
case ’i‘: {
while (1) {
// Return motor’s state to raspberry pi.
motor_value_a = digitalRead(motor_a);
motor_value_b = digitalRead(motor_b);
motor_value_c = digitalRead(motor_c);
motor_value_d = digitalRead(motor_d);
motor_value = motor_value_a * 1000 + motor_value_b * 100 +
motor_value_c * 10 + motor_value_d;
Serial.println(motor_value, DEC);
delay(1000);
data = Serial.read();
if (data == ‘l’) {
break;
}
}
}
default:
break;
}
}
// Delay enough time for servo to move position.
digitalWrite(servo, HIGH);
delayMicroseconds(angle);
digitalWrite(servo, LOW);
delay(15);
}
總結(jié)這個(gè)簡單輪式機(jī)器人是大一那會(huì)兒我對自己課外所學(xué)知識的一個(gè)應(yīng)用。雖然現(xiàn)在回過頭再來看自己當(dāng)初做的項(xiàng)目,感覺技術(shù)原理非常簡單,遠(yuǎn)沒有我之后研究的ROS和MoveIt!那么復(fù)雜,但是通過整個(gè)制作過程,我學(xué)會(huì)了如何根據(jù)項(xiàng)目需求去網(wǎng)上購買相關(guān)的材料。
如何將主控等硬件設(shè)備安裝在機(jī)器人機(jī)械結(jié)構(gòu)最合理的位置上,如何使用IDE編寫Arduino程序,如何在Raspberry Pi上使用Python語言來讀取硬件數(shù)據(jù)并控制硬件,如何實(shí)現(xiàn)簡單的串口通信等等。我一直認(rèn)為興趣是最好的老師。
當(dāng)你開始接觸一個(gè)全新的領(lǐng)域時(shí),興趣可以成為你克服各種困難并鼓舞你前進(jìn)的強(qiáng)大動(dòng)力。當(dāng)然,除了興趣,更重要的是親自動(dòng)手實(shí)踐,書上的東西講得再好也是別人的,不是你的,就算重復(fù)造輪子也有著其無法替代的重要意義,因?yàn)椴⒉皇敲總€(gè)人都能造得出輪子,通過學(xué)習(xí)并實(shí)踐前人所學(xué)習(xí)過的知識,你會(huì)收獲別人不會(huì)有的寶貴經(jīng)驗(yàn)!
最后,個(gè)人認(rèn)為智能小車對于廣大剛開始接觸機(jī)器人的初學(xué)者來說確實(shí)是一個(gè)非常好的練手項(xiàng)目,你可以根據(jù)自己的喜好和技術(shù)水平的高低來定制屬于你自己的智能小車,實(shí)現(xiàn)你想要的各種功能??傊?,對于我來說。
通過本次項(xiàng)目我開始真正喜歡上了嵌入式開發(fā)并逐漸走上了專業(yè)化的道路,每個(gè)人都應(yīng)該有自己的夢想,那這個(gè)簡單輪式機(jī)器人就是我夢想的起點(diǎn),激勵(lì)著我不斷向前!當(dāng)然,也希望大家能在制作機(jī)器人的道路上玩得開心并有所收獲!
文章作者:繆宇飏,myyerrol 轉(zhuǎn)載于:https://myyerrol.io/zh-cn/2018/05/15/diy_robots_1_simple_wheeled_robot/
編輯:jq
-
PWM
+關(guān)注
關(guān)注
114文章
5196瀏覽量
214371 -
電機(jī)
+關(guān)注
關(guān)注
142文章
9053瀏覽量
145924 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4344瀏覽量
62809 -
代碼
+關(guān)注
關(guān)注
30文章
4809瀏覽量
68817 -
GPIO
+關(guān)注
關(guān)注
16文章
1215瀏覽量
52230
原文標(biāo)題:干貨|手把手教你自制輪式機(jī)器人
文章出處:【微信號:mcu168,微信公眾號:硬件攻城獅】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論