提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
随着人工智能普及,智能小车开始流行起来,可是现在的小车基本是履带式或者四轮驱动,不能很好地做到方便快捷,至少在转弯方面就浪费了相应的时间,我们都知道两点间直线距离最短,为了实现小车直接走一条直线路径到达目的地的目的就引入了三轮全向小车的概念,本文章主要讲诉的关于三轮排爆小车如何在微信小程序的帮助下驱动小车。
一、微信小程序制作
微信小程序制作我使用的是微信开发者工具v1.05版本开发,其开发工具下载以及相关开发文档网站:https://developers.weixin.qq.com/miniprogram/dev/framework/
选择你想下载的版本。
接下来就是对想要的界面进行编写,相关资料可以在组件和API中寻找。以下是我简单做的一些界面以及对应的代码(是.wxml的代码)。
蓝牙连接界面:
<button bindtap="discoverDevices">开始搜寻蓝牙设备</button>
<button bindtap="getDevices">获得蓝牙设备</button>
<view wx:if="{{showFlage}}" wx:for="{{devices}}" wx:for-item="device" wx:key="key" bindtap="create" data-index="{{index}}">
<view style="width:750rpx;height:100rpx;color:rgb(80, 23, 238)">{{device.name}} {{device.deviceId}}</view>
</view>
<view wx:if="{{showFlage1}}">蓝牙设备{{name}} {{deviceId}}
</view>
<view wx:if="{{showFlage1}}">点击下面服务值获得特征值</view>
<view wx:for="{{services}}" wx:for-item="service" wx:key="key" bindtap="choice" data-index="{{index}}"> <view wx:if="{{showFlage1}}" style="width:750rpx;height:100rpx;color:rgb(80, 23, 238)"> 服务值:{{service.uuid}} </view>
</view>
<view wx:if="{{showFlage2}}">点击下面特征值读写数据</view>
<view wx:if="{{showFlage2}}" wx:for="{{characteristics}}" wx:for-item="characteristic" wx:key="key" bindtap="select" data-index="{{index}}" style="width:750rpx;height:100rpx;color:rgb(238, 23, 23)">
<view> 特征值:{{characteristic.uuid}} read:{{characteristic.properties.read}} write:{{characteristic.properties.write}}</view>
</view>
<button bindtap="disconnect">断开设备并返回</button>
<view style="color: rgb(17, 192, 245);">请输入数据:
<input style="height: 100rpx; width: 750rpx;" focus="{{showkeyboard}}" confirm-type="send" bindconfirm="sendData" disabled="{{inputKey}}"></input>
</view>
<view style="color: rgb(17, 192, 245);">接收到的数据:</view>
<view>{{showData}}</view>
小车控制界面:
<!--index.wxml-->
<view class="task_text">
<view class="task_title">三轮全向排爆小车控制界面</view>
<view class="task_desc">请开始遥控</view>
<!--index.wxml<button bindtap="connected">连接设备</button>-->
</view>
<view class="text"></view>
<view class="forward">
<button bindtap="Front" bindlongpress="setFront" class="Forward" type="warn" plain="true">
<view class="forwardword">
向前
</view>
</button>
</view>
<view class="turn">
<view class="leftward">
<button bindtap="Leftward" bindlongpress="setleftward" class="Leftward" type="warn" plain="true">
<view class="leftwardword">
向左
</view>
</button>
</view>
<view class="rightward" >
<button bindtap="Rightward" bindlongpress="setrightward" class="Rightward" type="warn" plain="true">
<view class="rightwardword">
向右
</view>
</button>
</view>
</view>
<view class="backward" >
<button bindtap="Back" bindlongpress="setback" class="Backward" type="warn" plain="true">
<view class="backwardword">
向后
</view>
</button>
</view>
机械臂控制界面:
<!--pages/Arm/Arm.js.wxml-->
<!--logs.wxml-->
<view class="Mechanical arm">
<view class="arm_item">
<view class="task_text">
<view class="task_title">三轮全向排爆小车机械臂控制界面</view>
<view class="task_desc">请开始遥控</view>
</view>
<view class="text"></view>
<view class="putdown">
<button bindtap="Put" bindlongpress="setput" class="Putdown" type="warn" plain="true">
<view class="putdownword">
放下
</view>
</button>
</view>
<view class="turn">
<view class="grab">
<button bindtap="Grab" bindlongpress="setgrab" class="Grab" type="warn" plain="true">
<view class="grabword">
张开
</view>
</button>
</view>
<view class="drop" >
<button bindtap="Drop" bindlongpress="setdrop" class="Drop" type="warn" plain="true">
<view class="dropword">
降下
</view>
</button>
</view>
</view>
</view>
</view>
<view class="backward" >
<button bindtap="Back" bindlongpress="setback" class="Backward" type="warn" plain="true">
<view class="backwardword">
闭合
</view>
</button>
</view>
二、电机驱动
我使用的电机驱动板是两个L298N,开发板使用的Arduino,电机是370直流有刷电机(因为本人不太会使用带编码器电机),在编写代码时调整好对应的速度让他能够实现前后左右移动,直流电机不好的地方就是速度是一定的,有会编码器电机的小伙伴可以使用。直流电机的代码示例如下:
#include <SoftwareSerial.h>
void _stop();
const int F_L_motor_back=5; //前左电机后退(IN1)
const int F_L_motor_go=6; //前左电机前进(IN2)
const int F_R_motor_go=9; // 前右电机前进(IN3)
const int F_R_motor_back=10; // 前右电机前进(IN4)
const int A_motor_back=3; // 后电机前进(IN1)
const int A_motor_go=11; // 后电机前进(IN2)
void motor_pinint()
{
pinMode(F_L_motor_back,OUTPUT); // PIN 5 (PWM)
pinMode(F_L_motor_go,OUTPUT); // PIN 6 (PWM)
pinMode(F_R_motor_go,OUTPUT); // PIN 9 (PWM)
pinMode(F_R_motor_back,OUTPUT); // PIN 10 (PWM)
pinMode(A_motor_back,OUTPUT); // PIN 3 (PWM)
pinMode(A_motor_go,OUTPUT); // PIN 11 (PWM)
}
void _stop()//刹车,停车
{
digitalWrite(F_L_motor_back,0);
digitalWrite(F_L_motor_go,0);
digitalWrite(F_R_motor_go,0);
digitalWrite(F_R_motor_back,0);
digitalWrite(A_motor_back,0);
digitalWrite(A_motor_go,0);
}
void Forward()//前进
{
analogWrite(F_R_motor_go,0);//前右电机前进速度为零,PWM比例0~255调速
analogWrite(F_R_motor_back,120);//前右电机后退,PWM比例0~255调速
analogWrite(F_L_motor_go,150);// 前左电机前进,PWM比例0~255调速
analogWrite(F_L_motor_back,0);//前左电机后退速度为零,PWM比例0~255调速
analogWrite(A_motor_go,0);//后电机速度为零
analogWrite(A_motor_back,0);//后电机速度为零
}
void Left()//左移动
{
analogWrite(A_motor_go,150); //后电机前进,PWM比例0~255调速
analogWrite(A_motor_back,0);//后电机后退速度为零,PWM比例0~255调速
analogWrite(F_R_motor_go,0);//前右电机前进速度为零,PWM比例0~255调速
analogWrite(F_R_motor_back,120);//前右电机后退,PWM比例0~255调速
analogWrite(F_L_motor_go,0);// 前左电机前进,PWM比例0~255调速
analogWrite(F_L_motor_back,65);//前左电机后退速度为零,PWM比例0~255调速
}
void Right() //右移动
{
analogWrite(A_motor_back,150); //后电机后退,PWM比例0~255调速
analogWrite(A_motor_go,0);//后电机前进速度为零,PWM比例0~255调速
analogWrite(F_R_motor_go,120);//前右电机前进,PWM比例0~255调速
analogWrite(F_R_motor_back,0);//前右电机后退速度为零,PWM比例0~255调速
analogWrite(F_L_motor_go,65); // 前左电机前进速度为零,PWM比例0~255调速
analogWrite(F_L_motor_back,0);//前左电机后退,PWM比例0~255调速
}
void Back()//后退
{
analogWrite(F_R_motor_back,0);//前右电机后退速度为零,PWM比例0~255调速
analogWrite(F_R_motor_go,120);//前右电机前进,PWM比例0~255调速
analogWrite(F_L_motor_back,150);// 前左电机后退,PWM比例0~255调速
analogWrite(F_L_motor_go,0);//前左电机前进速度为零,PWM比例0~255调速
analogWrite(A_motor_go,0);//后电机速度为零
analogWrite(A_motor_back,0);//后电机速度为零
}
三、蓝牙串口通信
分为微信小程序部分,以及Arduino部分的代码编写。
首先是微信小程序部分的代码(.js里)如下示例:
// index.js
Page({
/**
* 页面的初始数据
*/
data: {
discoverFlag:false,
devices:[],
deviceId:'',
serviceId:'',
services:[],
characteristics:[],
characteristicId:'',
showFlage:true,
name:'',
showFlage1:false,
showFlage2:false,
available:false,
read:false,
write:false,
showkeyboard:false,
inputKey:true,
showData:'',
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.openBluetoothAdapter({
success (res) {
console.log(res)
}
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
let that=this
wx.getBluetoothAdapterState({
success (res) {
console.log(res)
if(res.available){
that.setData({
available:true
})
}
else{
that.setData({
available:false
})
wx:wx.showToast({
title: '蓝牙未打开',
})
}
}
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
openAdapter(e){
wx.openBluetoothAdapter({
success (res) {
console.log(res)
}
})
},
discoverDevices(){
let that=this
wx.startBluetoothDevicesDiscovery({
services: [ ],
success (res) {
console.log(res)
that.setData({
discoverFlag:res.isDiscovering
})
}
})
},
getDevices(){
let that=this
function ab2hex(buffer) {
var hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function(bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('');
}
if(this.data.discoverFlag){
// ArrayBuffer转16进度字符串示例
wx.onBluetoothDeviceFound(function(res) {
var devices = res.devices;
console.log('new device list has founded')
console.dir(devices)
console.log(ab2hex(devices[0].advertisData))
})
}
// ArrayBuffer转16进度字符串示例
wx.getBluetoothDevices({
success: function (res) {
console.log(res)
if (res.devices[0]) {
console.log(ab2hex(res.devices[0].advertisData))
that.setData({
devices:res.devices
})
}
}
})
if(that.data.devices.length>=20){
wx.stopBluetoothDevicesDiscovery({
success (res) {
console.log(res)
}
})
}
},
create(e){
let that=this
console.log(e)
let index= e.currentTarget.dataset.index
wx.getBluetoothAdapterState({
success (res) {
console.log(res)
if(res.available){
that.setData({
available:true
})
}
else{
that.setData({
available:false
})
wx:wx.showToast({
title: '蓝牙未打开',
})
}
}
})
wx.createBLEConnection({
deviceId: that.data.devices[index].deviceId,
wx:wx.showLoading({
title: '连接中',
}),
success (res) {
console.log(res)
that.setData({
deviceId: that.data.devices[index].deviceId,
name:that.data.devices[index].name,
showFlage:false,
showFlage1:true
})
wx:wx.hideLoading({
})
wx.getBLEDeviceServices({
// 这里的 deviceId 需要已经通过 wx.createBLEConnection 与对应设备建立连接
deviceId:that.data.deviceId,
success (res) {
console.log('device services:', res.services)
that.setData({
services:res.services
})
}
})
}
})
},
choice(e){
console.log(e)
let that=this
let index=e.currentTarget.dataset.index
let serviceId = this.data.services[index].uuid
this.setData({
serviceId:serviceId
})
wx.getBLEDeviceCharacteristics({
// 这里的 deviceId 需要已经通过 wx.createBLEConnection 与对应设备建立链接
deviceId:this.data.deviceId,
// 这里的 serviceId 需要在 wx.getBLEDeviceServices 接口中获取
serviceId:this.data.serviceId,
success (res) {
console.log('device getBLEDeviceCharacteristics:', res.characteristics)
that.setData({
characteristics:res.characteristics,
showFlage2:true,
showFlage1:false
})
}
})
},
disconnect(){
let that=this
wx.closeBLEConnection({
deviceId:this.data.deviceId,
success (res) {
console.log(res)
that.setData({
showFlage:true,
showFlage1:false,
showFlage2:false,
inputKey:true,
})
}
})
},
select(e){
console.log(e)
let index=e.currentTarget.dataset.index
let characteristicId = this.data.characteristics[index].uuid
this.setData({
characteristicId:characteristicId,
showkeyboard:true,
inputKey:false,
})
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
deviceId:this.data.deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId:this.data.serviceId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId:this.data.characteristicId,
success (res) {
console.log('notifyBLECharacteristicValueChange success', res.errMsg)
// ArrayBuffer转16进制字符串示例
function ab2hex(buffer) {
let hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function(bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('');
}
wx.onBLECharacteristicValueChange(function(res) {
console.log(`characteristic ${res.characteristicId} has changed, now is ${res.value}`)
console.log(ab2hex(res.value))
})
}
})
},
sendData(e){
console.log(e)
let value=e.detail.value
// 向蓝牙设备发送一个0x00的16进制数据
let buffer = new ArrayBuffer(value.length)
let dataView = new DataView(buffer)
for(let i=0;i< value.length;i++){
dataView.setUint8(i, value[i].charCodeAt())
}
wx.writeBLECharacteristicValue({
// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
deviceId:this.data.deviceId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId:this.data.serviceId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId:this.data.characteristicId,
// 这里的value是ArrayBuffer类型
value: buffer,
success (res) {
console.log(buffer)
console.log('writeBLECharacteristicValue success', res.errMsg)
wx.showToast({
title:'发送成功',
})
},
fail(res){
wx.showToast({
title: '发送失败',
})
}
})
},
setDevice(){
let that=this
wx.showModal({
title: '提示',
content: '点击确定将覆盖原有设置',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
wx.setStorageSync('device1', {
deviceId:that.data.deviceId,
serviceId:that.data.serviceId,
characteristicId:that.data.characteristicId,
})
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
}
})
以上代码是蓝牙连接界面的代码,另两个界面的代码和蓝牙连接界面类似就没有放了。
Arduino部分代码如下:
int receive;
void reve(void);
void _stop();
void setup()
{
Serial.begin(9600); //串口波特率9600(手机端使用)
motor_pinint( );
}
void loop()
{
reve();
}
void reve(void)
{
receive=Serial.parseInt();
if(receive==7) {Forward( ) ;delay(2000);_stop();}//前进
else if(receive==6) {Back( ) ;delay(2000);_stop();}//后退
else if(receive==1) {_stop() ;delay(2000);_stop();}//停车
else if(receive==8) {Left( ) ;delay(2000);_stop();}//原地左
else if(receive==9) {Right( ) ;delay(2000);_stop();}//原地右
}
四、机械臂
机械臂部分我是在淘宝上买的,然后配对的相应的代码以及控制机械臂的app,我还没有找到如何实现用一个蓝牙控制小车和机械臂的方法所以就分开控制的。机械臂相关资料百度网盘领取:
链接:https://pan.baidu.com/s/1tuZTwO1D_DeY1pmcn4eHwA?pwd=6666
提取码:6666