文章目录
全部文件
基于Arduino的可采集数据上传到阿里云的体感手柄
前言
作品思路:
(1)通过检测加速度传感器的姿态,实现对舵机角度控制使之分别偏转30、45、90度-模拟遥控飞机的上左右按键。
(2)通过压力传感器的压力变化来控制电机的快慢-模拟控制遥控飞机的马达转速
(3)检测手柄的温度,达到设定阈值后蜂鸣器和灯光提示,通过lcd显示当前温度-模拟检测手柄的温度,防止手柄过度被使用而烧坏。
(4)以上三种传感器的数据都可以在云平台上面展示。
一、所需准备材料
1、软件
- Arduino IDE
- 阿里云物联网平台
2、硬件
- wemos D1主控板
- MPU6050加速度传感器
- key压力传感器
- 马达
- LCD1602液晶屏
- 5V继电器
- 面包板
- 杜邦线若干
二、接线
温度传感器ds18b20:
GND - GND
VCC - VCC5V
S - D5
蜂鸣器:
GND - GND
VCC - VCC5V
S - D6
三色LED:
GND - GND
R - D7
压力传感器:
GND - GND
VCC - VCC5V
S - A0
继电器-控制端:
VCC-5V
GND-GND
S - D10
继电器-输出端:
NO - 电机
公共端 - 3.3V
MPU-6050:
SCL - D3
SDA - D4
GND - GND
VCC - VCC5V
SG90舵机:
GND - GND
VCC - VCC5V
数据端 - D9
LCD1602:
GND - GND
VCC - VCC5V
SCL - D15
SDA - D14
三、代码
1、引入以下库文件到Arduino IDE的libraries
2、IDE上的准备
添加8266开发板包,添加过程可参考
https://blog.youkuaiyun.com/K_AAbb/article/details/108066550
选择wemos开发板
3、烧录代码
/**阿里云**/
#include <ESP8266WiFi.h>//安装esp8266arduino开发环境
static WiFiClient espClient;
#include <AliyunIoTSDK.h>//引入阿里云 IoT SDK
//需要安装crypto库、PubSubClient库
//设置产品和设备的信息,从阿里云设备信息里查看
#define PRODUCT_KEY "a1dzs9TX6RJ"//替换自己的PRODUCT_KEY
#define DEVICE_NAME "USER"//替换自己的DEVICE_NAME
#define DEVICE_SECRET "weuOhE0MaNa3egw4zioNmjQCPxyjMqko"//替换自己的DEVICE_SECRET
#define REGION_ID "cn-shanghai"//默认cn-shanghai
#define WIFI_SSID "misha"//替换自己的WIFI
#define WIFI_PASSWD "37168510"//替换自己的WIFI
unsigned long lastMsMain = 0;
/**温度**/
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#define ONE_WIRE_BUS D5 //ds18b20温度
OneWire oneWire(ONE_WIRE_BUS);// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
float tempC = 0;
int TEM;
const int tonePin=D6;//蜂鸣器
const int redPin = D7;//三色led
/**压力**/
const int pinRelay = D10;//管脚D12连接到继电器模块的信号脚
const int s_pin = A0;//定义压力传感器为A0
int val = 0;//创建val储存压力值
/**加速度**/
#include <Kalman.h>
#include <Wire.h>
#include <Math.h>
#include <Servo.h> // 声明调用Servo.h库
Servo myservo; // 创建一个舵机对象
float fRad2Deg = 57.295779513f; //将弧度转为角度的乘数
const int MPU = 0x68; //MPU-6050的I2C地址
const int nValCnt = 7; //一次读取寄存器的数量
const int nCalibTimes = 1000;//校准时读数的次数
int calibData[nValCnt]; //校准数据
unsigned long nLastTime = 0; //上一次读数的时间
float fLastRoll = 0.0f; //上一次滤波得到的Roll角
float fLastPitch = 0.0f; //上一次滤波得到的Pitch角
Kalman kalmanRoll; //Roll角滤波器
Kalman kalmanPitch; //Pitch角滤波器
/**LCD1602**/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,16,2); //LCD1602总线地址,0x3F
void setup(void)
{
Serial.begin(9600);
/**阿里云初始化**/
wifiInit(WIFI_SSID, WIFI_PASSWD);//连接到wifi
//初始化 iot,需传入 wifi 的 client,和设备产品信息
AliyunIoTSDK::begin(espClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET, REGION_ID);
/**压力初始化**/
pinMode(s_pin,INPUT); //压力
pinMode(pinRelay,OUTPUT);//设置pinRelay脚为输出状态
/**温度初始化**/
sensors.begin(); // initialize the bus
pinMode(redPin, OUTPUT); //定义三色led为输出模式
pinMode(tonePin,OUTPUT); //定义蜂鸣器为输出模式
/**加速度初始化**/
Wire.begin(); //初始化Wire库
WriteMPUReg(0x68, 0); //启动MPU6050设备,0x68为MPU6050总线地址
Calibration(); //执行校准
nLastTime = micros(); //记录当前时间
myservo.attach(D9); // 将引脚D2上的舵机与声明的舵机对
/**LCD1602初始化**/
lcd.init(); //初始化lcd
lcd.backlight(); //打开背光灯
}
void loop(void)
{
/**阿里云循环**/
Yun();
/**压力循环**/
Stress();
/**温度循环**/
Temperature();
/**加速度循环**/
Speed();
/**LCD1602循环**/
LCD();
}
void Yun(void){
AliyunIoTSDK::loop();//必要函数
if (millis() - lastMsMain >= 2000){//每2秒发送一次
lastMsMain = millis();
//发送LED状态到云平台(高电平:1;低电平:0)
AliyunIoTSDK::send("LED", digitalRead(D7));//“ “内为标识符
AliyunIoTSDK::send("wendu", sensors.getTempCByIndex(0));//
AliyunIoTSDK::send("yayali", analogRead(A0));//
}
}
void Stress(void){//压力
val=analogRead(s_pin);//读取模拟接口0 的值,并将其赋给val
if(val > 500){
digitalWrite(pinRelay,HIGH);
delay(10);
}else{
digitalWrite(pinRelay,LOW);
delay(10);
}
}
void Temperature(void){//温度
sensors.requestTemperatures(); // Send the command to get temperatures
TEM = map(sensors.getTempCByIndex(0), 25, 30, 0, 255);
tempC = sensors.getTempCByIndex(0);//将温度的值赋给tempC
if(tempC<28){ //灯不亮,蜂鸣器不响
digitalWrite(redPin,LOW);
digitalWrite(tonePin,LOW);
}
else{//当温度超过28度,蜂鸣器响起,灯光灭
digitalWrite(redPin,HIGH);
digitalWrite(tonePin,HIGH);
}
}
void Speed(void){//加速度
int readouts[nValCnt];
ReadAccGyr(readouts); //读出测量值
float realVals[7];
Rectify(readouts, realVals); //根据校准的偏移量进行纠正
//计算加速度向量的模长,均以g为单位
float fNorm = sqrt(realVals[0] * realVals[0] + realVals[1] * realVals[1] + realVals[2] * realVals[2]);
float fRoll = GetRoll(realVals, fNorm); //计算Roll角
if (realVals[1] > 0) {
fRoll = -fRoll;
}
float fPitch = GetPitch(realVals, fNorm); //计算Pitch角
if (realVals[0] < 0) {
fPitch = -fPitch;
}
unsigned long nCurTime = micros();//计算两次测量的时间间隔dt,以秒为单位
float dt = (double)(nCurTime - nLastTime) / 1000000.0;
//对Roll角和Pitch角进行卡尔曼滤波
float fNewRoll = kalmanRoll.getAngle(fRoll, realVals[4], dt);
float fNewPitch = kalmanPitch.getAngle(fPitch, realVals[5], dt);
//跟据滤波值计算角度速
float fRollRate = (fNewRoll - fLastRoll) / dt;
float fPitchRate = (fNewPitch - fLastPitch) / dt;
//更新Roll角和Pitch角
fLastRoll = fNewRoll;
fLastPitch = fNewPitch;
//更新本次测的时间
nLastTime = nCurTime;
/**本次识别左倾和右倾,前倾和后倾,用了每个倾斜状态能达到的独特值**/
// 左倾,0
if ( fLastPitch > -100 && fLastPitch < -60){
myservo.write(0);
delay(100);
}
//右倾,180
else if( fLastPitch > 185 && fLastPitch < 250) {
for(int j=0;j<=180;j++){
myservo.write(j);
delay(20);}
}
//前倾,45
else if(( fLastRoll > -230 && fLastRoll < -175) && fLastPitch > 0){
for(int k=0;k<=45;k++){
myservo.write(k);
delay(20);}
}
//后倾,135
else if(( fLastRoll > 120 && fLastRoll < 170) && fLastPitch < 0){
for(int p=0;p<=135;p++){
myservo.write(p);
delay(20);}
}
else{
myservo.write(0);
delay(100);
}
Serial.print("Roll:");
Serial.println(fNewRoll);
Serial.print("Pitch:");
Serial.println(fNewPitch);
// delay(4000);//---------------------------------------------------这一延时不知对功能有没影响,若有影响删除延时就行--------------------------------------------//
}
void LCD(void){//LCD1602
lcd.setCursor(0,0); // 光标从0列,0行开始打印
lcd.print("temp:");
lcd.print(tempC); // Print a message to the LCD.
lcd.setCursor(0,1); // 光标从0列1行开始打印
lcd.print("Stress:");
lcd.print(val); // Print a message to the LCD.
delay(500); //wait for 250 microseconds
lcd.clear();
}
/**阿里云串口显示**/
//wifi 连接
void wifiInit(const char *ssid, const char *passphrase)
{
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, passphrase);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println("WiFi not Connect");
}
Serial.println("Connected to AP");
}
/**阿里云串口显示**/
/**加速度算法**/
//向MPU6050写入一个字节的数据
//指定寄存器地址与一个字节的值
void WriteMPUReg(int nReg, unsigned char nVal) {
Wire.beginTransmission(MPU);
Wire.write(nReg);
Wire.write(nVal);
Wire.endTransmission(true);
}
//从MPU6050读出一个字节的数据
//指定寄存器地址,返回读出的值
unsigned char ReadMPUReg(int nReg) {
Wire.beginTransmission(MPU);
Wire.write(nReg);
Wire.requestFrom(MPU, 1, true);
Wire.endTransmission(true);
return Wire.read();
}
//从MPU6050读出加速度计三个分量、温度和三个角速度计
//保存在指定的数组中
void ReadAccGyr(int *pVals) {
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.requestFrom(MPU, nValCnt * 2, true);
Wire.endTransmission(true);
for (long i = 0; i < nValCnt; ++i) {
pVals[i] = Wire.read() << 8 | Wire.read();
}
}
//对大量读数进行统计,校准平均偏移量
void Calibration()
{
float valSums[7] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0};
//先求和
for (int i = 0; i < nCalibTimes; ++i) {
int mpuVals[nValCnt];
ReadAccGyr(mpuVals);
for (int j = 0; j < nValCnt; ++j) {
valSums[j] += mpuVals[j];
}
}
//再求平均
for (int i = 0; i < nValCnt; ++i) {
calibData[i] = int(valSums[i] / nCalibTimes);
}
calibData[2] += 16384; //设芯片Z轴竖直向下,设定静态工作点。
}
//算得Roll角。算法见文档。
float GetRoll(float *pRealVals, float fNorm) {
float fNormXZ = sqrt(pRealVals[0] * pRealVals[0] + pRealVals[2] * pRealVals[2]);
float fCos = fNormXZ / fNorm;
return acos(fCos) * fRad2Deg;
}
//算得Pitch角。算法见文档。
float GetPitch(float *pRealVals, float fNorm) {
float fNormYZ = sqrt(pRealVals[1] * pRealVals[1] + pRealVals[2] * pRealVals[2]);
float fCos = fNormYZ / fNorm;
return acos(fCos) * fRad2Deg;
}
//对读数进行纠正,消除偏移,并转换为物理量。公式见文档。
void Rectify(int *pReadout, float *pRealVals) {
for (int i = 0; i < 3; ++i) {
pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 16384.0f;
}
pRealVals[3] = pReadout[3] / 340.0f + 36.53;
for (int i = 4; i < 7; ++i) {
pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 131.0f;
}
}
/**加速度算法**/
四、阿里云部分
这部分就不说了吧,我以前的博客也有类似的,基本就是创建产品,创建设备,定义产品功能这些了,不会的去百度百度
结语
做这个项目源于以前去帮别人做毕设,距离现在21年也快一年半了吧,当时还不是很懂得整理资料,资料方面内容倒是很全,但是可能会有点乱,好多细节也不太记得了,大家多动动手去做就熟练啦。