Mini四轴自动控制(五) ESP8266-12F SPI通信,电机PWM频率自定义
本帖最后由 zxldwlsj 于 2018-12-1 08:35 编辑好久没更新了,今天给大家带来了满满的干货:
[*]Arduino Leonardo和ESP8266 SPI接口通信;
[*]四个电机PWM频率自定义设置。因为用analogWrite频率会很低,对空心杯不合适(这里涉及多个定时器的设置,以后会给出详细文档介绍);
[*]如何将浮点数据和字节数据相互转化。因为spi是一个字节一个字节传数据的,而我们的数据又是小数,所以为了传输数据,要将小数转为字节,同时接受到字节数据,我们还得转为小数用于我们的控制器设计。
废话不多说,直接上代码。代码我就不做具体解释了,萌新看不懂的可以留言,我会回复的。定时器设置部分(带pwm字眼的)可以先不看,等我下回分解。
下面这是写到ESP8266里面的,从机模式。注意由于这里的代码显示有问题,大家要仔细检查#include <ESP8266WiFi.h>
#include "SPISlave.h"
uint8_t buf_RecFromWiFi = {0};
uint8_t buf_SendToWiFi = {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 = 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 =buf_send;
}
});
for(int j=0;j<32;j++)
{
client.write(buf_SendToWiFi);
}
}
下面写到arduino开发板里面,注意由于这里的代码显示有问题,大家要仔细检查
#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 = {0};
uint8_t buf_send = {0};
union Float6ToByte24
{
float Float;
uint8_t Byte;
};
union Float4ToByte16
{
float Float;
uint8_t Byte;
};
union Float1ToByte4
{
float Float;
uint8_t Byte;
};
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);
}
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 = ax;
gyo_union.Float = ay;
gyo_union.Float = az;
gyo_union.Float = gx;
gyo_union.Float = gy;
gyo_union.Float = gz;
motor_add_union.Float=MOTOR1+MOTOR2+MOTOR3+MOTOR4;
// motor_add_union.Float = 0;
dt_union.Float = 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;
}
for (int i = 28; i < 32; i++)
{
buf_send =dt_union.Byte;
}
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;
MOTOR2 = motor_union.Float;
MOTOR3 = motor_union.Float;
MOTOR4 = motor_union.Float;
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传回电脑。这样就形成了闭环控制系统,读者可以去我项目第二章查看相关原理图。
我是新来的 楼主不干了吗,一年多不更新了 0526468 发表于 2020-8-8 21:25
楼主不干了吗,一年多不更新了
干完了 完美收工 哈哈 以后再开一贴 楼主厉害 半年了,没动静啊
页:
[1]