Mini四轴自动控制(五) ESP8266-12F SPI通信,电机PWM频率自定义-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 13850|回复: 5

[项目] Mini四轴自动控制(五) ESP8266-12F SPI通信,电机PWM频率自定义

[复制链接]
发表于 2018-11-27 19:59 | 显示全部楼层 |阅读模式
本帖最后由 zxldwlsj 于 2018-12-1 08:35 编辑

好久没更新了,今天给大家带来了满满的干货:

  • Arduino Leonardo和ESP8266 SPI接口通信;
  • 四个电机PWM频率自定义设置因为用analogWrite频率会很低,对空心杯不合适(这里涉及多个定时器的设置,以后会给出详细文档介绍);
  • 如何将浮点数据和字节数据相互转化因为spi是一个字节一个字节传数据的,而我们的数据又是小数,所以为了传输数据,要将小数转为字节,同时接受到字节数据,我们还得转为小数用于我们的控制器设计。



废话不多说,直接上代码。代码我就不做具体解释了,萌新看不懂的可以留言,我会回复的。定时器设置部分(带pwm字眼的)可以先不看,等我下回分解。

下面这是写到ESP8266里面的,从机模式。注意由于这里的代码显示有问题,大家要仔细检查[mw_shl_code=arduino,true]#include <ESP8266WiFi.h>
#include "SPISlave.h"

uint8_t buf_RecFromWiFi[32] = {0};
uint8_t buf_SendToWiFi[32] = {0};
const char *ssid     = "Quanser_UVS";
const char *password = "UVS_wifi";
const char *host = "192.168.2.10";
const int tcpPort = 18005;
IPAddress staticIP(192,168,2,66);
IPAddress gateway(192,168,2,10);
IPAddress subnet(255,255,255,0);
WiFiClient client;

void setup()
{
// Serial.begin(115200);
  WiFi.begin(ssid, password);
  WiFi.config(staticIP, gateway, subnet);
  while (WiFi.status() != WL_CONNECTED)
    {
        delay(100);
     }
  SPISlave.begin();
}

void loop()
{
  while (!client.connected())
    {
        if (!client.connect(host, tcpPort))
        {
            delay(50);
        }
    }   
/**** read motor data from wifi and send them to master ****/
   if (client.available())
   {
      for(int i=0;i<16;i++)
      {
        buf_RecFromWiFi = client.read();
       }
        for(int j=16;j<32;j++)
      {
        buf_RecFromWiFi[j] = 0;
       }
       SPISlave.setData(buf_RecFromWiFi,32);
   }
   
   // delay(2);   
/**** read data from master and send them to wifi ****/
   SPISlave.onData([](uint8_t * buf_send, size_t len) {
      for(int j=0;j<32;j++)
        {
         buf_SendToWiFi[j] =buf_send[j];
        }
      });
     for(int j=0;j<32;j++)
     {
        client.write(buf_SendToWiFi[j]);
     }               
}[/mw_shl_code]

下面写到arduino开发板里面,注意由于这里的代码显示有问题,大家要仔细检查



[mw_shl_code=arduino,true]
#include <SPI.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
MPU6050 mpu;

float dt;
int16_t ax, ay, az, gx, gy, gz;
uint32_t timer;
float MOTOR1 = 0, MOTOR2 = 0, MOTOR3 = 0, MOTOR4 = 0;
int moto1 = 0, moto2 = 0, moto3 = 0, moto4 = 0;
uint8_t buf_receive[32] = {0};
uint8_t buf_send[32] = {0};

union Float6ToByte24
{
  float Float[6];
  uint8_t Byte[24];
};
union Float4ToByte16
{
  float Float[4];
  uint8_t Byte[16];
};
union Float1ToByte4
{
  float Float[1];
  uint8_t Byte[4];
};
Float6ToByte24 gyo_union;
Float4ToByte16 motor_union;
Float1ToByte4 dt_union, motor_add_union;
class ESPSafeMaster {
  private:
    uint8_t _ss_pin;
    void _pulseSS() {
      digitalWrite(_ss_pin, HIGH);
      delayMicroseconds(5);
      digitalWrite(_ss_pin, LOW);
    }
  public:
    ESPSafeMaster(uint8_t pin): _ss_pin(pin) {}
    void begin() {
      pinMode(_ss_pin, OUTPUT);
      _pulseSS();
    }

    uint32_t readStatus() {
      _pulseSS();
      SPI.transfer(0x04);
      uint32_t status = (SPI.transfer(0) | ((uint32_t)(SPI.transfer(0)) << 8) | ((uint32_t)(SPI.transfer(0)) << 16) | ((uint32_t)(SPI.transfer(0)) << 24));
      _pulseSS();
      return status;
    }

    void writeStatus(uint32_t status) {
      _pulseSS();
      SPI.transfer(0x01);
      SPI.transfer(status & 0xFF);
      SPI.transfer((status >> 8) & 0xFF);
      SPI.transfer((status >> 16) & 0xFF);
      SPI.transfer((status >> 24) & 0xFF);
      _pulseSS();
    }

    void readData(uint8_t * data) {
      // _pulseSS();
      SPI.transfer(0x03);
      SPI.transfer(0x00);
      for (uint8_t i = 0; i < 32; i++) {
        data = SPI.transfer(0);
      }
      // _pulseSS();
    }

    void writeData(uint8_t * data, size_t len) {
      uint8_t i = 0;
      //_pulseSS();
      SPI.transfer(0x02);
      SPI.transfer(0x00);
      while (len-- && i < 32) {
        SPI.transfer(data[i++]);
      }
      while (i++ < 32) {
        SPI.transfer(0);
      }
      // _pulseSS();
    }
};
ESPSafeMaster esp(8);

void pwm5_9_10configure(int mode)
{
  // TCCR1A configuration
  //  00 : Channel A disabled D9
  //  00 : Channel B disabled D10
  //  00 : Channel C disabled D11
  //  01 : Fast PWM 8 bit
  TCCR1A = 1;
  TCCR3A = 1;

  // TCCR1B configuration
  // Clock mode and Fast PWM 8 bit
  TCCR1B = mode | 0x08;
  TCCR3B = mode | 0x08;

  // TCCR1C configuration
  TCCR1C = 0;
  TCCR3C = 0;
}
void pwm6configure(int mode)
{
  // TCCR4A configuration
  TCCR4A = 0;
  // TCCR4B configuration
  TCCR4B = mode;
  // TCCR4C configuration
  TCCR4C = 0;
  // TCCR4D configuration
  TCCR4D = 0;
  // PLL Configuration
  // Use 96MHz / 1.5 = 64MHz
  PLLFRQ = (PLLFRQ & 0xCF) | 0x20;
  // PLLFRQ=(PLLFRQ&0xCF)|0x10;// Will double all frequencies

  // Terminal count for Timer 4 PWM
  OCR4C = 255;
}
void pwmSet5(int value)
{
  OCR3A = value; // Set PWM value
  //DDRB|=1<<5;    // Set Output Mode B5
  TCCR3A |= 0x80; // Activate channel
}
void pwmSet9(int value)
{
  OCR1A = value; // Set PWM value
  //DDRB|=1<<5;    // Set Output Mode B5
  TCCR1A |= 0x80; // Activate channel
}
void pwmSet10(int value)
{
  OCR1B = value; // Set PWM value
  //DDRB|=1<<6;    // Set Output Mode B6
  TCCR1A |= 0x20; // Set PWM value
}
void pwmSet6(int value)
{
  OCR4D = value; // Set PWM value
  //DDRD|=1<<7;    // Set Output Mode D7
  TCCR4C |= 0x09; // Activate channel D
}
void setup()
{
  //Serial.begin(115200);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pwm5_9_10configure(1);//16M/256/1=62500Hz
  // pwm5_9_10configure(3);//16M/256/64=976Hz
  pwm6configure(4);//64M/256/4=62500Hz
  // pwm6configure(9);//64M/256/256=976Hz
  SPI.begin();
  SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
  mpu.initialize();
  esp.begin();
  delay(500);
}

void loop()
{
  dt = (float)(micros() - timer) / 1000000; // Calculate delta time
  timer = micros();
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);     //IIC获取MPU6050六轴数据 ax ay az gx gy gz
  gyo_union.Float[0] = ax;
  gyo_union.Float[1] = ay;
  gyo_union.Float[2] = az;
  gyo_union.Float[3] = gx;
  gyo_union.Float[4] = gy;
  gyo_union.Float[5] = gz;
  motor_add_union.Float[0]=MOTOR1+MOTOR2+MOTOR3+MOTOR4;
// motor_add_union.Float[0] = 0;
  dt_union.Float[0] = dt;

  for (int i = 0; i < 24; i++)
  {
    buf_send = gyo_union.Byte;
  }
  for (int i = 24; i < 28; i++)
  {
    buf_send =  motor_add_union.Byte[i - 24];
  }
  for (int i = 28; i < 32; i++)
  {
    buf_send =  dt_union.Byte[i - 28];
  }
  
  esp.writeData(buf_send, 32); //write data (32 bytes)
  delay(1);
  esp.readData(buf_receive); //read data (16 bytes)

  for (int i = 0; i < 16; i++)
  {
    motor_union.Byte = buf_receive;
  }
  MOTOR1 = motor_union.Float[0];
  MOTOR2 = motor_union.Float[1];
  MOTOR3 = motor_union.Float[2];
  MOTOR4 = motor_union.Float[3];

  moto1 = (int) MOTOR1;
  moto2 = (int) MOTOR2;
  moto3 = (int) MOTOR3;
  moto4 = (int) MOTOR4;

  //Serial.println("data");
  //Serial.println(MOTOR1);
  //Serial.println(MOTOR2);
  //Serial.println(MOTOR3);
  //Serial.println(MOTOR4);
      if(moto1>=0&&moto1<=255)
        {pwmSet5(moto1);}
       else
        {pwmSet5(0);}
      if(moto2>=0&&moto2<=255)
        {pwmSet6(moto2);}
      else
        {pwmSet6(0);}
      if(moto3>=0&&moto3<=255)
        {pwmSet9(moto3);}
      else
        {pwmSet9(0);}
      if(moto4>=0&&moto4<=255)
        {pwmSet10(moto4);}
      else
        {pwmSet10(0);}
}[/mw_shl_code]

最后提一下,控制算法没在arduino里面,而在上位机电脑里面,用matlab/simulink模块搭建的,上位机只用算出四个电机的pwm,通过路由器发送给esp8266即可,同时,arduino还得把陀螺仪数据,pwm求和,采样时间,这三类数据一共32byte通过8266传回电脑。这样就形成了闭环控制系统,读者可以去我项目第二章查看相关原理图。







发表于 2019-4-25 16:29 | 显示全部楼层
我是新来的
发表于 2020-8-8 21:25 | 显示全部楼层
楼主不干了吗,一年多不更新了
 楼主| 发表于 2020-9-6 15:17 | 显示全部楼层
0526468 发表于 2020-8-8 21:25
楼主不干了吗,一年多不更新了

干完了 完美收工 哈哈 以后再开一贴
发表于 2021-4-11 13:25 | 显示全部楼层
半年了,没动静啊
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-1 04:56 , Processed in 0.077423 second(s), 16 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表