查看: 1046|回复: 0

[项目] 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里面的,从机模式。注意由于这里的代码显示有问题,大家要仔细检查

kittenblock中小学创客名师推荐的图形化编程软件

#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]); 
     }               
}


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



kittenblock中小学创客名师推荐的图形化编程软件


#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);}
}


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







您需要登录后才可以回帖 登录 | 立即注册  

本版积分规则

热门推荐

学习记录2,Blinker读取温湿度
学习记录2,Blinker读取温
开关现在是使用得很6了,准备进行下一步,读取数据。 找了下官方的例程,发现用的是w
学生智能打卡系统(接入blinker)
学生智能打卡系统(接入bl
【项目名称】学生智能打卡系统(接入blinker) 一.感谢各位大佬 首先感谢社区的管理员
关于红外控制空调的模块选型
关于红外控制空调的模块选
想问问这中模块能支持arduino吗
LCD1602只亮 不显示
LCD1602只亮 不显示
#include // initialize the library by associating any needed LCD interface pin
18脚的8x8LED点阵如何使用??
18脚的8x8LED点阵如何使用
本帖最后由 Creeper666 于 2018-8-14 12:24 编辑 这个点阵模块上面一排有12个脚,
Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
快速回复 返回顶部 返回列表