材料清单:
合宙air101小板:9.9元
航模有刷电机:5元左右
L298N电机驱动板:6元左右
蓝牙模块:jdy33,7元左右
航模3s电池或者5-12V充电宝
工具:
热熔胶枪,烙铁,焊锡,杜邦线,剪刀……
功能:
能实现手机控制小船前进后退及行驶速度;超过信号距离,蓝牙断开后,小船停止运动。
硬件连接
原理:
代码:原理看注释
--定义限幅函数 function LimitThrust(T) if T>100 then T=100 elseif T<0 then T=0 end return T end function shache()--刹车 --刹车 --控制电机L转动方向,逆时针 gpio.set(19,0)--PB3-->IN2 gpio.set(21,0)--pB5-->IN1 --上电后,先关闭PWM, -- pwm.close(1)--关闭PWM0 --控制电机R转动方向,顺时针 gpio.set(1,0)--PA1-->IN3 gpio.set(4,0)--pA4-->IN4 --上电后,先关闭PWM, -- pwm.close(0)--关闭PWM0 print("刹车,关闭PWM") end function qianjin(X,Y)--前进 local T_start=40 --启动油门,慢慢调,T_start local TL=T_start-(50-X)+(Y-50)--左边电机,TL不超过100,得限幅 local TR=T_start+(50-X)+(Y-50)--右边电机,TR不超过100,得限幅 --控制电机L转动方向,逆时针,产生拉力 gpio.set(19,1)--PB3-->IN2 gpio.set(21,0)--pB5-->IN1 --控制电机R转动方向,顺时针,产生拉力 gpio.set(1,0)--PA1-->IN3 gpio.set(4,1)--pA4-->IN4 --限制在0-100内 local speed_L=LimitThrust(TL)-- (0~100) local speed_R=LimitThrust(TR)-- (0~100) print("speed_L",speed_L) print("speed_R",speed_R) if speed_L==0 or speed_R==0 then pwm.close(0)--关闭PWM0 pwm.close(1)--关闭PWM1 print("PWM Close") else --Suart.write(id,"PWM open "..tostring(speed_x))--此函数只能发送字符串,不能发送数字,发送给手机 pwm.open(1,50,speed_L,0,100)--占空比为0时,会出问题,所以用if else区分开,左边电机接PWM1 pwm.open(0,50,speed_R,0,100)--占空比为0时,会出问题,所以用if else区分开,左边电机接PWM0 end end function houtui(X,Y)--后退 local T_start=40 --启动油门,慢慢调,T_start local TL=T_start-(50-X)+(50-Y)--左边电机,TL不超过100,得限幅 local TR=T_start+(50-X)+(50-Y)--右边电机,TR不超过100,得限幅 --控制电机L转动方向,顺时针,产生推力 gpio.set(19,0)--PB3-->IN2 gpio.set(21,1)--pB5-->IN1 --控制电机R转动方向,顺时针,产生推力 gpio.set(1,1)--PA1-->IN3 gpio.set(4,0)--pA4-->IN4 --限制在0-100内 local speed_L=LimitThrust(TL)-- (0~100) local speed_R=LimitThrust(TR)-- (0~100) print("speed_L",speed_L) print("speed_R",speed_R) if speed_L==0 or speed_R==0 then pwm.close(0)--关闭PWM0 pwm.close(1)--关闭PWM1 print("PWM Close") else --Suart.write(id,"PWM open "..tostring(speed_x))--此函数只能发送字符串,不能发送数字,发送给手机 pwm.open(1,50,speed_L,0,100)--占空比为0时,会出问题,所以用if else区分开,左边电机接PWM1 pwm.open(0,50,speed_R,0,100)--占空比为0时,会出问题,所以用if else区分开,右边电机接PWM0 end end RxData={
[1]=0,[2]=0,[3]=0,[4]=0,[5]=0,} function jiexi(rec_data)--解析数据帧 --由于蓝牙端口或者连接会自动发送数据给串口,这种简单的通信方式会造成错误命令,但也可以利用这个做个保护机制 --连接成功自动给串口发送:+CONNECTED 对应的RxData[1]=C ,ASSIC码为67。RxData[2]=O , ASSIC码为79。 --蓝牙断开自动给串口发送:+DISCONNECT 对应的RxData[1]=D ,ASSIC码为68。RxData[2]=I ,ASSIC码为73。 --解析手机发来的命令 RxData[1]=string.byte(rec_data,1,1)--帧头OXA5,ASSIC码为165 RxData[2]=string.byte(rec_data,2,2)--接收数据帧的第二个字符,x轴数据,0~100 RxData[3]=string.byte(rec_data,3,3)--接收数据帧的第三个字符,y轴数据,0~100 RxData[4]=string.byte(rec_data,4,4)--校验和,由手机app算好,发送过来 RxData[5]=string.byte(rec_data,5,5)--帧尾OX5A,ASSIC码为90 end --根据L298N使用说明,需设置引脚电平控制电机转向,选择 --控制电机L转动方向 --GPIO19-->PB3-->IN2 --GPIO21-->pB5-->IN1 gpio.setup(19, 0) gpio.setup(21, 0) --控制电机R转动方向 --GPIO1-->PA1-->IN3 --GPIO4-->pA4-->IN4 --先将引脚设置为输出模式,后续更改输出电平控制转向 gpio.setup(1, 0) gpio.setup(4, 0) --设置串口 uart.setup(1,9600)--设置串口1的波特率为9600 --打开串口1的回调函数,当串口1收到数据会自动调function函数 uart.on(1,"receive",function(id,len) Rec_data=uart.read(id,len)--将串口收到的数据读出 jiexi(Rec_data)--解析数据帧 if (RxData[1]==165)and(RxData[5]==90)and(RxData[4]==RxData[2]+RxData[3]) then--判断是否为有效数据帧 --print("x=",RxData[1],"y=",RxData[2]) local x=RxData[2] local y=RxData[3] if (x>=0 and x<=100)and(y>=0 and y<=100)then--有效坐标数据 if y>50 then--摇杆中位以上 qianjin(x,y)--前进 elseif (x==50 and y==50) then--摇杆中位 shache();--刹车 elseif y<50 then houtui(x,y)--后退 end end elseif (RxData[2]==67 and RxData[3]==79)or(RxData[2]==68 and RxData[3]==73) then--如果是蓝牙断开或者连接产生的提示字符串 shache();--刹车 end end)
--由于蓝牙端口或者连接会自动发送数据给串口,这种简单的通信方式会造成错误命令,但也可以利用这个做个保护机制 --连接成功自动给串口发送:+CONNECTED 对应的RxData[1]=C ,ASSIC码为67。RxData[2]=O , ASSIC码为79。 --蓝牙断开自动给串口发送:+DISCONNECT 对应的RxData[1]=D ,ASSIC码为68。RxData[2]=I ,ASSIC码为73。
感觉:真不错,100行代码不到搞定
视频:
手机端:
安装app:蓝牙调试器
配置步骤:
1,刷新蓝牙,连接蓝牙
2,进入专业调试,点击中间弹出,添加工程,进入通信设置,再编辑控件
通信设置:添加两个字符型变量,命名为 x,y,
再编辑控件:
添加组件,链接变量,调整组件大小
弄好返回,自动弹出设置x\y范围,设置为0-100,打开这个开关,摇杆会自动归中
点击运行:
可以愉快的玩耍了。
补充:
这个是协议
设置通信模式:仅操作控件时发生。拒绝无效通信
有改成其他单片机的需求,联系主页邮箱