EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 jacky401 于 2019-7-16 18:15 编辑 ; i e6 E$ u5 S5 n
, ^$ e+ [. Z( v; L% _. r; T3 r% G; v1.试验设备及接线
1 G6 B; `0 K& L# _& f) u1.1实验设备 · MiniQ 桌面机器人底盘
6 d7 u# e5 g: n, ?3 p7 @; {8 m0 B
; q% ~! E/ T4 g9 C5 c
- 底盘直径:122mm # m. ~6 V5 h) |
- 轮子直径:42mm
6 E: n' _; _. V3 F3 Z- 底盘高度:15mm , a- Y) v2 ^. I4 Q5 n4 B0 J
- 兼容 Arduino 标准板及 Romeo 控制器固定孔
4 F9 B9 P( l. b( O2 z- 电机参数: · N20 电机电压:3-9V · 无负载转速:13000rpm · 50:1 减速箱 · 260rpm@6V · 40mA@6V · 360mA 堵转@6V · 10 盎司英寸扭矩@6V · Romeo 三合一 Arduino 兼容控制器
: P" z D, f: j% T- 采用 Atmel Atmega328 单片机 6 `6 K( W- b( }0 e7 q# Z! h2 `
- Arduino UNO bootloader $ U) F5 h/ g, Y7 R+ s% g
- 完全兼容 Aruduino UNO 的端口布局
$ ^% a5 \- s6 {5 y- 集成 APC220 无线数传和 DF-BluetoothV3(SKU:TEL0026)蓝牙模块接口 " e& Y5 q5 G; W3 h+ C* O4 q
- 支持 5 组 I2C 总线接口
. G* ]+ r+ a, \* E! u; D9 F3 {- 支持两路电机驱动,峰值电流 2A,4 个控制口使用跳线切换 + `: t' _0 y6 y
- 外部输入电压范围:6V~20V
9 d; Q [/ N2 d' {- 更详细的参数介绍详见附录的网页地址。
9 m3 A0 ~% v* `6 H+ I" T
+ y+ W* E/ V z: C* ~1 S · MiniQ 小车上层安装板
U% D3 Z. l. C* D
. Y7 A3 @+ ]3 @2 G5 k · Benewake TFmini 标版
6 k4 O9 E7 _+ Z I& a+ ~
TFmini 详细参数见 TFmini 使用说明。
7 A4 i0 m1 b) s1 n3 s4 m# S4 o) B0 |( A' n" `
· 9g 舵机
0 B' t) z+ o' v% d( l' \1 V1 a* I( Q1.2接线; H6 V5 H& G+ O/ f
w) W% Z6 }, Z; A j$ ~5 b
2.小车避障原理+ Q/ Y" o1 k1 @) X
小车启动后,小车开始向前运动。当雷达探测到前方阈值内有障碍物时,小车停止运动,开始左右扫描寻路。舵机搭载 TFmini 从 90°开始向 180°扫描,然后从 180°向 0°扫描。
: k" F* i9 m% T! ], ~! y/ y l
: y0 I# w1 _% ~当扫描方向无障碍物时,小车向此方向转向,舵机回正到 90°。若从左至右扫描一圈都没有可以行进的路线,则小车后退,舵机回正。 . j7 b, }$ |9 p2 C% o. J. \
逻辑流程图如下所示:: o. l5 ^* B! w, [
& Z$ f2 _! ?' {$ ~1 g
3.注意事项 · 当前避障原理模型只用来抛砖引玉,探索用 TFmini 避障的可行性,并不能大范围的适用于大规模的商业场景,如有需要,应以专业软件开发人员的代码为准。 · 搭载的外部电源过重时,会影响小车车轮的摩擦力,可能两个车轮的转速不一致,导致小车并不能按照轨迹行驶。 · 小车车轮在光滑地面有可能造成空转的现象,导致小车不能走直线。 · 如果单独对 TFmini 外部供电,则需将外部电源和控制板共地处理。 · 如果搭载更高复杂度的程序,要考虑芯片的能力,当前开发板在跑程序时已经发现会有卡顿的现象。 4.附录
& m; x0 R2 o8 G& H- b4.1代码 \5 c& V% G W! X, t
#include <Servo.h>
2 v$ w: n n5 RServo myservo;1 p8 e! b3 q5 C3 e& f4 p
int pos=90; //定义舵机角度$ Y9 Q5 A8 v; p$ _7 V8 Z) j4 J4 x
bool flag=true;//定义舵机转向$ M8 m; n8 t8 k0 q# y, Y- y6 ?* ~) r
float dist_f;//定义foward 方向距离0 _& N, ?- f; J1 A x3 K" M+ ?
float dist_s;//定义sideway 方向距离
9 j# Y( m6 X5 S4 Jint E1=5; //定义 M1 使能
\" |, m M% Dint E2=6; //定义 M2 使能7 ^$ o1 Y2 [* [. ~/ W2 r8 c
int M1=4; //定义 M1 控制' V5 G; t( A9 M' i$ O
int M2=7; //定义 M2 控制
u7 _# Q0 [9 K& tint temp_distance =0;- ?; E; E& J5 c) j
/**
- M* e( t4 K8 C6 `, t* 双轮停止
" O0 \# O/ ?" ]: K*/# T2 P+ C2 g! U5 T! j
void brake(void){
B5 K4 Y* s3 C0 BdigitalWrite(E1,LOW); //给 E1 低电平
: o) Q8 q6 D9 @0 q. `digitalWrite(E2,LOW); //给 E2 低电平
1 Q/ v& u* U0 `, E, \. j}
9 ~. P& l# e6 R! E+ N* G/**0 d) M; H) G; C; X
* 双轮前进( `6 m2 U0 R6 Z* K; o
*// y0 O# U1 N: o% C# v* [
void advance(char a, char b){" }, p! [6 T1 _; ^
analogWrite(E1,a);6 I6 f F+ [4 d2 x& s
digitalWrite(M1,LOW);( g% g+ w. n7 Z. h3 ]; z" V
analogWrite(E2,b);2 N" [" q" z& Q/ D3 ?
digitalWrite(M2,LOW);4 V- W) J" O6 K+ V( _" S, B
}# B0 h' }' D5 U8 |
/**- E* H( l( w/ c6 \' Z
* 双轮后退7 u: u3 Q& V/ U7 z. ]9 ?
*/
! w: X' C; R8 i% V0 z e. pvoid back(char a, char b){
4 O. m# Y o' d" i4 EanalogWrite(E1,a);
& T" t0 }# }! J% A$ \0 q EdigitalWrite(M1,HIGH);$ |1 }' W5 i- Y( G6 S& A0 g
analogWrite(E2,b);1 [9 y' R/ i+ a, U6 m
digitalWrite(M2,HIGH);
9 Z7 s6 f' Y* c4 X& Y}: D/ k. E/ y7 a8 z. }& u5 S
/** c/ W7 K% u, s9 k2 v
* 左转
1 h# ]$ L. L( J% N*/& h; g6 `0 ~% Q* d( R# l* U0 b
void turn_L(char a, char b){+ g* g+ P) V- y8 s0 C/ Q
analogWrite(E1,a);
$ L' f- [* @7 R6 A) b D/ f3 hdigitalWrite(M1,LOW);
( Y' l; E1 N, d! A3 yanalogWrite(E2,b);
6 h, V3 s4 V% `" ]digitalWrite(M2,HIGH);
' R! u3 A) M$ L, W: x/ t}
2 K" w: f3 H( M& G0 ^/**+ q& c& H N' \2 J/ J9 i, A
* 右转, s; h+ v9 X' R7 O
*/
1 e: j8 G0 c" W+ e; Xvoid turn_R(char a, char b){
; _! o. U- c# e7 }" b% vanalogWrite(E1,a);
, N' q; B P0 rdigitalWrite(M1,HIGH);. _, j+ x: g' _0 p$ r- A
analogWrite(E2,b);& h/ i1 P9 y& c0 E8 g6 H8 D
digitalWrite(M2,LOW);0 X( z# v: k6 h+ `3 ?8 }
}9 B @ O" V: J2 k# _, r
/**
! ?/ s3 x- k# C! F4 \' F* 读取 TFmini 测量结果
% R; @- f% {7 z9 d; M*/2 p7 p3 X5 ^& Y% A; P% T
void getTFminiData(int* distance, int* strength){2 b W; W) U8 u' ]
static char i = 0;
* Z/ Y$ m% h; Q- i' ~* y0 wchar j = 0;
8 F, i# Z4 c5 Vint checksum = 0;" Y1 Q" P# m* p
static int rx[9];2 B; b7 O9 }1 ^: D
if(Serial.available()) {2 @1 D& J$ N" C! Z# y9 g
rx = Serial.read();6 B7 r) H3 h) l7 N/ W# }& e
if(rx[0] != 0x59) {% J1 G% R0 L! ^8 j# x
i = 0;
# v" O& c$ y y3 m8 ^9 O. k0 U} else if(i == 1 && rx[1] != 0x59) {# I& c2 k" Y: u3 T3 i$ a5 m
i = 0;
; y$ K+ |+ s* B) |6 ?} else if(i == 8) {9 R) E. z: s/ `! [" e9 W
for(j = 0; j < 8; j++) {/ f- g1 w$ i7 h7 f( c" I5 x
checksum += rx[j];6 ^/ v6 p( A2 l' a# N* E
}5 R; K+ L0 L0 f3 A) ]% {6 K, g* Z
/*& ]& a5 r$ Q, `7 }3 `
if(rx[8] == (checksum % 256)) {, |/ Z( R9 Z c; k' x3 ]
*distance = rx[2] + rx[3] * 256;
% P2 W$ y, B0 f4 f' c4 H*strength = rx[4] + rx[5] * 256;6 w' r( V. {" j2 _5 Y
}*/0 {: f- f; n2 @& i
*distance = rx[2] + rx[3] * 256;3 u% @( c* j y# B% x
*strength = rx[4] + rx[5] * 256;3 p7 i4 ^+ P& n5 u6 K3 @
i = 0;
* P) \# i* p; M% q" l} else {9 p4 t" P5 T* o1 E7 q
i++;2 i. z6 P2 m( d1 x: X; Y
}
3 v: y- x( q8 }}
+ X2 G& R/ L- {6 R- Z8 B}
4 b3 [! [# D5 [* Q. \# K7 t. Vvoid setup() {
* W B0 e7 C/ d# K' C2 k* ?// put your setup code here, to run once:
% H" f3 a# P, W, C" n3 [Serial.begin(115200);# f3 j; F- y9 k$ q6 v# t0 M4 T
//舵机的插口在 4
& e0 d- i2 K- M* E7 Imyservo.attach(4);
2 f% F1 f8 [, n3 Obrake();
" g$ ^" N- Q( U& c: N8 A- l/*' }0 l. q, {8 l% a$ o$ @& A
* 将雷达指向前方
a% _: D. P3 S2 X9 J0 m" H: b*/- n, v5 e+ V" q, G
myservo.write(pos);
$ q( r) }4 B. I9 m, |. o/*
! J! B% `' g: S8 i/ v* 设置轮胎电机输出口
( l( {+ q( l' x( i3 Z. t*/
% d% W2 Z1 V! x6 kpinMode(4,OUTPUT);8 z1 C6 P( j6 M% k! v H
pinMode(5,OUTPUT);: Z2 t3 l* T% @6 n5 t9 l
pinMode(6,OUTPUT);
. [) J2 n9 v" S) Z+ J3 DpinMode(7,OUTPUT);
0 x, ~- }9 d9 y3 i1 Ydelay(10);% i' A6 t% Z- v0 F x: s# e# `
}. q+ b; Z5 A" e; U" m6 W& @
void loop() {
7 Q* y: y5 V- l1 u/ a4 A( V5 J) l/*
J1 ^+ L* x. d4 x; I9 A- W* 读数一次$ i! ^9 e) L( Y! ?
*/
7 V- j* i! ?/ |& D+ Cint distance = 0;0 _( y8 j* g- n8 j" o$ ?
int strength = 0;* b1 }- T+ p: e: E+ `( `- E
getTFminiData(&distance, &strength);
: r8 [$ O" S) T/ c& nwhile(!distance) {' F3 { c, h1 v1 X
getTFminiData(&distance, &strength);
2 k: d [1 P! H tSerial.print("Distance: ");
/ D5 W2 n$ \1 b- NSerial.print(distance);! H% L, S8 r) F
Serial.print("cm ");
% g' d8 G# h6 PSerial.print("strength: ");3 G9 S2 [* q# ?" [# I( N
Serial.println(strength);! Z/ o, k3 {7 T0 W& [
}
: a2 G4 D+ I! ?* ]7 u7 M9 ~/*6 K9 P& v& t% m: j" j( n
* 设置 30CM 阈值) X5 r+ B. C* b4 o$ d G" b! p( E+ R
*/% V O( R5 l9 Q5 p
if(distance <= 30 && distance > 0){
0 m4 `$ A- P3 w! ztemp_distance = distance;8 r/ @) Z7 s6 G/ I4 v. O( I" x
}0 \5 r( _; C& n" G9 g3 u9 r9 a- }4 I
delay(10);
( J/ Q4 T. J. Q- K6 i8 N( ^/*: r, E' _ u$ f; p, E" B' Q
* 判断读数距离5 r0 b. w# ?0 h& _/ ^8 T, h( G
* 如果度数距离小于阈值,则停车,开始向左向右扫描,直到扫描出有空隙可以走,然后车轮转弯,然后扫描器回正
1 ~& k! x# M0 } B3 h* 如果读数距离大于阈值,则开车
) o; c# H' v0 O% l! ]*/3 ?$ X7 W5 Q, P+ s5 |; ^
if(temp_distance <= 30 && temp_distance >= 0){. t/ y2 j- c$ x+ n t) t+ S
brake();
( B" p/ H* B- o. P/*
/ v% F I! N7 i( Y- S* 判断当前舵机应该向左还是向右转" O9 h; }) ` Q0 d* K
*/6 ~' q! j8 P2 G& N
if(flag){- X0 q5 c' a8 ?5 C5 A9 A
if(pos<170){
+ C L2 i0 H4 Q! [pos=pos+45;, I4 {' L5 K8 C( y, x4 H
}else{% @7 ~2 r( \5 X/ ?
flag = false;2 `' _! \) }' k" }! |6 o( k
}
' d4 C0 R& X) e$ \/*8 L, O! {6 g# N& O2 q
* 如果探测距离大于阈值,则舵机回正,小车转向
+ c. j2 z: _! s+ I+ d*/
# q; @0 }. f5 v, ~. Yif(distance > 32){8 d( Z5 H. N* c2 `. A0 L3 I1 T6 R
pos = 90;, @% j( h9 F. ^4 e y
myservo.write(pos);6 i8 Q7 e, f9 d5 s' B# F+ p
delay(1200);
9 q! A+ F2 `. j' [+ n/ A }. q2 c//判断小车回正方向3 i! S2 f) F" ~4 Z: d& ?
if(pos >= 90){% e. d+ H: w' s( k" e( K: y b
turn_L(35,35);
/ o: {+ r4 T" O+ R$ P5 `2 _}else{
8 C- M/ G& u& T6 h2 aturn_R(35,35);
+ D3 x* z2 t% w+ W- U( E}1 _+ ]9 e/ |% I. t
delay(250);2 [5 e/ c% `8 i2 O! e' R' v1 h
temp_distance = distance;1 Z- Z& ?. ? L4 `! B
}0 D6 e( T$ N9 o; X/ J, o4 f
/*" O9 S) q# ?2 u! h
* 如果探测距离小于阈值,则继续扫描
6 _+ K, S; E8 B+ D! D9 C+ T3 k# w*/& i5 ?" ~; M+ T2 s1 W/ f0 J
else{0 M) ?5 u0 a' B4 Q( b4 x. I
myservo.write(pos);" Z& C1 Y, p! z% f4 Q
delay(1200);" z/ R4 P/ U8 C' n) L! m' {
}
& M3 t. I0 F( O2 O" R. E}else{& Y8 x0 u& |1 g2 ~& T6 ~* T, U
if(pos>10){
- Z' q! v8 a: R2 L8 t6 lpos=pos-45;8 b0 @- c$ s+ v- S" ~$ o' }
}else{8 a5 C% j5 g' O. U, u1 x
flag=true;
$ u* G% B' x0 g}1 f& D( t7 w; X N# v- G
/*
& Y4 [# A! k; P& g* 如果探测距离大于阈值,则舵机回正,小车转向, L/ J$ J( A9 X
*/4 Z6 |" \$ u2 Z R( k* A5 U
if(distance > 32){- F6 p; b @+ Z0 O8 ]3 I* [) ~" H
pos = 90;- A, o( l/ V1 a3 p2 h
myservo.write(pos);/ ~ P( P9 N1 V
delay(1200);) W$ G1 @5 h- j( ?0 M" Y4 \
//判断小车回正方向
& \& W5 ^/ Q2 wif(pos >= 90){
, C' t3 U' I8 T; i- _turn_L(35,35);
; m/ }1 f- J5 J$ F7 U8 z6 c}else{
9 M5 a' T1 ]. y3 Q( G5 ]turn_R(35,35);5 I# q$ \, Y* d5 g+ {2 s7 B
}
L, ~! F/ D" h# h, F" s0 \delay(250);
6 [- I! y$ E8 i& v! k, qtemp_distance = distance;- v) W K% y3 q& e
}
$ q+ C9 y! Y2 v: V6 ^- F, Z/*
6 w' _- y9 {$ k* 如果探测距离小于阈值,则继续扫描6 f! F* V6 X0 m- D% s; o
*/
5 w0 A8 t6 L9 }4 _ ^else{8 W9 v- H7 N! h/ t
myservo.write(pos);' s$ W3 \; j. U, q. r
delay(1200);# y4 Y X( q7 R" y% v
}/ z* S8 f& o. ]$ n; ?7 e) K+ u+ p8 J
}3 r, j* p9 Z$ Y: L% @
}
6 J! a4 a! y4 L$ G/*& n* T) E' Y! F+ |3 L! v
* 如果前方没有障碍物,直行
. @4 {% F3 S q*/
$ z0 a) Q+ Z: gelse if(distance > 32 && distance < 1200){
( p. v8 ^" M) o/ h( `. dadvance(35,35);, {) {2 D N0 c. ~- K# w% B
}" ?* U' ~& d- z3 |0 I) ?& j
/*) }: d: n4 c& B& \; F+ r) G& ^; R
* 如果雷达挂了,小车停止* M: }% Q4 Y7 ~# I. y' \
*/
5 W1 ^! L! H d( Eelse if(distance == -3){
% I- I6 o/ N- V8 @% o1 Ebrake();& _: H5 [; u! b7 i2 a% n# z- i
}) q2 {/ k" b" o$ c) p6 F. w2 t
} ! B8 p) v6 X/ s0 o6 s, E
. K& t: x5 p" D& x |