【Arduino】基于阿里云的体感手柄


全部文件

基于Arduino的可采集数据上传到阿里云的体感手柄


前言

作品思路:
(1)通过检测加速度传感器的姿态,实现对舵机角度控制使之分别偏转304590-模拟遥控飞机的上左右按键。

(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.csdn.net/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年也快一年半了吧,当时还不是很懂得整理资料,资料方面内容倒是很全,但是可能会有点乱,好多细节也不太记得了,大家多动动手去做就熟练啦。

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值