EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 jacky401 于 2019-7-16 18:15 编辑
9 g y7 `) J& X6 Q+ H7 z4 b& p3 ~" a5 R. e/ @2 y0 a% `
1.试验设备及接线 + j) s; n8 G6 v1 i8 x2 _
1.1实验设备 · MiniQ 桌面机器人底盘
9 Z) E# ?) q5 A) E! i
7 A3 J& ^1 d# P) d$ C1 G- 底盘直径:122mm ' ~4 F2 H! K. o( O
- 轮子直径:42mm " x# m) ~7 B) G0 z+ C: k( c4 S
- 底盘高度:15mm
) C' T8 K9 ]4 L+ k3 e- k0 p* Z, M- 兼容 Arduino 标准板及 Romeo 控制器固定孔 - o, J/ @$ c; x
- 电机参数: · N20 电机电压:3-9V · 无负载转速:13000rpm · 50:1 减速箱 · 260rpm@6V · 40mA@6V · 360mA 堵转@6V · 10 盎司英寸扭矩@6V · Romeo 三合一 Arduino 兼容控制器
) N' z6 [1 C! z2 n0 z) P" m* q- 采用 Atmel Atmega328 单片机 ; x" {& A) m' x ~) X* Q+ j, o& Y
- Arduino UNO bootloader ! J' V) m- b# e
- 完全兼容 Aruduino UNO 的端口布局
, {9 s! L% Y& B" t& P- 集成 APC220 无线数传和 DF-BluetoothV3(SKU:TEL0026)蓝牙模块接口
8 ]# {3 h# d" U( H M- 支持 5 组 I2C 总线接口 ( d# R; q5 ^0 ~) [
- 支持两路电机驱动,峰值电流 2A,4 个控制口使用跳线切换 $ e* H8 O+ ?/ s/ R8 N
- 外部输入电压范围:6V~20V
, w8 [8 K! @) L! o% m8 E: O8 E- 更详细的参数介绍详见附录的网页地址。* q/ n! i( R2 c5 g" a
) S" }4 b4 ^4 v& b( l
· MiniQ 小车上层安装板
$ E+ A0 A# b3 g, ^4 R# L
$ L1 e; j9 V: E2 D- H · Benewake TFmini 标版
* f5 {1 @4 }4 K+ i6 hTFmini 详细参数见 TFmini 使用说明。
1 j- `1 G+ L" K& c& }2 r& [
. ~, p) L1 @" H; h · 9g 舵机
3 Z2 V0 v3 T P+ P: S( Z
1.2接线
4 j( {$ k* k0 ?! h8 }+ v
+ [( F4 V3 @$ T3 D) N
2.小车避障原理; |2 W u; N8 b# Y+ T, F# d0 U/ g3 N! M
小车启动后,小车开始向前运动。当雷达探测到前方阈值内有障碍物时,小车停止运动,开始左右扫描寻路。舵机搭载 TFmini 从 90°开始向 180°扫描,然后从 180°向 0°扫描。
9 s3 p) h* K: P3 B6 V
$ V7 @9 B) m( u8 o
当扫描方向无障碍物时,小车向此方向转向,舵机回正到 90°。若从左至右扫描一圈都没有可以行进的路线,则小车后退,舵机回正。 / M- p3 b/ G5 @& y1 {
逻辑流程图如下所示:
U: B0 a2 m3 E' q+ x& ]) @$ o1 V% Q
5 M' Y1 o- X+ S
3.注意事项 · 当前避障原理模型只用来抛砖引玉,探索用 TFmini 避障的可行性,并不能大范围的适用于大规模的商业场景,如有需要,应以专业软件开发人员的代码为准。 · 搭载的外部电源过重时,会影响小车车轮的摩擦力,可能两个车轮的转速不一致,导致小车并不能按照轨迹行驶。 · 小车车轮在光滑地面有可能造成空转的现象,导致小车不能走直线。 · 如果单独对 TFmini 外部供电,则需将外部电源和控制板共地处理。 · 如果搭载更高复杂度的程序,要考虑芯片的能力,当前开发板在跑程序时已经发现会有卡顿的现象。 4.附录. p+ P* q7 S; Y, o. C3 O
4.1代码5 D& {5 t& m2 d1 a' W% ~
#include <Servo.h>
t1 s2 |) I" T; M9 SServo myservo;
) B& G S' v! S, U0 t4 m+ cint pos=90; //定义舵机角度
, T+ Z2 J2 r1 o) G0 [% t; r; zbool flag=true;//定义舵机转向
/ O3 G$ H$ h5 rfloat dist_f;//定义foward 方向距离
, e& s2 _( ^) W5 ^float dist_s;//定义sideway 方向距离
# R ?& c/ O5 J6 uint E1=5; //定义 M1 使能
4 @& l4 l: n+ d2 S9 Hint E2=6; //定义 M2 使能
: W: ?6 i- w# f+ ?int M1=4; //定义 M1 控制# s/ A- F( f2 m" z% e5 B" v
int M2=7; //定义 M2 控制
% h$ W0 p& O9 B6 L c2 Y7 D2 qint temp_distance =0;2 U4 \: s0 m% N0 v) n+ ]+ v& A
/**/ V2 Y6 _' U/ D* s# J
* 双轮停止
. @$ F5 R3 \. F9 p*/
- [/ R& r0 z- J5 l' bvoid brake(void){
! p% `* l, {2 GdigitalWrite(E1,LOW); //给 E1 低电平
/ W5 H+ F2 a+ _% F( a0 T& J( y4 Y& |digitalWrite(E2,LOW); //给 E2 低电平
& ^/ }# C7 t' O0 }8 n9 u}. d) y, h8 e3 c- j+ F4 f
/**" Y% y5 W! s: v w% P" o$ Q) f$ e
* 双轮前进* [0 U: k: v6 G2 [9 C2 n
*/
6 q: {4 o4 r' j V+ C- Z) {void advance(char a, char b){$ r; q" A# x/ g) }7 ]
analogWrite(E1,a);4 P) h& r% z2 ]8 J4 L
digitalWrite(M1,LOW);
) U8 g& t1 C9 S- E# Z6 FanalogWrite(E2,b);
+ J2 W8 \ h r/ R) d; i6 w& ?! X, CdigitalWrite(M2,LOW);* n0 a s2 m E+ x; W* I. {
}- m% b- \, F. R h& D: W
/**) Z' L& W+ ~2 q' ]& s+ c
* 双轮后退7 [4 f2 `! S" c* ~) A
*/8 ? r# q F. n; z: `& N9 Y
void back(char a, char b){
k' F. t4 r/ w) nanalogWrite(E1,a);
! v. n0 b5 }5 F+ l, J6 QdigitalWrite(M1,HIGH);- \+ p. N+ b& y0 U+ \5 s9 H* P
analogWrite(E2,b);7 R1 J- _1 H" B3 @6 V0 j
digitalWrite(M2,HIGH);
7 h1 O! h- z0 B- v}7 t0 U# i- X3 u b! b7 A
/**& U' Z1 [3 C% }% |2 M2 S% }$ [6 D
* 左转
9 `, A, j' g1 D2 A% [$ f$ N*/4 @% O# m5 i! T% |- m5 }
void turn_L(char a, char b){" O4 H6 p0 k7 e/ R; R* t' W/ q
analogWrite(E1,a);
3 P. s2 Z( U& y) c. v! H: fdigitalWrite(M1,LOW);/ o* k0 m- B6 Z( e/ P% c2 f! k
analogWrite(E2,b);/ w9 X G- l9 V N8 L
digitalWrite(M2,HIGH);, v+ e# S. i8 h' L! V$ k) |) u
}/ L: u8 q% j4 q* w( x
/**/ q- ?; m* u+ T) B! r
* 右转/ b2 X0 m" i7 z& E/ M3 g
*/
$ h# t$ P2 c$ k% C8 n8 P* Kvoid turn_R(char a, char b){
q# G/ F; x ]7 FanalogWrite(E1,a);, M3 x6 }7 g2 J0 I, Q
digitalWrite(M1,HIGH);$ r& P- {. b: M2 J6 W
analogWrite(E2,b);& g/ y2 t, ~5 A8 o/ r1 Q* |
digitalWrite(M2,LOW);
0 Y6 _" X' [8 Y- a" Y( I) J+ G}
( `. R* q# }) u/**
( S+ \$ {! l+ X- x. l( |& Z( c* 读取 TFmini 测量结果
6 X5 g' q! x: G8 _& Y5 K) s*/
u0 x) q/ q9 D X, j. z" fvoid getTFminiData(int* distance, int* strength){( z' p/ |) K# x3 V2 b
static char i = 0;
0 |$ x& A8 u( J- K3 m0 T: ^char j = 0;- d3 v5 A, G; _: X0 e$ R9 k
int checksum = 0;
$ s: j0 u) Z* [& `static int rx[9];/ K9 O4 i( I/ G6 a. u
if(Serial.available()) {
' V: p7 c$ d6 _. Y3 Rrx = Serial.read();6 Q7 J' _# @) j; S
if(rx[0] != 0x59) {" m2 x' i4 ?3 f2 y3 W; T+ J
i = 0;
2 a, @7 p1 P o4 q; J" C* l} else if(i == 1 && rx[1] != 0x59) {
; e$ d: }4 \$ Vi = 0;
* \. f8 ~' e. m2 m} else if(i == 8) {& J. I9 Q5 ] \" f
for(j = 0; j < 8; j++) {
0 D3 O/ _- Q. w6 @# \7 Dchecksum += rx[j];
8 z( `: L2 a/ f1 T' h1 H5 A% b}6 e1 i5 C9 ?4 u
/*6 T! Q+ ]+ _4 z8 \- _% u; I! E
if(rx[8] == (checksum % 256)) {
* X8 B0 ^9 l4 ~' m* \; [7 _( j' c*distance = rx[2] + rx[3] * 256;
) K6 U1 y+ e. @ k*strength = rx[4] + rx[5] * 256;
' U0 V; ]9 w: B; `}*/$ h2 q7 ?& H8 o9 y# g
*distance = rx[2] + rx[3] * 256;
+ l3 G# ?# h: \% n*strength = rx[4] + rx[5] * 256;' w1 Z, a! d1 `
i = 0;
+ M2 |) j0 r( {" e0 r} else {
* O0 G$ c* Q- ~8 P; Zi++;+ s* h/ Z4 \* N) K; u" J
}9 I* i1 I( s0 _6 O" P9 l
}1 M- L" F4 v9 _6 o5 r6 d& b& f
}( o8 G" M& R+ p# J
void setup() {
1 S# T" p5 f* _- s// put your setup code here, to run once:
5 K" |; M9 `" tSerial.begin(115200);. C3 C& e5 M$ r3 P: r8 v
//舵机的插口在 4
+ O" q* R2 V4 B7 b) b. rmyservo.attach(4);
4 X+ O6 e7 V: }" X3 cbrake();
5 ~1 Y0 ]6 s" S/*1 q1 v8 E" b' {5 m
* 将雷达指向前方* i3 E" b: C/ q& i- t
*/
8 U7 s6 p& x, m pmyservo.write(pos);
! D2 P, h, E- |) l/*
9 _/ p3 j |2 t& j' _% c* 设置轮胎电机输出口- [5 x+ Q! `6 o, ^
*/% I" e0 Z! x, C, d
pinMode(4,OUTPUT);
6 e" p" K$ O& H" r6 X' c/ D7 ^3 RpinMode(5,OUTPUT);2 H3 ?; _2 p2 T x
pinMode(6,OUTPUT);
% w# M% {% D- o3 z9 [4 xpinMode(7,OUTPUT);
% o' {( `3 @: idelay(10);
; R! \/ |3 v5 k6 N' k# Z" S}8 ] ?6 @3 n' E8 v( c' e8 g# ~
void loop() {/ k! s' i9 B. E/ H1 d
/*
L" H0 c/ Y! B- n& V1 s+ f* 读数一次* W7 U; n4 H/ y9 w2 E/ \
*/3 Z3 d; i2 H5 `7 f' u. v; [9 Z4 k8 l6 x
int distance = 0;4 o# X& `4 M4 _: L- K4 S5 q' n
int strength = 0;# d7 C1 n4 Q& j8 b8 Q
getTFminiData(&distance, &strength);
! o5 E" {4 ^% I) `% kwhile(!distance) {
. V9 f7 f: `4 V/ j( ~' KgetTFminiData(&distance, &strength);, H- ~$ c2 O8 M. h% h* _/ N3 u
Serial.print("Distance: ");
5 V' q" O7 p: J, j) G! ASerial.print(distance);6 @& d* z% K g7 g$ l8 {1 E
Serial.print("cm ");
. h, e, I9 `3 G" Y6 kSerial.print("strength: ");- `; e5 e- O7 ]6 D) Z W
Serial.println(strength);
; S: d9 J7 \$ }* s0 ~3 i9 P7 q) k}
1 \0 l6 R$ j7 L. s: Y/*' |5 a: r0 I, o5 R4 B! I
* 设置 30CM 阈值
5 l% M3 }& n" F) V$ G; c*/
/ r, C: B. e; _if(distance <= 30 && distance > 0){, F. q$ q: f7 A& d& m
temp_distance = distance;
3 `/ |8 h I x# ?4 y}
; J! z( i7 |" p$ `3 n8 tdelay(10);" h* m5 S5 N" p5 V# ^
/*
& `: d. ^) K; n: s% A3 r* 判断读数距离5 z! D j. B+ C; f8 H! s
* 如果度数距离小于阈值,则停车,开始向左向右扫描,直到扫描出有空隙可以走,然后车轮转弯,然后扫描器回正1 A7 Q; ?' }5 p* Y5 r1 `
* 如果读数距离大于阈值,则开车
' D& n8 A) w" n8 ]5 L*/8 i/ q+ _5 t7 ?) T/ m& ^
if(temp_distance <= 30 && temp_distance >= 0){9 o% n/ E e7 K i8 f
brake();8 c" p3 b! h( i/ l
/* J" b7 [. x8 H4 U
* 判断当前舵机应该向左还是向右转9 T$ b2 t% W$ s; m& D0 q
*/! E9 ?8 ?( B! J- U3 w$ S
if(flag){
6 n: K- U1 B8 l+ \5 ?: Fif(pos<170){( t# v; {; v) z- J: ?6 b
pos=pos+45;
: r, g5 m' c' b: V( I2 S9 u) L}else{$ U' @" p' n7 {7 J. [7 e) O7 }9 n; `
flag = false;' s+ W9 |- n8 N; h O' y
}
: c. \5 E) ~9 r+ i, S$ z, k/*3 J. F% f$ O( n. |
* 如果探测距离大于阈值,则舵机回正,小车转向
5 F2 V- S: V3 V( y*/
6 M1 w% B2 M+ N9 G# |# O0 ]if(distance > 32){6 U+ ?: a/ a/ E) ]3 z: |5 N: G6 u/ \
pos = 90;
6 E2 B% N$ ]6 m* U% K& @4 Omyservo.write(pos);
$ H- R2 I% e$ c6 Hdelay(1200);
/ ^4 [6 y1 D. W6 T- J0 g- F//判断小车回正方向
% r @ k1 Y, a3 U7 p% G9 hif(pos >= 90){
- q% `; Y. T9 zturn_L(35,35);
, F( I, ?& O2 L9 ]6 |6 M7 |}else{; b, U2 X: y' x7 c- n3 O6 q9 l; w
turn_R(35,35);3 H" o: z0 g0 Q# v: f
}- j- G" Q5 A: `6 C/ p
delay(250); z( C% }/ l6 I4 o
temp_distance = distance;# x2 ]5 W B5 m9 f, y
}
% @/ R1 O8 ?. X/ }7 X3 R2 M/** S* T3 T# ]% E! L& i& r1 b) e
* 如果探测距离小于阈值,则继续扫描* d J# A x; }) | C
*/
* O9 C7 x a- q# l8 j/ melse{3 X( ]" o$ j& c& O
myservo.write(pos);
7 w( h# _3 j1 @& H3 o$ Q8 |* odelay(1200);
; ~! D+ T; `4 a/ R. r}
+ u% g; z) U7 y}else{
. G/ W+ T3 Y6 c; d3 O0 Iif(pos>10){! @) u4 r2 l/ W4 A) d, R+ P% M
pos=pos-45;
2 v7 S0 s( E% J$ |6 n}else{
3 x) l* q; q, z) I/ T: wflag=true;& D6 ]! \; [; U
}0 y: o% G, _! X* F0 V0 t
/*
0 J) ]1 N+ c E5 t" V# {* 如果探测距离大于阈值,则舵机回正,小车转向" ^& \, H2 Q" J
*/+ U4 Y4 U; [" m. E
if(distance > 32){/ e: h. T% s; z9 R# J- H1 O! b
pos = 90;
) g# ~7 @. s* M+ r5 d$ e P$ Pmyservo.write(pos);1 T2 J2 }* A6 {& q& P7 ?. w$ C
delay(1200);0 r/ Q- \ ~9 i& w) s4 o- `, M L! ^
//判断小车回正方向
; k0 U6 g! k9 d$ Lif(pos >= 90){! P$ H( b7 ~* ^! i) t5 n6 [) Q
turn_L(35,35);
6 _' E2 _( \* R J}else{/ U% o( O) m6 o( l: d4 m3 j
turn_R(35,35);) H5 K& o( U* ]+ `- m t
}& `+ f5 M- X" E+ I" W
delay(250);7 ]2 C: |. L4 V) y1 Z' f( g
temp_distance = distance;
( `$ n0 E: p4 o}
; Q, F! K6 ^2 S$ e; O! z/*
2 d3 `0 D& U% D# N1 r* 如果探测距离小于阈值,则继续扫描! H; ^; N# D# t1 G0 ` B
*// x4 @5 M+ y0 _# x$ r1 d8 w
else{) j) |/ p3 v9 W8 M0 [1 [
myservo.write(pos);2 e1 R3 ?8 U8 F* }5 O
delay(1200);: y6 \% _4 D$ ^
}% q$ U' o1 z7 H5 }1 d
}
5 j$ x$ H& P! [" G8 e, ?}, W3 S8 o b7 Z) y) H
/*
( P: a9 ~7 Q( b1 }2 L* 如果前方没有障碍物,直行
4 @ k% [/ e+ u9 M*/, ?: x) h8 I& w/ q3 m
else if(distance > 32 && distance < 1200){) A4 v% p& ~) A" ~, R
advance(35,35);
1 @" I1 S3 c* W% u! P4 t7 |}! |7 N. L' G% j% P* a
/*
- H9 u/ D. J: P0 G1 M0 X# _* 如果雷达挂了,小车停止
5 o( t+ _8 k3 r2 u( F2 `/ \ h*/
- l, z8 Z0 j' e/ ]* I' Nelse if(distance == -3){* j" X% s( h) |* t) e4 z
brake();
J+ J* f5 _' c$ J}
" P* ]( H* |) q* {" [" v6 T3 v4 u} * T# X4 f, r) J6 F" _/ ^- g
7 a# J& c* b8 ]9 m( p |