平衡车终于成功了

2023-05-16

说来惭愧2017-12-0118:13:27

并非原创,代码资料也是从论坛搜刮的。自己做了适配性的调整。

这个小车断断续续造了将近1个月!

 


  1 #include  "Wire.h"`
  2 #include <U8g2lib.h>
  3 #include <SPI.h>
  4 const uint8_t IMUAddress = 0x68; // AD0 is logic low on the PCB
  5 const uint16_t I2C_TIMEOUT = 100; // Used to check for errors in I2C communication
  6 
  7 uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, bool sendStop) {
  8   return i2cWrite(registerAddress, &data, 1, sendStop); // Returns 0 on success
  9 }
 10 
 11 uint8_t i2cWrite(uint8_t registerAddress, uint8_t *data, uint8_t length, bool sendStop) {
 12     Wire.beginTransmission(IMUAddress);
 13     Wire.write(registerAddress);
 14     Wire.write(data, length);
 15     uint8_t rcode = Wire.endTransmission(sendStop); // Returns 0 on success
 16     if (rcode) {
 17       Serial.print(F("i2cWrite failed: "));
 18       Serial.println(rcode);
 19     }
 20     return rcode; // See: http://arduino.cc/en/Reference/WireEndTransmission
 21 }
 22 
 23 uint8_t i2cRead(uint8_t registerAddress, uint8_t *data, uint8_t nbytes) {
 24     uint32_t timeOutTimer;
 25     Wire.beginTransmission(IMUAddress);
 26     Wire.write(registerAddress);
 27     uint8_t rcode = Wire.endTransmission(false); // Don't release the bus
 28     if (rcode) {
 29       Serial.print(F("i2cRead failed: "));
 30       Serial.println(rcode);
 31       return rcode; // See: http://arduino.cc/en/Reference/WireEndTransmission
 32     }
 33     Wire.requestFrom(IMUAddress, nbytes, (uint8_t)true); // Send a repeated start and then release the bus after reading
 34     for (uint8_t i = 0; i < nbytes; i++) {
 35       if (Wire.available())
 36         data[i] = Wire.read();
 37       else {
 38         timeOutTimer = micros();
 39         while (((micros() - timeOutTimer) < I2C_TIMEOUT) && !Wire.available());
 40         if (Wire.available())
 41           data[i] = Wire.read();
 42         else {
 43           Serial.println(F("i2cRead timeout"));
 44           return 5; // This error value is not already taken by endTransmission
 45         }
 46       }
 47     }
 48     return 0; // Success
 49 }
 50 
 51 /******************************************************/
 52 
 53 //2560 pin map  引脚定义好即可,然后改变一下PID的几个值(kp,kd,ksp,ksi)即可,剩下的全部都是固定的程序,
 54 //可能小车会有一点重心不在中点的现象,加一下角度值或者减一点即可
 55 //至于每个MPU6050的误差,自己调节一下即可,不是很难
 56 //调试时先将速度环的ksp,ksi=0,调到基本可以站起来,然后可能会出现倒,或者自动跑起来的时候加上速度环
 57 //这时就会很稳定的站起来,然后用小力气的手推不会倒。
 58 
 59 int ENA=10;
 60 int ENB=11;
 61 int IN1=4;
 62 int IN2=5;
 63 int IN3=6;
 64 int IN4=7;
 65 int MAS,MBS;
 66 /* IMU Data */
 67 double accX, accY, accZ;
 68 double gyroX, gyroY, gyroZ;
 69 int16_t tempRaw;
 70 double gyroXangle, gyroYangle; // Angle calculate using the gyro only
 71 double compAngleX, compAngleY; // Calculated angle using a complementary filter
 72 double kalAngleX, kalAngleY; // Calculated angle using a Kalman filter
 73 uint8_t i2cData[14]; // Buffer for I2C data
 74 uint32_t timer;
 75 unsigned long lastTime;      
 76 /***************************************/
 77 double P[2][2] = {{ 1, 0 },{ 0, 1 }};
 78 double Pdot[4] ={ 0,0,0,0};
 79 static const double Q_angle=0.001, Q_gyro=0.003, R_angle=0.5,dtt=0.005,C_0 = 1;
 80 double q_bias, angle_err, PCt_0, PCt_1, E, K_0, K_1, t_0, t_1;
 81 double angle,angle_dot,aaxdot,aax;
 82 double position_dot,position_dot_filter,positiono;
 83 /*-------------Encoder---------------*/
 84 
 85 #define LF 0
 86 #define RT 1
 87 
 88 //The balance PID
 89 float kp,kd,ksp,ksi;
 90 
 91 int Lduration,Rduration;
 92 boolean LcoderDir,RcoderDir;
 93 const byte encoder0pinA = 2;
 94 const byte encoder0pinB = 8;
 95 byte encoder0PinALast;
 96 const byte encoder1pinA = 3;
 97 const byte encoder1pinB = 9;
 98 byte encoder1PinALast;
 99 
100 int RotationCoder[2];
101 int turn_flag=0;
102 float move_flag=3.5;//
103 float right_need = 0, left_need = 0;;
104 
105 int pwm;
106 int pwm_R,pwm_L;
107 float range;
108 float range_error_all;
109 float wheel_speed;
110 float last_wheel;
111 float error_a=0;
112 U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 12, /* data=*/ 13, /* reset=*/ U8X8_PIN_NONE);   // 四角显示屏
113 void Kalman_Filter(double angle_m,double gyro_m)
114 {
115     angle+=(gyro_m-q_bias) * dtt;
116     Pdot[0]=Q_angle - P[0][1] - P[1][0];
117     Pdot[1]=- P[1][1];
118     Pdot[2]=- P[1][1];
119     Pdot[3]=Q_gyro;
120     P[0][0] += Pdot[0] * dtt;
121     P[0][1] += Pdot[1] * dtt;
122     P[1][0] += Pdot[2] * dtt;
123     P[1][1] += Pdot[3] * dtt;
124     angle_err = angle_m - angle;
125     PCt_0 = C_0 * P[0][0];
126     PCt_1 = C_0 * P[1][0];
127     E = R_angle + C_0 * PCt_0;
128     K_0 = PCt_0 / E;
129     K_1 = PCt_1 / E;
130     t_0 = PCt_0;
131     t_1 = C_0 * P[0][1];
132     P[0][0] -= K_0 * t_0;
133     P[0][1] -= K_0 * t_1;
134     P[1][0] -= K_1 * t_0;
135     P[1][1] -= K_1 * t_1;
136     angle+= K_0 * angle_err;
137     q_bias += K_1 * angle_err;
138     angle_dot = gyro_m-q_bias;//也许应该用last_angle-angle
139 }
140  
141 void setup() {
142     Wire.begin();
143     u8g2.begin();   //选择U8G2模式,或者U8X8模式
144     Serial.begin(9600);
145     pinMode(IN1, OUTPUT);
146     pinMode(IN2, OUTPUT);
147     pinMode(IN3, OUTPUT);
148     pinMode(IN4, OUTPUT);  
149     pinMode(ENA, OUTPUT);
150     pinMode(ENB, OUTPUT);
151     TWBR = ((F_CPU / 400000L) - 16) / 2; // Set I2C frequency to 400kHz
152  
153     i2cData[0] = 7; // Set the sample rate to 1000Hz - 8kHz/(7+1) = 1000Hz
154     i2cData[1] = 0x00; // Disable FSYNC and set 260 Hz Acc filtering, 256 Hz Gyro filtering, 8 KHz sampling
155     i2cData[2] = 0x00; // Set Gyro Full Scale Range to ±250deg/s
156     i2cData[3] = 0x00; // Set Accelerometer Full Scale Range to ±2g
157     while (i2cWrite(0x19, i2cData, 4, false)); // Write to all four registers at once
158     while (i2cWrite(0x6B, 0x01, true)); // PLL with X axis gyroscope reference and disable sleep mode
159  
160     while (i2cRead(0x75, i2cData, 1));
161     if (i2cData[0] != 0x68) { // Read "WHO_AM_I" register
162         Serial.print(F("Error reading sensor"));
163         while (1);
164     }
165 
166     delay(20); // Wait for sensor to stabilize
167 
168     while (i2cRead(0x3B, i2cData, 6));
169     accX = (i2cData[0] << 8) | i2cData[1];
170     accY = (i2cData[2] << 8) | i2cData[3];
171     accZ = (i2cData[4] << 8) | i2cData[5];
172 
173 
174     double roll  = atan2(accX, accZ) * RAD_TO_DEG;
175     EnCoderInit();
176     timer = micros();
177 
178       //The balance PID
179     kp= 42;//42;//24.80;43
180     kd= 2.0;//1.9;//9.66;1.4
181     ksp=8.5;//8.5;//4.14;
182     ksi=2.1;//2.1;//0.99; 0.550
183      u8g2.firstPage();
184   do {
185      u8g2.setFont(u8g2_font_ncenB14_tr); //设置字体/u8g2_font_5x7_tr
186      u8g2.setCursor(0, 15);    //设置光标处
187      u8g2.print("MiniBlack");  //输出内容
188      //u8g2.setCursor(0,30);    //设置光标处
189      //u8g2.print("T:");  //输出内容
190   } while ( u8g2.nextPage() );
191 }
192 
193 void EnCoderInit()
194 {
195     pinMode(8,INPUT);
196     pinMode(9,INPUT);
197     attachInterrupt(LF, LwheelSpeed, RISING);
198     attachInterrupt(RT, RwheelSpeed, RISING);
199 }
200 
201 void pwm_calculate()
202 {
203     unsigned long  now = millis();       // 当前时间(ms)
204     int Time = now - lastTime;
205     int range_error;
206     range += (Lduration + Rduration) * 0.5;
207     range *= 0.9;
208     range_error = Lduration - Rduration;
209     range_error_all += range_error;
210     
211     wheel_speed = range - last_wheel;   
212     //wheel_speed = constrain(wheel_speed,-800,800);
213     //Serial.println(wheel_speed);
214     last_wheel = range;  
215     pwm = (angle + 0.825) * kp + angle_dot * kd + range * ksp + wheel_speed * ksi;     
216     if(pwm > 255)pwm = 255;
217     if(pwm < -255)pwm = -255;
218     
219     if(turn_flag == 0)
220     {
221          pwm_R = pwm + range_error_all;
222          pwm_L = pwm - range_error_all;
223     }
224     else if(turn_flag == 1)     //左转
225     {
226         pwm_R = pwm ;  //Direction PID control
227         pwm_L = pwm + left_need * 68;
228         range_error_all = 0;     //clean
229     }
230     else if(turn_flag == 2)
231     {
232         pwm_R = pwm + right_need * 68;  //Direction PID control
233         pwm_L = pwm ;
234         range_error_all = 0;     //clean
235     }
236        
237        Lduration = 0;//clean
238        Rduration = 0;
239        lastTime = now;
240 }
241 
242 void PWMD()
243 {  
244       if(pwm>0)
245       {
246           digitalWrite(IN1, HIGH);
247           digitalWrite(IN2, LOW);
248           digitalWrite(IN3, LOW);
249           digitalWrite(IN4, HIGH);    
250       }
251       else if(pwm<0)
252       {
253           digitalWrite(IN1, LOW);
254           digitalWrite(IN2, HIGH);
255           digitalWrite(IN3, HIGH);
256           digitalWrite(IN4, LOW);
257       }
258       int PWMr = abs(pwm);
259       int PWMl = abs(pwm);
260     
261       analogWrite(ENB, max(PWMl,51)); //PWM调速a==0-255  51
262       analogWrite(ENA, max(PWMr,54)); //PWM调速a==0-255  54
263       
264 }
265 
266 void LwheelSpeed()
267 {
268       if(digitalRead(encoder0pinB))
269         Lduration++;
270       else Lduration--;
271 }
272 
273 
274 void RwheelSpeed()
275 {
276       if(digitalRead(encoder1pinB))
277         Rduration--;
278       else Rduration++;
279 }
280 
281 void control()
282 {
283     if(Serial.available()){
284       int val;
285       val=Serial.read();
286       switch(val){
287         case 'w':
288           if(move_flag<5)move_flag += 0.5;
289           else  move_flag = 0;
290           break;
291         case 's':
292           if(move_flag<5)move_flag -= 0.5;
293           else  move_flag = 0;
294          Serial.println("back");
295           break;
296         case 'a':
297           turn_flag = 1;
298           left_need = 0.6;
299           Serial.println("zuo");
300           break;
301         case 'd':
302           turn_flag = 2;
303           right_need = 0.6;
304           Serial.println("you");
305           break;
306         case 't':
307           move_flag=0;
308           turn_flag=0;
309           right_need = left_need = 0;
310           Serial.println("stop");
311           break;
312         default:
313           break;
314           }
315       }
316 }
317 
318 void loop()
319 {
320 
321     control();
322     while (i2cRead(0x3B, i2cData, 14));
323     accX = ((i2cData[0] << 8) | i2cData[1]);
324     //accY = ((i2cData[2] << 8) | i2cData[3]);
325     accZ = ((i2cData[4] << 8) | i2cData[5]);
326     //gyroX = (i2cData[8] << 8) | i2cData[9];
327     gyroY = (i2cData[10] << 8) | i2cData[11];
328     //gyroZ = (i2cData[12] << 8) | i2cData[13];
329 
330     double dt = (double)(micros() - timer) / 1000000; // Calculate delta time
331     timer = micros();
332  
333     double roll  = atan2(accX, accZ) * RAD_TO_DEG - move_flag;
334 
335 
336     double gyroXrate = gyroX / 131.0; // Convert to deg/s
337     double gyroYrate = -gyroY / 131.0; // Convert to deg/s
338 
339     //gyroXangle += gyroXrate * dt; // Calculate gyro angle without any filter
340     //gyroYangle += gyroYrate * dt;
341 
342     Kalman_Filter(roll,gyroYrate);   
343     if(abs(angle)<35){
344         //Serial.println(angle); 
345        ////
346        
347         //  
348         pwm_calculate();
349         PWMD();
350     }
351     else{
352         analogWrite(ENB, 0); //PWM调速a==0-255
353         analogWrite(ENA, 0); //PWM调速a==0-255
354     }  
355     delay(2);
356 }  

代码有很多都不理解,资料是从论坛大神那里查到的。

转载于:https://www.cnblogs.com/pengwenzheng/p/7943931.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

平衡车终于成功了 的相关文章

随机推荐

  • 【免费内网穿透】公网环境下,Windows系统远程桌面控制树莓派

    系列文章 免费内网穿透 公网环境下 xff0c Windows系统远程桌面控制树莓派 无需公网IP 为远程桌面树莓派配置固定的公网TCP端口地址 远程桌面控制树莓派 xff0c 我们可以用xrdp协议来实现 xff0c 它内部使用的是win
  • 如何两个月刷400道leetcode

    前言 随着互联网寒潮的到来 越来越多的互联网公司提高了面试的难度 xff0c 其中之一就是加大了面试当中手撕算法题的比例 这里说的算法题不是深度学习 xff0c 机器学习这类的算法 xff0c 而是排序 xff0c 广度优先 xff0c 动
  • DE1-SOC开发板使用学习

    1 Yocto build utility 工具是什么 xff1f Linux Console with framebuffer是什么 xff1f 2 文档里面有几个Linux发布版本的 xff0c 分别是ubuntu和LXDE版本 LXD
  • 在shell脚本的第一行中,必须写#!/bin/bash吗?

    可以不写 执行时手工执行 bin sh xxxx sh 效果是一样的 bin sh 表示本脚本由 bin 路径的sh程序来解释 跟命令行下 xff03 通常用作注释 xff0c 但是 xff03 xff01 放在一起就标志着这是一个shel
  • android架构中最底层是什么层,Android体系架构

    Android开发入门教程一丶了解手机通讯技术发展史1 第一代通讯技术 第一代通讯技术 简单来说就是大哥大 其原理是通过 模拟信号进行传输 1 说话的时候产生声波震动 2 声波震动会让大哥大中的铜片产生震动 3 铜片震动会让其电容产生变化
  • linux桌面lxde 安装_Archlinux LXDE 桌面环境安装配置

    安装 LXDE LXDE 是模块化的 你可以从下面的列表中挑选你需要的包 xff0c 所有的包都可以通过pacman下载安装得到 他们大多数都在extra和community仓库中 如果你要安装像 LXAppearance 和 LXNM 这
  • PX4 FMU启动流程 2. 二、 nsh_initscript

    PX4 FMU启动流程 2 二 nsh initscript PX4 FMU启动流程 2 二 nsh initscript 转载请注明出处 2014 11 27 冷月追风
  • Eigen库

    MatrixXd表示任意size的矩阵 xff0c 元素类型为double VectorXd表示任意size的向量 xff0c 元素类型为double 创建3 1的向量v xff0c 并赋值为1 2 3 VectorXd v 3 v lt
  • 亲爱的热爱的百度云全集资源

    网盘链接 转载于 https www cnblogs com awesome share p 11234341 html
  • 解决Docker容器 iptables问题---docker: Error response from daemon: driver failed programming external conne...

    一 问题现象 最近在研究Docker容器日志管理时 xff0c 启动容器出现iptables相关报错 xff0c 具体问题如下 运行容器 root 64 node 11 docker run d p 24224 24224 p 24224
  • 内网穿透远程查看内网监控摄像头

    在现代社会中 xff0c 大家总是奔波于家和公司之间 大部分时间用于工作中 xff0c 也就很难及时知晓家中的动态情况 xff0c 对于家中有老人 小孩或宠物的 xff08 甚至对居住环境安全不放心的 xff09 xff0c 这已然是个棘手
  • 2022/6/15 docker安装与项目部署(入门教程)

    目录 一丶docker简介 二丶Docker私库简介 xff08 Dockerhub xff09 三丶Docker优势 四丶docker安装 4 1 使用官方安装脚本自动安装 xff08 仅适用于公网环境 xff09 4 2 手动安装 4
  • vim实现批量注释和批量删除注释

    批量注释 1 进入文档 xff0c vim test txt 后 xff0c 按住ctrl 43 v进入VISUAL BLOCK模式 xff0c 上下选择需要注释的行 2 按大写键 xff0c 再按i xff0c 或者直接按shift 43
  • 20191003

    A 把字典树建出来 xff0c 问题就转化成要选择m个节点 xff0c 使得它们能覆盖所有叶子节点 xff0c 且不存在两个节点使得一个是另一个的祖先 于是可以在字典树上跑树形dp xff0c 复杂度 O n 2m 或 O nm 2 xff
  • 20191004

    A 解 1 我们发现只需要关心处于结果字符串前 k 位的字符 因此考虑从后往前处理 对于一个询问区间 xff0c 我们暴力连边 xff0c 用并查集维护 xff0c x 的父亲等于 y 相当于位于 x 的字符是从位于 y 的字符处复制过来的
  • git 如何解决 (master|MERGING)

    git 如何解决 master MERGING git reset hard head 回退版本信息 git pull origin master 转载于 https www cnblogs com 651434092qq p 110188
  • linux ping 指定次数

    ping 192 168 0 1 c4 转载于 https www cnblogs com sea stream p 10345600 html
  • java 解决 java.lang.Integer cannot be cast to java.lang.String

    1 在执行代码打印map的value时 xff0c 提示错误java lang Integer cannot be cast to java lang String xff0c 这个错误很明显是类型转换错误 查看表字段的数据 解决方案 1
  • DBoW2应用

    图像对应的bag of words向量 v t 假设词典总共有 W 个单词 xff0c 那么每一幅图像能够用一个 W 维的向量表示 xff08 t 1 t 2 t 3 t W xff09 其中 t i 61 frac n id n nd l
  • 平衡车终于成功了

    说来惭愧2017 12 0118 13 27 并非原创 xff0c 代码资料也是从论坛搜刮的 自己做了适配性的调整 这个小车断断续续造了将近1个月 xff01 1 include 34 Wire h 34 96 2 include lt U