使用Arduino UNO和蓝牙模块制作智能小车

目录

概述

1 硬件结构

1.1 硬件组成

1.2 蓝牙模块介绍

1.3 控制板IO引脚定义

2 机械结构

3 固件设计

4 App设计

5 参考文献


概述

       本文主要介绍使用Arduino UNO作为主板,用于控制电机和接收蓝牙模块数据。蓝牙模块用于从手机App上接收控制信号,使用L298N作为驱动板设计一台智能小车,可通过手机上的App来控制小车的运行状态。

项目代码 git 地址:Arduino_project: 基于Arduino板卡的开源项目 (gitee.com)

1 硬件结构

1.1 硬件组成

         本系统硬件结构是以Arduino为主控板,蓝牙模块上RX和TX与Arduino上的TX和RX相连。L298N作为电源管理模块和驱动模块,分别为控制板、蓝牙模块提供电源。电池模块提供整个系统的工作电压,采用可充电的锂电池,单个电池电压为: 3.7V, 电池盒中总共装载4节锂电池。硬件列表如下。

名称功能介绍注释
Arduino UNO控制板处理蓝牙数据和控制电机
L298N驱动模块驱动四个电机:正转、反转、停止
HC-05 蓝牙模块接收/发送控信号传送App发送的信号
3.7V 锂电池系统供电4节锂电池构成供电盒

1.2 蓝牙模块介绍

       HC-08蓝牙串口通信模块是新一代的基于Bluetooth Specification V4.0 BLE 蓝牙协议的数传模块。无线工作频段为 2.4GHz ISM,调制方式是 GFSK。模块最大发射功率为4dBm,接收灵敏度-93dBm,空旷环境下和 手机可以实现 80 米超远距离通信。

        其和MCU之间通过串口通信,软件设计也简单便捷,且不需要考虑蓝牙协议栈问题,非常适合做速成产品。

蓝牙模块与MCU之间连接图:

1.3 控制板IO引脚定义

引脚功能定义如下:

控制板引脚功能介绍
AI-0连接控制板: IN-1左侧电机控制信号引脚
AI-1连接控制板: IN-2左侧电机控制信号引脚
AI-2连接控制板: IN-3右侧电机控制信号引脚
AI-3连接控制板: IN-4右侧电机控制信号引脚
RX/TX连接HC-08蓝牙模块 TX/RX

2 机械结构

       系统采用集成底盘结构,四个电机固定在最底层底板上,L298N放在最底层的顶层板上,顶层板用于支撑控制板和电池模块。其具体框架结构如下:

3 固件设计

       固件主要使用电机控制和蓝牙模块数据的发送和接收。其具体代码如下,工程采用Arduino IDE开发:

系统代码:

// ATMEL ATMEGA8 & 168 / ARDUINO
//
//                  +-\/-+
//            PC6  1|    |28  PC5 (AI 5)
//      (D 0) PD0  2|    |27  PC4 (AI 4)
//      (D 1) PD1  3|    |26  PC3 (AI 3)
//      (D 2) PD2  4|    |25  PC2 (AI 2)
// PWM+ (D 3) PD3  5|    |24  PC1 (AI 1)
//      (D 4) PD4  6|    |23  PC0 (AI 0)
//            VCC  7|    |22  GND
//            GND  8|    |21  AREF
//            PB6  9|    |20  AVCC
//            PB7 10|    |19  PB5 (D 13)
// PWM+ (D 5) PD5 11|    |18  PB4 (D 12)
// PWM+ (D 6) PD6 12|    |17  PB3 (D 11) PWM
//      (D 7) PD7 13|    |16  PB2 (D 10) PWM
//      (D 8) PB0 14|    |15  PB1 (D 9)  PWM
//                  +----+#include <Arduino.h>//电机控制接口 
#define PIN_A0   (14)
#define PIN_A1   (15)
#define PIN_A2   (16)
#define PIN_A3   (17)static const uint8_t MA0 = PIN_A0;
static const uint8_t MA1 = PIN_A1;
static const uint8_t MA2 = PIN_A2;
static const uint8_t MA3 = PIN_A3;// BLUE TOOTH
char command;void setup() 
{// put your setup code here, to run once:Serial.begin(9600);pinMode(MA0, OUTPUT);pinMode(MA1, OUTPUT);pinMode(MA2, OUTPUT);pinMode(MA3, OUTPUT);
}void loop() 
{while(Serial.available()){command =Serial.read();switch(command ){case 0x18:    //前进digitalWrite(MA0, LOW);digitalWrite(MA1, HIGH);digitalWrite(MA2, LOW);digitalWrite(MA3, HIGH);break;case 0x52:    //后退digitalWrite(MA0, HIGH);digitalWrite(MA1, LOW);digitalWrite(MA2, HIGH);digitalWrite(MA3, LOW);break;case 0x08:    // 左转digitalWrite(MA0, HIGH);digitalWrite(MA1, LOW);digitalWrite(MA2, LOW);digitalWrite(MA3, HIGH);break;case 0x5a:     //右转digitalWrite(MA0, LOW);digitalWrite(MA1, HIGH);digitalWrite(MA2, HIGH);digitalWrite(MA3, LOW);break;case 0x45: default:digitalWrite(MA0, LOW);digitalWrite(MA1, LOW);digitalWrite(MA2, LOW);digitalWrite(MA3, LOW);break;        }}
}

4 App设计

        使用微信小程序开发App,其特点是集成在微信App内,不用单独安装,搜索到该App既可以使用。该程序主要实现4个按钮,实现小车前进、后退、左转、右转功能。

App UI:

开发工具:

核心代码如下: 

const utils = require('utils.js')
const ble = require('bluetooth.js')
Page({/*** 页面的初始数据*/data: {pageload: false,connected: false,send_hex: false,send_string: true,send_string_val: 'Hex',recv_string: true,recv_string_val: 'Hex',recv_value: '',send_number: 0,recv_number: 0,recv_hex: true,try_cnt:0,deviceArray: []},/*** 生命周期函数--监听页面加载*/onLoad: function (options) {var that = this; console.log(options);this.setData({pageload:true,connected: false,deviceId: options.id,try_cnt:0,deviceName: options.name});console.log("detail:  onLoad");wx.stopBluetoothDevicesDiscovery({success: function (res) {console.log('停止搜索设备', res)}})that.closeBLEConnection(that.data.deviceId);that.createBLEConnection(that.data.deviceId, that.data.deviceName); }, onHide () {var that = this;// Do something when hide.// 断开连接console.log("detail:  onHide");},onShow:function(){      // var that = this; // connect bluetooth// that.closeBLEConnection(that.data.deviceId);// that.createBLEConnection(that.data.deviceId, that.data.deviceName); },onUnload() {var that = this;this.setData({pageload:true,connected: false,try_cnt:0,});console.log("page:  onUnload  ");that.offBLEMonitor();that.closeBLEConnection(that.data.deviceId);that.closeBluetoothAdapter();wx.showToast({title: '断开蓝牙',icon: 'success',duration: 2000})  },DisConnectTap:function(){var that = this;that.setData({pageload:true,connected: false,try_cnt:0,});ble.openBluetoothAdapter(that.data.deviceId, that.data.deviceName);that.createBLEConnection(that.data.deviceId, that.data.deviceName); },RecvCleanTap: function () {this.setData({recv_value: '',recv_number: 0});},  /*** 创建连接* @param {*} deviceId * @param {*} name */createBLEConnection(deviceId, name) {wx.createBLEConnection({deviceId,  success: (res) => {console.log('createBLEConnection - success: ', res)this.getBLEDeviceServices(deviceId)              },fail: (res) => {console.error('createBLEConnection - fail: ', res)if(res.errCode == 10006 ){this.createBLEConnection(deviceId, name)}else{ble.openBluetoothAdapter(deviceId, name)this.createBLEConnection(deviceId, name)}this.setData({connected: false,})               } })},getBLEDeviceServices(deviceId) {var that = this;wx.getBLEDeviceServices({deviceId,success: (res) => {console.log('getBLEDeviceServices - success: ', res)for (let i = 0; i < res.services.length; i++) {var ergodic_UUID =res.services[i].uuid;      //取出服务里面的UUIDvar UUID_slice = ergodic_UUID.slice(4, 8);   //截取4到8位console.log('getBLEDeviceServices, service ID =  ', res.services[i].uuid);if ( res.services[i].isPrimary && (UUID_slice == "FFE0") ) {that.setData({serviceId: res.services[i].uuid,});break;}}wx.getConnectedBluetoothDevices({services: res.services,success: (res) => {                         console.log("getConnectedBluetoothDevices - success:  " +  res)},fail: (res) => {console.error('getConnectedBluetoothDevices - fail: ', res)ble.openBluetoothAdapter(deviceId, that.data.deviceName)}                    })that.getBLEDeviceCharacteristics(deviceId, that.data.serviceId);},fail: (res) => {console.error('getBLEDeviceServices - fail: ', res)// try it againble.openBluetoothAdapter(deviceId, that.data.deviceName)that.monitor_connected();} });},getBLEDeviceCharacteristics(deviceId, serviceId) {var that = this;let falg = false;wx.getBLEDeviceCharacteristics({deviceId,serviceId,success: (res) => {that.setData({connected: true,})                console.log('getBLEDeviceCharacteristics success', res.characteristics)for (let i = 0; i < res.characteristics.length; i++) {let item = res.characteristics[i]console.log('getBLEDeviceCharacteristics, Characteristics ID =  ', item.uuid)// 该特征值:可读if (item.properties.read) {wx.readBLECharacteristicValue({deviceId,serviceId,characteristicId: item.uuid,})}// 该特征值:可写if (item.properties.write) {this.setData({canWrite: true})this._deviceId = deviceIdthis._serviceId = serviceIdthis._characteristicId = item.uuidthis.writeValue()}if (item.properties.notify || item.properties.indicate) {that.setData({characteristicId: item.uuid});falg = true;break;}}if( falg ){console.debug('getBLEDeviceCharacteristics - deviceId : ', deviceId)console.debug('getBLEDeviceCharacteristics - serviceId : ', serviceId)console.debug('getBLEDeviceCharacteristics - characteristicId: ', that.data.characteristicId)// read device character value that.readBLECharacteristicValue(deviceId, serviceId, that.data.characteristicId)   that.notifyBLECharacteristicValueChange(deviceId, serviceId, that.data.characteristicId) }},fail: (res) => {console.error('getBLEDeviceCharacteristics -- fail: ', res)this.setData({connected: false,})if (res.errCode === 10006){that.offBLEMonitor();that.createBLEConnection(deviceId, that.data.deviceName); }}})},readBLECharacteristicValue(deviceId,serviceId, characteristicId ){wx.readBLECharacteristicValue({// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接deviceId,// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取serviceId,// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取characteristicId,success (res) {console.log('readBLECharacteristicValue:', res.errCode)}})},notifyBLECharacteristicValueChange(deviceId,serviceId, characteristicId ){var that = this;wx.notifyBLECharacteristicValueChange({state: true,    // enable notifydeviceId,serviceId,characteristicId,success: (res) => {console.info('notifyBLECharacteristicValueChange success: ', res.errMsg)// read data here // 操作之前先监听,保证第一时间获取数据wx.onBLECharacteristicValueChange(function(res) {that.data.connected = true; console.info('onBLECharacteristicValueChange', res);console.info(`characteristic ${res.characteristicId} has changed, now is ${res.value}`);var result = res.value;var hex = utils.buf2hex(result);var _hex_ss =  utils.hex2string(hex);console.info("hex: " + hex);console.info("string: " + _hex_ss);var recv_number_1 = that.data.recv_number + _hex_ss.length / 2;var recv_number = Math.round(recv_number_1);that.setData({recv_number: recv_number,recv_value: that.data.recv_value + _hex_ss,});let _ss = that.data.recv_valueif( _ss.includes("TM(C):") && _ss.includes("HM:") && _ss.includes("\n")){let buff =  _ss.split(' ')console.log( _ss )console.log(buff)that.data.recv_value = "";that.data.recv_number = 0;that.setData({temphtValue: buff[2],humidityValue: buff[4],});}      that.monitor_connected();})                                 },fail: (res) => {console.error('notifyBLECharacteristicValueChange fail: ', res)that.monitor_connected();}})    },monitor_connected_action(){var that = this;let deviceId = that.data.deviceId;wx.onBLEConnectionStateChange(function(res) {// 该方法回调中可以用于处理连接意外断开等异常情况console.log( "onBLEConnectionStateChange ----- " +  `device ${res.deviceId} state has changed, connected: ${res.connected}`)if( res.deviceId == deviceId && res.connected == false ){    wx.closeBLEConnection({deviceId,success: (res) => {console.debug('detail: closeBLEConnection success', res);  that.offBLEMonitor();that.createBLEConnection(deviceId, that.data.deviceName); },fail: (res) => {                     console.error('detail: closeBLEConnection fail', res);  if (res.errCode === 10006) {that.offBLEMonitor();that.createBLEConnection(deviceId, that.data.deviceName); }}})that.setData({try_cnt: that.data.try_cnt + 1,})}else{that.data.try_cnt  = 0;}})   },monitor_connected(){var that = this;setTimeout(that.monitor_connected_action, 200);},writeValue( val ) {// 向蓝牙设备发送一个0x00的16进制数据let buffer = new ArrayBuffer(1);let dataView = new DataView(buffer);dataView.setUint8(0, val);console.debug('getBLEDeviceCharacteristics - deviceId : ', this._deviceId)console.debug('getBLEDeviceCharacteristics - serviceId : ', this._serviceId)console.debug('getBLEDeviceCharacteristics - characteristicId: ', this._characteristicId)wx.writeBLECharacteristicValue({deviceId: this._deviceId,serviceId: this._serviceId,characteristicId: this._characteristicId,value: buffer,success: (res) => {console.debug('writeBLECharacteristicValue success', res);  },fail: (res) => {console.error(' writeBLECharacteristicValue fail', res);  this.setData({connected: false,}) }})},closeBluetoothAdapter() {wx.closeBluetoothAdapter({           success (res) {console.log(res)}        })this.setData({connected: false,}),         this._discoveryStarted = false},closeBLEConnection( deviceId ) {wx.closeBLEConnection({deviceId,success: (res) => {console.debug('detail: closeBLEConnection success', res);  },fail: (res) => {console.error('detail: closeBLEConnection fail', res);  }})this.setData({connected: false,canWrite: false,})},run_up:function(){var that = this;var val = 0x18 ;      that.writeValue( val );   }, run_down:function(){var that = this;var val = 0x52;      that.writeValue( val );   },run_left:function(){var that = this;var val = 0x08;      that.writeValue( val );   },run_right:function(){var that = this;var val = 0x5a;      that.writeValue( val );   },whiteLightValueSliderChange:function(e){var that = this;// 向蓝牙设备发送一个0x00的16进制数据var val = Math.random() * 255 | 0;      that.writeValue( val );   },offBLEMonitor(){this.setData({connected: false,}), wx.offBLEPeripheralConnectionStateChanged();wx.offBLEConnectionStateChange();wx.offBLECharacteristicValueChange();wx.offBLEMTUChange();}
})

5 参考文献

1)使用Arduino UNO硬件平台制作智能小车-CSDN博客

2)汇承HC-08蓝牙串口模块使用规格书(含指令集).pdf

3)概览 | 微信开放文档 (qq.com)

4)Arduino 实验室 – Arduino中文站,提供丰富的Arduino教程和DIY资讯 (nxez.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/677435.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows下搭建Redis Sentinel

下载安装程序 下载Redis关于Windows安装程序&#xff0c;下载地址 下载成功后进行解压&#xff0c;解压如下&#xff1a; 配置redis和sentinel 首先复制三份redis.windows.conf&#xff0c;分别命名为&#xff1a;redis.6379.conf、redis.6380.conf、redis.6381.conf&…

Spring基础 - SpringMVC请求流程和案例

Spring基础 - SpringMVC请求流程和案例 什么是MVC 用一种业务逻辑、数据、界面显示分离的方法&#xff0c;将业务逻辑聚集到一个部件里面&#xff0c;在改进和个性化定制界面及用户交互的同时&#xff0c;不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理…

【漏洞复现】SpringBlade export-user接口存在SQL注入漏洞

漏洞描述 SpringBlade 是一个由商业级项目升级优化而来的微服务架构 采用Spring Boot 2.7 、Spring Cloud 2021 等核心技术构建,完全遵循阿里巴巴编码规范。提供基于React和Vue的两个前端框架用于快速搭建企业级的SaaS多租户微服务平台。SpringBlade export-user接口存在SQL注…

4核8G服务器性能怎么样?4核8G12M配置能支持多少人同时访问?

4核8G服务器性能怎么样?4核8G12M配置能支持多少人同时访问&#xff1f;腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为…

Doris中的本地routineload环境,用于开发回归测试用例

----------------2024-2-6-更新-------------- doris的routineload&#xff0c;就是从kafka中加载数据到表&#xff0c;特点是定时、周期性的从kafka取数据。 要想在本地开发测试routine load相关功能&#xff0c;需要配置kafka环境&#xff0c;尤其是需要增加routine load回…

C语言中的数据类型-强转

强制类型转换 概念&#xff1a;将某种类型的数据转化我们需要的数据类型&#xff0c;注意强制类型转化是临时强转&#xff0c;不会改变本身的数据类型。 强转又分为显式强转和隐式转化 显示强转是按照我们的要求进行转化 格式&#xff1a;(需要转化数据类型)变量名 #inclu…

fast.ai 深度学习笔记(五)

深度学习 2&#xff1a;第 2 部分第 10 课 原文&#xff1a;medium.com/hiromi_suenaga/deep-learning-2-part-2-lesson-10-422d87c3340c 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 来自 fast.ai 课程的个人笔记。随着我继续复习课程以“真正”理解它&#xff0c;…

Stable Diffusion 模型下载:GhostMix(幽灵混合)

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十 下载地址 模型介绍 GhostMix 是绝对让你惊艳的模型&#xff0c;也是自己认为现在最强的2.5D模型。我认为模型的更新应该是基于现有的画面整体不大变的前提下&#xff0c;提高模型的成…

单片机学习笔记---蜂鸣器工作原理

目录 蜂鸣器介绍 蜂鸣器的驱动方式 ULN2003D芯片工作原理 实战预备知识&#xff1a;基础乐理 音名的分组 全音和半音的关系 音高的表示 五线谱中的符号定义 简谱上的符号定义 C调音符与频率对照表 相关计算 蜂鸣器介绍 蜂鸣器是一种将电信号转换为声音信号的器件&a…

C++,stl,list容器详解

目录 1.list基本概念 2.list构造函数 3.list的赋值和交换 4.list大小操作 5.list的插入的删除 6.list数据存取 7.list反转和排序 排序案例 1.list基本概念 2.list构造函数 #include<bits/stdc.h> using namespace std;void print(const list<int> &lk) …

Maui blazor ios 按设备类型设置是否启用safeArea

需求&#xff0c;新做了个app&#xff0c; 使用的是maui blazor技术&#xff0c;里面用了渐变背景&#xff0c;在默认启用SafeArea情况下&#xff0c;底部背景很突兀 由于现版本maui在SafeArea有点bug&#xff0c;官方教程的<ContentPage SafeAreafalse不生效&#xff0c;于…

防火墙USG6000V配置接口实验

要求:防火墙向下使用子接口分别对应生产区和办公区,所有分区设备可以ping通网关 最终效果部分示例:client1,Server1,PC2都能ping通网关 实现流程: 云要添加虚拟网卡ip(此处用的是创建的虚拟环回ip),更改端口映射为双向通道且更改编号 SW1:#要先登录防火墙初始账号和密码,然后…

电商小程序05用户注册

目录 1 搭建页面2 设置默认跳转总结 我们上一篇拆解了登录功能&#xff0c;如果用户没有账号就需要注册了。本篇我们介绍一下注册功能的实现。 1 搭建页面 打开应用&#xff0c;点击左上角的新建页面 输入页面的名称&#xff0c;用户注册 删掉网格布局&#xff0c;添加表单容…

Qt网络编程-ZMQ的使用

不同主机或者相同主机中不同进程之间可以借助网络通信相互进行数据交互&#xff0c;网络通信实现了进程之间的通信。比如两个进程之间需要借助UDP进行单播通信&#xff0c;则双方需要知道对方的IP和端口&#xff0c;假设两者不在同一主机中&#xff0c;如下示意图&#xff1a; …

查看系统进程信息的Tasklist命令

Tasklist命令是一个用来显示运行在本地计算机上所有进程的命令行工具&#xff0c;带有多个执行参数。另外&#xff0c;Tasklist可以代替Tlist工具。通过任务管理器&#xff0c;可以查看到本机完整的进程列表&#xff0c;而且可以通过手工定制进程列表方式获得更多进程信息&…

回归预测模型:MATLAB多项式回归

1. 多项式回归模型的基本原理 多项式回归是线性回归的一种扩展&#xff0c;用于分析自变量 X X X与因变量 Y Y Y之间的非线性关系。与简单的线性回归模型不同&#xff0c;多项式回归模型通过引入自变量的高次项来增加模型的复杂度&#xff0c;从而能够拟合数据中的非线性模式。…

【北邮鲁鹏老师计算机视觉课程笔记】02 filter

1 图像的类型 二进制图像&#xff1a; 灰度图像&#xff1a; 彩色图像&#xff1a; 2 任务&#xff1a;图像去噪 噪声点让我们看得难受是因为噪声点与周边像素差别很大 3 均值 滤波核 卷积核 4 卷积操作 对应相乘再累加起来 卷积核记录了权值&#xff0c;把权值套到要卷积…

Redis——集群环境部署

一般情况下的Redis&#xff0c;我们都是在一台服务器上进行操作的&#xff0c;也就是说读、写以及备份操作都是在一台Redis服务器上进行的。随着项目访问量的增加&#xff0c;对Redis服务器的操作也更加频繁&#xff0c;虽然Redis读写速度都很快&#xff0c;但是一定程度上也会…

统一身份认证系统架构设计与实践总结

随着互联网的快速发展和应用的普及&#xff0c;人们在各个网站和应用上需要不同的账号和密码进行身份认证。为了解决这个问题&#xff0c;统一身份认证系统应运而生。本文将总结统一身份认证系统的架构设计与实践经验&#xff0c;帮助读者了解如何设计和实现一个高效、安全的统…

〖大前端 - ES6篇②〗- let和const

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;哈哥撩编程&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xff0c;目前在公司…