久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 7029|回復(fù): 3
打印 上一主題 下一主題
收起左側(cè)

Arduino+MPU6050平衡小車 含源碼 圖片

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:670179 發(fā)表于 2019-12-21 23:31 | 只看該作者 |只看大圖 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
采用arduino單片機(jī),MPU6050模塊,L298n電機(jī)驅(qū)動(dòng)模塊,HC06藍(lán)牙模塊進(jìn)行參數(shù)調(diào)節(jié),
一個(gè)KEY鍵連IO3,用于保存當(dāng)前參數(shù)與讀取參數(shù)。
代碼下載后可直接使用,可根據(jù)你機(jī)器工況調(diào)整PID即可。



單片機(jī)源程序如下:
  1. /****************************************************************************
  2. Minibalance For Arduino
  3. ****************************************************************************/
  4. #include <DATASCOPE.h>      //這是PC端上位機(jī)的庫(kù)文件
  5. #include <PinChangeInt.h>    //外部中斷
  6. #include <MsTimer2.h>        //定時(shí)中斷
  7. #include <KalmanFilter.h>    //卡爾曼濾波
  8. #include "I2Cdev.h"        
  9. #include "MPU6050_6Axis_MotionApps20.h"//MPU6050庫(kù)文件
  10. #include "Wire.h"  
  11. #include <EEPROM.h>         
  12. MPU6050 Mpu6050; //實(shí)例化一個(gè) MPU6050 對(duì)象,對(duì)象名稱為 Mpu6050
  13. DATASCOPE data;//實(shí)例化一個(gè) 上位機(jī) 對(duì)象,對(duì)象名稱為 data
  14. KalmanFilter KalFilter;//實(shí)例化一個(gè)卡爾曼濾波器對(duì)象,對(duì)象名稱為 KalFilter
  15. int16_t ax, ay, az, gx, gy, gz;  //MPU6050的三軸加速度和三軸陀螺儀數(shù)據(jù)
  16. #define KEY 3     //按鍵引腳
  17. #define IN1 11   //TB6612FNG驅(qū)動(dòng)模塊控制信號(hào) 共6個(gè)
  18. #define IN2 12
  19. #define IN3 7
  20. #define IN4 6
  21. #define PWMA 10
  22. #define PWMB 9
  23. #define ENCODER_L 2  //編碼器采集引腳 每路2個(gè) 共4個(gè)
  24. #define DIRECTION_L 5
  25. #define ENCODER_R 4
  26. #define DIRECTION_R 8
  27. #define ZHONGZHI -4.2//小車的機(jī)械中值  DIFFERENCE
  28. #define DIFFERENCE 2
  29. int Balance_Pwm, Velocity_Pwm, Turn_Pwm;   //直立 速度 轉(zhuǎn)向環(huán)的PWM
  30. int Motor1, Motor2;      //電機(jī)疊加之后的PWM
  31. float Battery_Voltage;   //電池電壓 單位是V
  32. volatile long Velocity_L, Velocity_R = 0;   //左右輪編碼器數(shù)據(jù)
  33. int Velocity_Left, Velocity_Right = 0;     //左右輪速度
  34. int Flag_Qian, Flag_Hou, Flag_Left, Flag_Right; //遙控相關(guān)變量
  35. int Angle, Show_Data,PID_Send;  //用于顯示的角度和臨時(shí)變量
  36. unsigned char Flag_Stop = 1,Send_Count,Flash_Send;  //停止標(biāo)志位和上位機(jī)相關(guān)變量
  37. float Balance_Kp=15,Balance_Kd=0.4,Velocity_Kp=2,Velocity_Ki=0.01;
  38. //***************下面是卡爾曼濾波相關(guān)變量***************//
  39. float K1 = 0.05; // 對(duì)加速度計(jì)取值的權(quán)重
  40. float Q_angle = 0.001, Q_gyro = 0.005;
  41. float R_angle = 0.5 , C_0 = 1;
  42. float dt = 0.005; //注意:dt的取值為濾波器采樣時(shí)間 5ms
  43. int addr = 0;
  44. /**************************************************************************
  45. 函數(shù)功能:檢測(cè)小車是否被拿起
  46. 入口參數(shù):Z軸加速度 平衡傾角 左輪編碼器 右輪編碼器
  47. 返回  值:0:無(wú)事件 1:小車被拿起
  48. **************************************************************************/
  49. int Pick_Up(float Acceleration, float Angle, int encoder_left, int encoder_right){
  50.   static unsigned int flag, count0, count1, count2;
  51.   if (flag == 0) //第一步
  52.   {
  53.     if (abs(encoder_left) + abs(encoder_right) < 15)         count0++;  //條件1,小車接近靜止
  54.     else       count0 = 0;
  55.     if (count0 > 10)      flag = 1, count0 = 0;
  56.   }
  57.   if (flag == 1) //進(jìn)入第二步
  58.   {
  59.     if (++count1 > 400)       count1 = 0, flag = 0;                         //超時(shí)不再等待2000ms
  60.     if (Acceleration > 27000 && (Angle > (-14 + ZHONGZHI)) && (Angle < (14 + ZHONGZHI)))  flag = 2; //條件2,小車是在0度附近被拿起
  61.   }
  62.   if (flag == 2)  //第三步
  63.   {
  64.     if (++count2 > 200)       count2 = 0, flag = 0;       //超時(shí)不再等待1000ms
  65.     if (abs(encoder_left + encoder_right) > 300)           //條件3,小車的輪胎因?yàn)檎答佭_(dá)到最大的轉(zhuǎn)速      
  66.      {
  67.         flag = 0;  return 1;
  68.       }                                          
  69.   }
  70.   return 0;
  71. }
  72. /**************************************************************************
  73. 函數(shù)功能:檢測(cè)小車是否被放下 作者:平衡小車之家
  74. 入口參數(shù): 平衡傾角 左輪編碼器 右輪編碼器
  75. 返回  值:0:無(wú)事件 1:小車放置并啟動(dòng)
  76. **************************************************************************/
  77. int Put_Down(float Angle, int encoder_left, int encoder_right){
  78.   static u16 flag, count;
  79.   if (Flag_Stop == 0)         return 0;                   //防止誤檢
  80.   if (flag == 0)
  81.   {
  82.     if (Angle > (-10 + ZHONGZHI) && Angle < (10 + ZHONGZHI) && encoder_left == 0 && encoder_right == 0)      flag = 1; //條件1,小車是在0度附近的
  83.   }
  84.   if (flag == 1)
  85.   {
  86.     if (++count > 100)       count = 0, flag = 0;  //超時(shí)不再等待 500ms
  87.     if (encoder_left > 12 && encoder_right > 12 && encoder_left < 80 && encoder_right < 80) //條件2,小車的輪胎在未上電的時(shí)候被人為轉(zhuǎn)動(dòng)
  88.     {
  89.       flag = 0;
  90.       flag = 0;
  91.       return 1;    //檢測(cè)到小車被放下
  92.     }
  93.   }
  94.   return 0;
  95. }
  96. /**************************************************************************
  97. 函數(shù)功能:異常關(guān)閉電機(jī) 作者:平衡小車之家
  98. 入口參數(shù):傾角和電池電壓
  99. 返回  值:1:異常  0:正常
  100. **************************************************************************/
  101. unsigned char Turn_Off(float angle, float voltage)
  102. {
  103.   unsigned char temp;
  104.   if (angle < -40 || angle > 40 || 1 == Flag_Stop || voltage < 11.1) //電池電壓低于11.1V關(guān)閉電機(jī) //===傾角大于40度關(guān)閉電機(jī)//===Flag_Stop置1關(guān)閉電機(jī)
  105.   {                                                                        
  106.     temp = 1;                                          
  107.     analogWrite(PWMA, 0);  //PWM輸出為0
  108.     analogWrite(PWMB, 0); //PWM輸出為0
  109.   }
  110.   else    temp = 0;   //不存在異常,返回0
  111.   return temp;
  112. }
  113. /**************************************************************************
  114. 函數(shù)功能:虛擬示波器往上位機(jī)發(fā)送數(shù)據(jù) 作者:平衡小車之家
  115. 入口參數(shù):無(wú)
  116. 返回  值:無(wú)
  117. **************************************************************************/
  118. void DataScope(void)
  119. {
  120.   int i;
  121.   data.DataScope_Get_Channel_Data(Angle, 1);  //顯示第一個(gè)數(shù)據(jù),角度
  122.   data.DataScope_Get_Channel_Data(Velocity_Left, 2);//顯示第二個(gè)數(shù)據(jù),左輪速度  也就是每40ms輸出的脈沖計(jì)數(shù)
  123.   data.DataScope_Get_Channel_Data(Velocity_Right, 3);//顯示第三個(gè)數(shù)據(jù),右輪速度 也就是每40ms輸出的脈沖計(jì)數(shù)
  124.   data.DataScope_Get_Channel_Data(Battery_Voltage, 4);//顯示第四個(gè)數(shù)據(jù),電池電壓,單位V
  125.   Send_Count = data.DataScope_Data_Generate(4);
  126.   for ( i = 0 ; i < Send_Count; i++)
  127.   {
  128.     Serial.write(DataScope_OutPut_Buffer[i]);  
  129.   }
  130.   delay(50);  //上位機(jī)必須嚴(yán)格控制發(fā)送時(shí)序
  131. }
  132. /**************************************************************************
  133. 函數(shù)功能:按鍵掃描  作者:平衡小車之家
  134. 入口參數(shù):無(wú)
  135. 返回  值:按鍵狀態(tài),1:?jiǎn)螕羰录?:無(wú)事件。
  136. **************************************************************************/
  137. unsigned char My_click(void){
  138.   static unsigned char flag_key = 1; //按鍵按松開標(biāo)志
  139.   unsigned char Key;   
  140.   Key = digitalRead(KEY);   //讀取按鍵狀態(tài)
  141.   if (flag_key && Key == 0) //如果發(fā)生單擊事件
  142.   {
  143.     flag_key = 0;
  144.     return 1;            // 單擊事件
  145.   }
  146.   else if (1 == Key)     flag_key = 1;
  147.   return 0;//無(wú)按鍵按下
  148. }
  149. /**************************************************************************
  150. 函數(shù)功能:直立PD控制  作者:平衡小車之家
  151. 入口參數(shù):角度、角速度
  152. 返回  值:直立控制PWM
  153. **************************************************************************/
  154. int balance(float Angle, float Gyro)
  155. {
  156.   float Bias;
  157.   int balance;
  158.   Bias = Angle -  ZHONGZHI;   //===求出平衡的角度中值 和機(jī)械相關(guān)
  159.   balance = Balance_Kp * Bias + Gyro * Balance_Kd; //===計(jì)算平衡控制的電機(jī)PWM  PD控制   kp是P系數(shù) kd是D系數(shù)
  160.   return balance;
  161. }
  162. /**************************************************************************
  163. 函數(shù)功能:速度PI控制 作者:平衡小車之家
  164. 入口參數(shù):左輪編碼器、右輪編碼器
  165. 返回  值:速度控制PWM
  166. **************************************************************************/
  167. int velocity(int encoder_left, int encoder_right)
  168. {
  169.   static float Velocity, Encoder_Least, Encoder, Movement;
  170.   static float Encoder_Integral, Target_Velocity;
  171.   float kp = 2, ki = kp / 200;    //PI參數(shù)
  172.   if       ( Flag_Qian == 1)Movement = 600;
  173.   else   if ( Flag_Hou == 1)Movement = -600;
  174.   else    //這里是停止的時(shí)候反轉(zhuǎn),讓小車盡快停下來(lái)
  175.   {
  176.     Movement = 0;
  177.     if (Encoder_Integral > 300)   Encoder_Integral -= 200;
  178.     if (Encoder_Integral < -300)  Encoder_Integral += 200;
  179.   }
  180.   //=============速度PI控制器=======================//
  181.   Encoder_Least = (encoder_left + encoder_right) - 0;               //===獲取最新速度偏差==測(cè)量速度(左右編碼器之和)-目標(biāo)速度(此處為零)
  182.   Encoder *= 0.7;                                                   //===一階低通濾波器
  183.   Encoder += Encoder_Least * 0.3;                                   //===一階低通濾波器
  184.   Encoder_Integral += Encoder;                                      //===積分出位移 積分時(shí)間:40ms
  185.   Encoder_Integral = Encoder_Integral - Movement;                   //===接收遙控器數(shù)據(jù),控制前進(jìn)后退
  186.   if (Encoder_Integral > 21000)    Encoder_Integral = 21000;        //===積分限幅
  187.   if (Encoder_Integral < -21000) Encoder_Integral = -21000;         //===積分限幅
  188.   Velocity = Encoder * Velocity_Kp + Encoder_Integral * Velocity_Ki;                  //===速度控制
  189.   if (Turn_Off(KalFilter.angle, Battery_Voltage) == 1 || Flag_Stop == 1)    Encoder_Integral = 0;//小車停止的時(shí)候積分清零
  190.   return Velocity;
  191. }
  192. /**************************************************************************
  193. 函數(shù)功能:轉(zhuǎn)向控制 作者:平衡小車之家
  194. 入口參數(shù):Z軸陀螺儀
  195. 返回  值:轉(zhuǎn)向控制PWM
  196. **************************************************************************/
  197. int turn(float gyro)//轉(zhuǎn)向控制
  198. {
  199.   static float Turn_Target, Turn, Turn_Convert = 3;
  200.   float Turn_Amplitude = 80, Kp = 2, Kd = 0.001;  //PD參數(shù)
  201.   if (1 == Flag_Left)             Turn_Target += Turn_Convert;  //根據(jù)遙控指令改變轉(zhuǎn)向偏差
  202.   else if (1 == Flag_Right)       Turn_Target -= Turn_Convert;//根據(jù)遙控指令改變轉(zhuǎn)向偏差
  203.   else Turn_Target = 0;
  204.   if (Turn_Target > Turn_Amplitude)  Turn_Target = Turn_Amplitude; //===轉(zhuǎn)向速度限幅
  205.   if (Turn_Target < -Turn_Amplitude) Turn_Target = -Turn_Amplitude;
  206.   Turn = -Turn_Target * Kp + gyro * Kd;         //===結(jié)合Z軸陀螺儀進(jìn)行PD控制
  207.   return Turn;
  208. }
  209. /**************************************************************************
  210. 函數(shù)功能:賦值給PWM寄存器 作者:平衡小車之家
  211. 入口參數(shù):左輪PWM、右輪PWM
  212. 返回  值:無(wú)
  213. **************************************************************************/
  214. void Set_Pwm(int moto1, int moto2)
  215. {
  216.   if (moto1 > 0)     digitalWrite(IN1, HIGH),      digitalWrite(IN2, LOW);  //TB6612的電平控制
  217.   else             digitalWrite(IN1, LOW),       digitalWrite(IN2, HIGH); //TB6612的電平控制
  218.   analogWrite(PWMA, abs(moto1)); //賦值給PWM寄存器
  219.   if (moto2 < 0) digitalWrite(IN3, HIGH),     digitalWrite(IN4, LOW); //TB6612的電平控制
  220.   else        digitalWrite(IN3, LOW),      digitalWrite(IN4, HIGH); //TB6612的電平控制
  221.   analogWrite(PWMB, abs(moto2));//賦值給PWM寄存器
  222. }
  223. /**************************************************************************
  224. 函數(shù)功能:限制PWM賦值  作者:平衡小車之家
  225. 入口參數(shù):無(wú)
  226. 返回  值:無(wú)
  227. **************************************************************************/
  228. void Xianfu_Pwm(void)
  229. {
  230.   int Amplitude = 250;  //===PWM滿幅是255 限制在250
  231.   if(Flag_Qian==1)  Motor2-=DIFFERENCE;  //DIFFERENCE是一個(gè)衡量平衡小車電機(jī)和機(jī)械安裝差異的一個(gè)變量。直接作用于輸出,讓小車具有更好的一致性。
  232.   if(Flag_Hou==1)   Motor2-=DIFFERENCE-2;
  233.   if (Motor1 < -Amplitude) Motor1 = -Amplitude;
  234.   if (Motor1 > Amplitude)  Motor1 = Amplitude;
  235.   if (Motor2 < -Amplitude) Motor2 = -Amplitude;
  236.   if (Motor2 > Amplitude)  Motor2 = Amplitude;
  237. }
  238. /**************************************************************************
  239. 函數(shù)功能:5ms控制函數(shù) 核心代碼 作者:平衡小車之家
  240. 入口參數(shù):無(wú)
  241. 返回  值:無(wú)
  242. **************************************************************************/
  243. void control()
  244. {
  245.   static int Velocity_Count, Turn_Count, Encoder_Count;
  246.   static float Voltage_All,Voltage_Count;
  247.   int Temp;
  248.   sei();//全局中斷開啟
  249.   Mpu6050.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);  //獲取MPU6050陀螺儀和加速度計(jì)的數(shù)據(jù)
  250.   KalFilter.Angletest(ax, ay, az, gx, gy, gz, dt, Q_angle, Q_gyro, R_angle, C_0, K1);          //通過(guò)卡爾曼濾波獲取角度
  251.   Angle = KalFilter.angle;//Angle是一個(gè)用于顯示的整形變量
  252.   Balance_Pwm = balance(KalFilter.angle, KalFilter.Gyro_x);//直立PD控制 控制周期5ms
  253.   if (++Velocity_Count >= 8) //速度控制,控制周期40ms
  254.   {
  255.     Velocity_Left = Velocity_L;    Velocity_L = 0;  //讀取左輪編碼器數(shù)據(jù),并清零,這就是通過(guò)M法測(cè)速(單位時(shí)間內(nèi)的脈沖數(shù))得到速度。
  256.     Velocity_Right = Velocity_R;    Velocity_R = 0; //讀取右輪編碼器數(shù)據(jù),并清零
  257.     Velocity_Pwm = velocity(Velocity_Left, Velocity_Right);//速度PI控制,控制周期40ms
  258.     Velocity_Count = 0;
  259.   }
  260.   if (++Turn_Count >= 4)//轉(zhuǎn)向控制,控制周期20ms
  261.   {
  262.     Turn_Pwm = turn(gz);
  263.     Turn_Count = 0;
  264.   }
  265.   Motor1 = Balance_Pwm - Velocity_Pwm + Turn_Pwm;  //直立速度轉(zhuǎn)向環(huán)的疊加
  266.   Motor2 = Balance_Pwm - Velocity_Pwm - Turn_Pwm; //直立速度轉(zhuǎn)向環(huán)的疊加
  267.   Xianfu_Pwm();//限幅
  268.   if (Pick_Up(az, KalFilter.angle, Velocity_Left, Velocity_Right))   Flag_Stop = 1;  //===如果被拿起就關(guān)閉電機(jī)//===檢查是否小車被那起
  269.   if (Put_Down(KalFilter.angle, Velocity_Left, Velocity_Right))      Flag_Stop = 0;              //===檢查是否小車被放下
  270.   if (Turn_Off(KalFilter.angle, Battery_Voltage) == 0)        Set_Pwm(Motor1, Motor2);//如果不存在異常,賦值給PWM寄存器控制電機(jī)
  271.   if (My_click()) Flag_Stop = !Flag_Stop;   //中斷剩余的時(shí)間掃描一下按鍵狀態(tài)
  272.   Temp = analogRead(0);  //采集一下電池電壓
  273.   
  274.   Voltage_Count++;       //平均值計(jì)數(shù)器
  275.   Voltage_All+=Temp;     //多次采樣累積
  276.   if(Voltage_Count==200) Battery_Voltage=11.1,Voltage_All=0,Voltage_Count=0;//求平均值  =Voltage_All*0.05371/200
  277. }
  278. /**************************************************************************
  279. 函數(shù)功能:初始化 相當(dāng)于STM32里面的Main函數(shù) 作者:平衡小車之家
  280. 入口參數(shù):無(wú)
  281. 返回  值:無(wú)
  282. **************************************************************************/
  283. void setup() {
  284.   pinMode(IN1, OUTPUT);        //TB6612控制引腳,控制電機(jī)1的方向,01為正轉(zhuǎn),10為反轉(zhuǎn)
  285.   pinMode(IN2, OUTPUT);          //TB6612控制引腳,
  286.   pinMode(IN3, OUTPUT);          //TB6612控制引腳,控制電機(jī)2的方向,01為正轉(zhuǎn),10為反轉(zhuǎn)
  287.   pinMode(IN4, OUTPUT);          //TB6612控制引腳,
  288.   pinMode(PWMA, OUTPUT);         //TB6612控制引腳,電機(jī)PWM
  289.   pinMode(PWMB, OUTPUT);         //TB6612控制引腳,電機(jī)PWM
  290.   digitalWrite(IN1, 0);          //TB6612控制引腳拉低
  291.   digitalWrite(IN2, 0);          //TB6612控制引腳拉低
  292.   digitalWrite(IN3, 0);          //TB6612控制引腳拉低
  293.   digitalWrite(IN4, 0);          //TB6612控制引腳拉低
  294.   analogWrite(PWMA, 0);          //TB6612控制引腳拉低
  295.   analogWrite(PWMB, 0);          //TB6612控制引腳拉低
  296.   pinMode(2, INPUT);       //編碼器引腳
  297.   pinMode(4, INPUT);       //編碼器引腳
  298.   pinMode(5, INPUT);       //編碼器引腳
  299.   pinMode(8, INPUT);       //編碼器引腳
  300.   pinMode(3, INPUT);       //按鍵引腳
  301.   Wire.begin();             //加入 IIC 總線
  302.   Serial.begin(9600);       //開啟串口,設(shè)置波特率為 9600
  303.   delay(1500);              //延時(shí)等待初始化完成
  304.   Mpu6050.initialize();     //初始化MPU6050
  305.   delay(20);
  306.   if(digitalRead(KEY)==0) {    //讀取EEPROM的參數(shù)
  307.   Balance_Kp =  (float)((EEPROM.read(addr+0)*256)+EEPROM.read(addr+1) )/100;
  308.   Balance_Kd =  (float)((EEPROM.read(addr+2)*256)+EEPROM.read(addr+3))/100;
  309.   Velocity_Kp = (float)((EEPROM.read(addr+4)*256)+EEPROM.read(addr+5))/100;
  310.   Velocity_Ki = (float)((EEPROM.read(addr+6)*256)+EEPROM.read(addr+7))/100;
  311.   }
  312.   MsTimer2::set(5, control);  //使用Timer2設(shè)置5ms定時(shí)中斷
  313.   MsTimer2::start();          //使用中斷使能
  314.   attachInterrupt(0, READ_ENCODER_L, CHANGE);           //開啟外部中斷 編碼器接口1
  315.   attachPinChangeInterrupt(4, READ_ENCODER_R, CHANGE);  //開啟外部中斷 編碼器接口2
  316. }
  317. /**************************************************************************
  318. 函數(shù)功能:主循環(huán)程序體
  319. 入口參數(shù):無(wú)
  320. 返回  值:無(wú)
  321. **************************************************************************/
  322. void loop() {
  323.   int Voltage_Temp;
  324.   static unsigned char flag;
  325.   unsigned char Balance_Kp_Temp=0,Balance_Kd_Temp=0,Velocity_Kp_Temp=0,Velocity_Ki_Temp=0;
  326.   Voltage_Temp = (Battery_Voltage - 11.1) * 60;  //根據(jù)APP的協(xié)議對(duì)電池電壓變量進(jìn)行處理
  327.   if (Voltage_Temp > 100)Voltage_Temp = 100;
  328.   if (Voltage_Temp < 0)Voltage_Temp = 0;
  329.   if (Flag_Stop == 0)
  330.   {
  331.     Serial.begin(9600);       //開啟串口,設(shè)置波特率為 9600
  332.     flag=!flag;
  333.       if(PID_Send==1)//發(fā)送PID參數(shù)
  334.   {
  335.     Serial.print("{C");
  336.     Serial.print((int)(Balance_Kp*100));   //左輪編碼器
  337.     Serial.print(":");
  338.     Serial.print((int)(Balance_Kd*100));  //右輪編碼器
  339.     Serial.print(":");
  340.     Serial.print((int)(Velocity_Kp*100));  //電池電壓
  341.     Serial.print(":");
  342.     Serial.print((int)(Velocity_Ki*100));  //平衡傾角
  343.     Serial.print("}$");
  344.     PID_Send=0;
  345.   }
  346.     else if(flag==0)
  347.     {
  348.     Serial.print("{A");
  349.     Serial.print(abs(Velocity_Left / 2));   //左輪編碼器
  350.     Serial.print(":");
  351.     Serial.print(abs(Velocity_Right / 2));  //右輪編碼器
  352.     Serial.print(":");
  353.     Serial.print(Voltage_Temp);  //電池電壓
  354.     Serial.print(":");
  355.     Serial.print(Angle);  //平衡傾角
  356.     Serial.print("}$");
  357.     }
  358.       else
  359.     {
  360.     Serial.print("{B");
  361.     Serial.print(Angle);   
  362.     Serial.print(":");
  363.     Serial.print(Voltage_Temp);  
  364.     Serial.print(":");
  365.     Serial.print(Velocity_Left/2);
  366.     Serial.print(":");
  367.     Serial.print(Velocity_Right/2);
  368.     Serial.print("}$");
  369.     }
  370.     delay(50);
  371.   }
  372.   else    Serial.begin(128000), DataScope(); //使用上位機(jī)時(shí),波特率是128000
  373.     if(Flash_Send==1)        //寫入PID參數(shù)到EEPROM,由app控制該指令
  374.     {
  375.      EEPROM.write(addr,     ((unsigned int)(Balance_Kp*100)&0xff00)>>8);
  376.      EEPROM.write(addr+1,   (unsigned int)(Balance_Kp*100)&0xff);
  377.      EEPROM.write(addr+2,   ((unsigned int)(Balance_Kd*100)&0xff00)>>8);
  378.      EEPROM.write(addr+3,   (unsigned int)(Balance_Kd*100)&0xff);
  379.      EEPROM.write(addr+4,   ((unsigned int)(Velocity_Kp*100)&0xff00)>>8);
  380.      EEPROM.write(addr+5,   (unsigned int)(Velocity_Kp*100)&0xff);
  381.      EEPROM.write(addr+6,   ((unsigned int)(Velocity_Ki*100)&0xff00)>>8);
  382.      EEPROM.write(addr+7,   (unsigned int)(Velocity_Ki*100)&0xff);
  383.      Flash_Send=0;
  384.     }
  385. }
  386. /**************************************************************************
  387. 函數(shù)功能:外部中斷讀取編碼器數(shù)據(jù),具有二倍頻功能 注意外部中斷是跳變沿觸發(fā)
  388. 入口參數(shù):無(wú)
  389. 返回  值:無(wú)
  390. **************************************************************************/
  391. void READ_ENCODER_L() {
  392.   if (digitalRead(ENCODER_L) == LOW) {     //如果是下降沿觸發(fā)的中斷
  393.     if (digitalRead(DIRECTION_L) == LOW)      Velocity_L--;  //根據(jù)另外一相電平判定方向
  394.     else      Velocity_L++;
  395.   }
  396.   else {     //如果是上升沿觸發(fā)的中斷
  397.     if (digitalRead(DIRECTION_L) == LOW)      Velocity_L++; //根據(jù)另外一相電平判定方向
  398.     else     Velocity_L--;
  399.   }
  400. }
  401. /**************************************************************************
  402. 函數(shù)功能:外部中斷讀取編碼器數(shù)據(jù),具有二倍頻功能 注意外部中斷是跳變沿觸發(fā)
  403. 入口參數(shù):無(wú)
  404. 返回  值:無(wú)
  405. **************************************************************************/
  406. void READ_ENCODER_R() {
  407.   if (digitalRead(ENCODER_R) == LOW) { //如果是下降沿觸發(fā)的中斷
  408.     if (digitalRead(DIRECTION_R) == LOW)      Velocity_R--;//根據(jù)另外一相電平判定方向
  409.     else      Velocity_R++;
  410.   }
  411.   else {   //如果是上升沿觸發(fā)的中斷
  412.     if (digitalRead(DIRECTION_R) == LOW)      Velocity_R++; //根據(jù)另外一相電平判定方向
  413.     else     Velocity_R--;
  414.   }
  415. }
  416. /**************************************************************************
  417. 函數(shù)功能:串口接收中斷
  418. 入口參數(shù):無(wú)
  419. 返回  值:無(wú)
  420. **************************************************************************/
  421. void serialEvent()
  422. {   
  423.     static unsigned char Flag_PID,Receive[10],Receive_Data,i,j;
  424.    static float Data;

  425.    while (Serial.available()) {

  426.     Receive_Data=Serial.read();  
  427.     if(Receive_Data==0x7B) Flag_PID=1;  //參數(shù)指令起始位
  428.     if(Receive_Data==0x7D) Flag_PID=2;  //參數(shù)指令停止位
  429.     if(Flag_PID==1)
  430.      {
  431.       Receive[i]=Receive_Data;     //記錄數(shù)據(jù)
  432.       i++;
  433.      }
  434.     else  if(Flag_PID==2)  //執(zhí)行指令
  435.      {
  436.            if(Receive[3]==0x50)          PID_Send=1;   //獲取PID參數(shù)
  437.            else  if(Receive[3]==0x57)    Flash_Send=1; //掉電保存參數(shù)
  438.            else  if(Receive[1]!=0x23)    //更新PID參數(shù)
  439.            {               
  440.             for(j=i;j>=4;j--)
  441.             {
  442.               Data+=(Receive[j-1]-48)*pow(10,i-j);   //通訊協(xié)議
  443.             }
  444.             switch(Receive[1])
  445.              {
  446.                case 0x30:  Balance_Kp=Data/100;break;
  447.                case 0x31:  Balance_Kd=Data/100;break;
  448.                case 0x32:  Velocity_Kp=Data/100;break;
  449.                case 0x33:  Velocity_Ki=Data/100;break;
  450.                case 0x34:  break; //9個(gè)通道,預(yù)留5個(gè)
  451.                case 0x35:  break;
  452.                case 0x36:  break;
  453.                case 0x37:  break;
  454.                case 0x38:  break;
  455.              }
  456.            }         
  457.            Flag_PID=0; //相關(guān)標(biāo)志位清零
  458.            i=0;
  459.            j=0;
  460.            Data=0;
  461.      }
  462.        else  //藍(lán)牙遙控指令
  463.        {
  464.               switch (Receive_Data)   {
  465.                  //這是MinibalanceV1.0的APP發(fā)送指令
  466.                   case 0x01: Flag_Qian = 1, Flag_Hou = 0, Flag_Left = 0, Flag_Right = 0;   break;              //前進(jìn)
  467.                   case 0x02: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 0, Flag_Right = 1;   break;              //右轉(zhuǎn)
  468.                   case 0x03: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 0, Flag_Right = 1;   break;              //右轉(zhuǎn)
  469.                   case 0x04: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 0, Flag_Right = 1;   break;              //右轉(zhuǎn)
  470.                   case 0x05: Flag_Qian = 0, Flag_Hou = 1, Flag_Left = 0, Flag_Right = 0;   break;              //后退
  471.                   case 0x06: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 1, Flag_Right = 0;   break;               //左轉(zhuǎn)
  472.                   case 0x07: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 1, Flag_Right = 0;   break;               //左轉(zhuǎn)
  473.                   case 0x08: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 1, Flag_Right = 0;   break;               //左轉(zhuǎn)
  474.                   //這是MinibalanceV3.5的APP發(fā)送指令
  475.                   case 0x41: Flag_Qian = 1, Flag_Hou = 0, Flag_Left = 0, Flag_Right = 0;   break;              //前進(jìn)
  476.                   case 0x42: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 0, Flag_Right = 1;   break;             //右轉(zhuǎn)
  477.                   case 0x43: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 0, Flag_Right = 1;   break;             //右轉(zhuǎn)
  478.                   case 0x44: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 0, Flag_Right = 1;   break;              //右轉(zhuǎn)
  479.                   case 0x45:  Flag_Qian = 0, Flag_Hou = 1, Flag_Left = 0, Flag_Right = 0;   break;             //后退
  480.                   case 0x46: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 1, Flag_Right = 0;    break;               //左轉(zhuǎn)
  481.                   case 0x47: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 1, Flag_Right = 0;   break;               //左轉(zhuǎn)
  482.                   case 0x48: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 1, Flag_Right = 0;   break;             //左轉(zhuǎn)
  483.                   default: Flag_Qian = 0, Flag_Hou = 0, Flag_Left = 0, Flag_Right = 0;    break;                //停止
  484.                 }
  485.         }
  486.    }
  487. }
復(fù)制代碼

以上資料51hei提供下載:
Minibalance_for_Arduino_Final20181113.rar (6.24 KB, 下載次數(shù): 70)


評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:603612 發(fā)表于 2019-12-23 18:48 | 只看該作者
學(xué)習(xí)了,編譯沒(méi)通過(guò)
fatal error: DATASCOPE.h: No such file or directory少文件
回復(fù)

使用道具 舉報(bào)

板凳
ID:171746 發(fā)表于 2019-12-30 19:27 | 只看該作者
請(qǐng)發(fā)詳細(xì)點(diǎn)的資料嗎?    我是小白啊
回復(fù)

使用道具 舉報(bào)

地板
ID:452800 發(fā)表于 2020-3-7 21:07 | 只看該作者
看不懂的樣子啊
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 成人精品一区 | 久久99精品久久久 | 一区二区三区四区av | 成人av鲁丝片一区二区小说 | 精品免费国产一区二区三区 | 一级黄色淫片 | 成人av片在线观看 | 亚洲精品一二三区 | 91精品国产一区二区三区蜜臀 | 久久久久久免费毛片精品 | 日韩在线一区二区 | 色就是色欧美 | 操操日| 日本一区精品 | 午夜久久久 | 国产一二区在线 | 欧美亚洲日本 | 国产成人91| 日本不卡一区二区三区 | 日韩av免费看 | 久久99蜜桃综合影院免费观看 | 成人美女免费网站视频 | 国产日韩欧美精品一区二区三区 | 亚洲一区二区三区在线播放 | 亚洲国产精品人人爽夜夜爽 | 韩国av网站在线观看 | 国产精品久久久久无码av | 欧美性网| 久久aⅴ乱码一区二区三区 91综合网 | 亚洲精品一区二区网址 | 九九伊人sl水蜜桃色推荐 | 电影在线| 欧美国产精品一区二区 | 亚洲香蕉在线视频 | 99成人精品 | 成人国产精品久久久 | 久久国内精品 | 在线成人av | 国产精品欧美精品 | 亚洲一区二区不卡在线观看 | 成人免费视频在线观看 |