极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 31621|回复: 7

自编四轴飞控代码——开源共勉

[复制链接]
发表于 2018-8-23 12:35:02 | 显示全部楼层 |阅读模式
本帖最后由 项目承接 于 2018-8-23 12:37 编辑

废话不说直接上代码,代码还在持续更新中,四轴DIY交流群:651925582
码云地址:https://gitee.com/s8888/four_axis_diy_code
当前飞机飞行调试状态视频
https://pan.baidu.com/s/186_9qj5sfNYck61N9ZJl_Q


遥控端

  1. /**x轴,y轴,Speed模拟量读取变量定义 start***/
  2. int x=0;
  3. int y=0;
  4. int s=0;

  5. int x1=0;
  6. int y1=0;
  7. int s1=0;
  8. int s2=0;
  9. int ss=0;
  10. /**x轴,y轴,Speed模拟量读取变量定义  end***/

  11. int i=0;  //飞控端发回状态值变量

  12. int op=0;//状态开关值

  13. void setup() {
  14.     /**串口初始化 start***/
  15.    Serial2.begin(115200);
  16.    Serial.begin(115200);
  17.    /**串口初始化 end***/
  18.    
  19. pinMode(11,OUTPUT);       //蜂鸣器引脚初始化
  20. pinMode(3,INPUT_PULLUP);  //遥控启动引脚初始化

  21. /**遥控开机提示 start***/
  22. for(int d=2;d>0;d--)
  23. {
  24. tone(11,2);
  25.   delay(d*100);
  26.   noTone(11);
  27.   delay(100);
  28. }
  29. /**遥控开机提示 end***/

  30. }

  31. void loop() {
  32.   /**遥控启动 start***/
  33. if((digitalRead(3)==0)&&(op==0))
  34. {
  35. op=1;
  36. }
  37. /**遥控启动 end***/

  38. /**拨码开关遥控停止 start***/
  39. if((digitalRead(3)==1)&&(op==1))
  40. {for(int d=2;d>0;d--)
  41. {
  42.   tone(11,2);
  43.   delay(d*200);
  44.   noTone(11);
  45.   delay(100);
  46. }
  47. op=0;
  48.    Serial2.print("$");//36//停止飞行指令
  49.    Serial2.print("!");//33 用于将每次传入的数值读取到,防止缓冲导致读取的不及时!

  50. }
  51. /**拨码开关 遥控停止 end***/

  52. /**遥控端接收 start***/
  53.   if( Serial2.available()>1)
  54. { i=Serial2.read();
  55. // Serial.println(i);
  56. }
  57. /**遥控端接收 end***/

  58.   /**飞控低压停止飞行 start***/
  59.   if(i==49)
  60. {
  61.   if(op==1)
  62.   {
  63.   tone(11,5);
  64.   delay(100);
  65.   noTone(11);
  66.   delay(100);
  67.   }
  68.   op==0;      //遥控停止状态值
  69.   i=0;        //遥控接收端数值归零
  70. }
  71.   /**飞控低压停止飞行 end***/


  72.    /**遥控模拟量读取 start***/
  73.        x=analogRead(A0);
  74.        y=analogRead(A1);
  75.        s=analogRead(A2)/7;
  76.       /**遥控模拟量读取 end***/

  77.       /**x轴,y轴,Speed 遥控模拟量输出值设置 start***/
  78.   if(x>950)
  79.     x=1;
  80.   else if(x<50)
  81.    x=2;
  82.    else
  83.    x=0;
  84.   if(y>950)  
  85.     y=1;
  86.   else if(y<50)
  87.     y=2;
  88. else
  89. y=0;
  90. if(s<15)
  91. s=0;
  92. if(s>120)
  93. s=120;
  94.     /**x轴,y轴,Speed 遥控模拟量输出值设置 end***/

  95.    /**遥控发送 start***/
  96. if((s!=s2)&&(op==1))
  97. {  
  98. pt();   //调用发送函数
  99. }
  100.   /**遥控发送 end***/
  101. }
  102.   /**遥控发送函数 start***/
  103. void pt()
  104. {
  105.    /**防止速度间差值过大引起剧烈反应 start***/
  106.   ss=s1-s;
  107. if(ss<-25)
  108. s1=s-25;
  109. else if(ss>25)
  110. s1=s1-25;
  111. else
  112.   s1=s;
  113.    /**防止速度间差值过大引起剧烈反应 end***/
  114.   
  115.   x1=x;
  116.   y1=y;
  117.   
  118.   s2=s;
  119.    if(s!=0)
  120. {
  121. /**遥控端发送格式 start***/
  122.      Serial2.print("&");//38
  123.      Serial2.print(x1);
  124.      Serial2.print("!");//33
  125.      Serial2.print(y1);
  126.      Serial2.print("!");
  127.      Serial2.print(s1);
  128.      Serial2.print("!");
  129.      Serial2.print("%");//37
  130.      Serial2.print("&");//38 用于将每次传入的数值读取到,防止缓冲导致读取的不及时!
  131.       /**遥控端发送格式 end***/
  132. }
  133.   /**遥控端停止飞行指令 start***/
  134.    else
  135.    {
  136.   if(ss>20)
  137.   {
  138.       s1=20;
  139.      for(s1;s1>0;s1=s1-5)
  140.       {
  141.     Serial2.print("&");//38
  142.     Serial2.print(x1);
  143.     Serial2.print("!");//33
  144.     Serial2.print(y1);
  145.     Serial2.print("!");
  146.     Serial2.print(s1);
  147.     Serial2.print("!");
  148.     Serial2.print("%");//37
  149.     Serial2.print("&");//38 用于将每次传入的数值读取到,防止缓冲导致读取的不及时!
  150.      delay(10);
  151.      }
  152.   }
  153.      Serial2.print("&");//38
  154.      Serial2.print(x1);
  155.      Serial2.print("!");//33
  156.      Serial2.print(y1);
  157.      Serial2.print("!");
  158.      Serial2.print(0);
  159.      Serial2.print("!");
  160.      Serial2.print("%");//37
  161.      Serial2.print("&");//38 用于将每次传入的数值读取到,防止缓冲导致读取的不及时!
  162.      delay(10);
  163. }
  164.   /**遥控端停止飞行指令 end***/

  165. }
  166. /**遥控发送函数 end***/
复制代码




飞控端

  1. //MPU6050相关设置
  2. #include <Kalman.h>
  3. #include <Wire.h>
  4. #include <Math.h>
  5. float fRad2Deg = 57.295779513f; //将弧度转为角度的乘数
  6. const int MPU = 0x68; //MPU-6050的I2C地址
  7. const int nValCnt = 7; //一次读取寄存器的数量
  8. const int nCalibTimes = 1000; //校准时读数的次数
  9. int calibData[nValCnt]; //校准数据
  10.    float realVals[7];
  11. unsigned long nCurTime;
  12. unsigned long nLastTime = 0; //上一次读数的时间
  13. float fLastRoll = 0.0f; //上一次滤波得到的Roll角
  14. float fLastPitch = 0.0f; //上一次滤波得到的Pitch角
  15. Kalman kalmanRoll; //Roll角滤波器
  16. Kalman kalmanPitch; //Pitch角滤波器

  17. /**控制接收端变量设置start***/
  18. int i=0;
  19. int iii=0;
  20. int ii[3];
  21. int ss[4];
  22. int s=0;//speed
  23. int a=0;// RX init
  24. int h=0;
  25. int p=0;
  26. int staus=0;// 当前状态,为1时可飞
  27. int pp=0;//限飞电压
  28. int limit=90;//pwm最大输出(0-255)
  29. /**控制接收端变量设置end***/


  30. /**pid变量设置start***/
  31. unsigned long t=0;
  32. float top;
  33. float left;
  34.   float topRate ;
  35.   float leftRate ;
  36.     float measured ;
  37. int sampletime=4;//ms 控制间隔时间

  38. //外环
  39. double kp=0.001;//0.45
  40. double ki=0.0035;
  41. double kd=0.0015;//0.0023
  42. //内环
  43. double knp=0.025;//0.45
  44. double kni=0.0035;
  45. double knd=0.0055;//0.0023
  46. int out1,out2,out3,out4;
  47. float desired=0.5;//获取期望角度
  48. int topp;//是否进行pid调整的中间变量
  49. int leftp;//是否进行pid调整的中间变量

  50. double error; //偏差:期望-测量值
  51. double integ; //偏差积分
  52. double iLimit; //作积分限制
  53. double deriv; //微分应该可用陀螺仪角速度代替

  54. double prerror;////前一次偏差
  55. double prlerror;////前一次偏差

  56. /**pid变量设置end***/

  57. /**电机引脚变量设置start***/
  58. int pin1=4;
  59. int pin2=5;
  60. int pin3=10;
  61. int pin4=11;
  62. /**电机引脚变量设置end***/

  63. /**PID调整函数***/
  64. void pid()
  65. {
  66.   h=s;                                 //遥控传进来的speed值赋值给h变量
  67.   int ol=(nCurTime-t)/1000;            //获取间隔时间   单位ms  
  68.   if(ol>sampletime){                   //此处判断是否进行调节
  69.     t=nCurTime;
  70.     measured=top;                      //获取roll角度
  71.     /**PID外环roll方向  start***/
  72.     error = desired - measured;        //偏差:期望-测量值
  73.    float pout=kp*error;                //pid外环 P项比例输出
  74.    float iout=ki*error*sampletime;     //pid外环 i项积分输出
  75.    float rout=pout+iout;               //pid外环 外环输出
  76.      /**PID外环roll方向 end***/
  77.      
  78.       /**PID内环roll方向 start***/
  79.      error =rout-topRate;           //角速度偏差:外环积分值-陀螺仪roll角速度测量值直接用的
  80.      pout=knp*error;                //pid内环 P项比例输出
  81.      iout=kni*error*sampletime;     //pid内环 I项积分输出
  82.      float dout=knd*(error-prerror);//pid内环 D项微分输出
  83.      prerror=error;                 //保存本次误差
  84.     float rrout=pout+iout+dout;     //pid内环 输出
  85.      /**PID内环roll方向 end***/

  86.       /**PID外环pitch方向  start***/
  87.     measured=left;//pitch              //获取pitch角度
  88.   
  89.     error = desired - measured;        //偏差:期望-测量值
  90.     pout=kp*error;                     //pid外环 P项比例输出
  91.     iout=ki*error*sampletime;          //pid外环 I项积分输出
  92.     rout=pout+iout;                    //pid外环 D项微分输出
  93.       /**PID外环pitch方向 end***/

  94.        /**PID内环pitch方向 start***/
  95.      error =rout-leftRate;             //角速度偏差:外环积分值-陀螺仪pitch角速度测量值直接用的
  96.      pout=knp*error;                   //pid内环 P项比例输出
  97.   
  98.      iout=kni*error*sampletime;        //pid内环 D项微分输出
  99.      dout=knd*(error-prlerror);        //pid内环 D项微分输出
  100.      prlerror=error;                   //保存本次误差
  101.      float  piout=pout+iout+dout;      //pid内环 输出
  102.       /**PID内环pitch方向 end***/

  103.         /**PWM输出 start***/
  104. out1=s-piout+rrout;
  105. out3=s+piout-rrout;
  106. out2=s-piout-rrout;
  107. out4=s+piout+rrout;
  108.         /**PWM输出 end***/

  109.    /**PWM输出限幅 start***/
  110. if(out1>limit)
  111. out1=limit;
  112. if(out2>limit)
  113. out2=limit;
  114. if(out3>limit)
  115. out3=limit;
  116. if(out4>limit)
  117. out4=limit;
  118. /**PWM输出限幅 end***/

  119.   /**PWM停止输出判断 start***/
  120. if(out3<0)
  121. out3=0;
  122. if(out2<0)
  123. out2=0;
  124. if(out1<0)
  125. out1=0;
  126. if(out4<0)
  127. out4=0;
  128. if(s==0)
  129. {
  130.   out1=0;
  131.   out2=0;
  132.   out3=0;
  133.   out4=0;
  134. }
  135. /**PWM停止输出判断 end***/

  136.   /**电路电源判断 start***/
  137. //p=analogRead(A6);
  138. //Serial.print("dianyuan:");
  139. //Serial.println(p);
  140. /**电路电源判断 end***/

  141. /**PWM输出串口检测 start***/
  142. //Serial.print("out1:");
  143. //Serial.println(out1);
  144. //Serial.print("out3:");
  145. //Serial.println(out3);
  146. //Serial.print("out2:");
  147. //Serial.println(out2);
  148. //Serial.print("out4:");
  149. //Serial.println(out4);
  150. /**PWM输出串口检测 end***/

  151. /**PWM输出 start***/
  152. analogWrite(pin1,out1);
  153.   analogWrite(pin2,out2);
  154.   analogWrite(pin3,out3);
  155.   analogWrite(pin4,out4);
  156.    /**PWM输出 end***/
  157.   }
  158. }



  159. void setup() {
  160.    /**飞控开机提示 start***/
  161.   pinMode(25,OUTPUT);//蜂鸣器引脚
  162. for(int d=1;d<4;d++)
  163. {
  164. tone(25, 3);
  165.   delay(100);
  166.   noTone(25);
  167.   delay(100);
  168. }
  169.    /**飞控开机提示end***/

  170.     /**MPU6050初始化 start***/
  171.    Wire.begin(); //初始化Wire库
  172.    WriteMPUReg(0x6B, 0); //启动MPU6050设备
  173.    Calibration(); //执行校准
  174.    nLastTime = micros(); //记录当前时间
  175.     /**MPU6050初始化 end***/

  176.     /**串口初始化 start***/
  177.    Serial2.begin(115200);
  178.    Serial.begin(115200);
  179.    /**串口初始化 end***/

  180.     /**电机输出口初始化 start***/
  181.    pinMode(pin1,OUTPUT);
  182.    pinMode(pin2,OUTPUT);
  183.    pinMode(pin3,OUTPUT);
  184.    pinMode(pin4,OUTPUT);
  185.      /**电机输出口初始化 end***/


  186. }

  187. void loop() {

  188. /**MPU6050测量结果输出 start***/
  189.   int readouts[nValCnt];
  190.   ReadAccGyr(readouts); //读出测量值
  191.   Rectify(readouts, realVals); //根据校准的偏移量进行纠正
  192.   //计算加速度向量的模长,均以g为单位
  193.   float fNorm = sqrt(realVals[0] * realVals[0] + realVals[1] * realVals[1] + realVals[2] * realVals[2]);
  194.   float fRoll = GetRoll(realVals, fNorm); //计算Roll角
  195.   if (realVals[1] > 0) {
  196.     fRoll = -fRoll;
  197.   }
  198.   float fPitch = GetPitch(realVals, fNorm); //计算Pitch角
  199.   if (realVals[0] < 0) {
  200.     fPitch = -fPitch;
  201.   }
  202.   //计算两次测量的时间间隔dt,以秒为单位
  203.    nCurTime = micros();
  204.   float dt = (double)(nCurTime - nLastTime) / 1000000.0;
  205.   //对Roll角和Pitch角进行卡尔曼滤波
  206.   float fNewRoll = kalmanRoll.getAngle(fRoll, realVals[4], dt);
  207.   float fNewPitch = kalmanPitch.getAngle(fPitch, realVals[5], dt);
  208.   //跟据滤波值计算角度速
  209.   float fRollRate = (fNewRoll - fLastRoll) / dt;
  210.   float fPitchRate = (fNewPitch - fLastPitch) / dt;
  211.    //更新本次测的时间
  212.   nLastTime = nCurTime;
  213. //更新Roll角和Pitch角
  214.   fLastRoll = fNewRoll;//top
  215.   fLastPitch = fNewPitch;//left
  216.   /**MPU6050测量结果输出 end***/
  217.   
  218.    
  219.      /**pid 涉及相关变量初始化 start***/
  220.     topRate=fRollRate;
  221.     leftRate= fPitchRate;
  222.     top=fNewRoll;
  223.     left=fNewPitch;
  224.      /**pid 涉及相关变量初始化 end***/

  225.       /**pid 本次是否进行调整判断 start***/
  226.     if(top<-1)
  227.   topp=-top;
  228.     else
  229.       topp=top;
  230.          if(left<-1)
  231. leftp=-left;
  232.     else
  233.       leftp=left;
  234. p=analogRead(A6);//电路电压测量

  235.    if(((h!=s)||(topp>desired)||(leftp>desired))&&(staus==1)&&(p>pp))
  236.   pid();
  237.   /**pid 本次是否进行调整判断 end***/


  238.        /**遥控数据接收 start***/
  239.   if( Serial2.available()>1)
  240. { i=Serial2.read();
  241. if(i>0)
  242. math();   //遥控数据处理函数调用
  243. }
  244.    /**遥控数据接收 end***/


  245. /**电源判断,低压停止飞行 start***/
  246. //   if((p<pp)&&(s>0)&&(staus==1))
  247. // {
  248. // power();
  249. //
  250. // }
  251.   /**电源判断,低压停止飞行 end***/

  252. }



  253. //向MPU6050写入一个字节的数据
  254. //指定寄存器地址与一个字节的值
  255. void WriteMPUReg(int nReg, unsigned char nVal) {
  256.   Wire.beginTransmission(MPU);
  257.   Wire.write(nReg);
  258.   Wire.write(nVal);
  259.   Wire.endTransmission(true);
  260. }

  261. //从MPU6050读出一个字节的数据
  262. //指定寄存器地址,返回读出的值
  263. unsigned char ReadMPUReg(int nReg) {
  264.   Wire.beginTransmission(MPU);
  265.   Wire.write(nReg);
  266.   Wire.requestFrom(MPU, 1, true);
  267.   Wire.endTransmission(true);
  268.   return Wire.read();
  269. }

  270. //从MPU6050读出加速度计三个分量、温度和三个角速度计
  271. //保存在指定的数组中
  272. void ReadAccGyr(int *pVals) {
  273.   Wire.beginTransmission(MPU);
  274.   Wire.write(0x3B);
  275.   Wire.requestFrom(MPU, nValCnt * 2, true);
  276.   Wire.endTransmission(true);
  277.   for (long i = 0; i < nValCnt; ++i) {
  278.     pVals[i] = Wire.read() << 8 | Wire.read();
  279.   }
  280. }

  281. //对大量读数进行统计,校准平均偏移量
  282. void Calibration()
  283. {
  284.   float valSums[7] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0};
  285.   //先求和
  286.   for (int i = 0; i < nCalibTimes; ++i) {
  287.     int mpuVals[nValCnt];
  288.     ReadAccGyr(mpuVals);
  289.     for (int j = 0; j < nValCnt; ++j) {
  290.       valSums[j] += mpuVals[j];
  291.     }
  292.   }
  293.   //再求平均
  294.   for (int i = 0; i < nValCnt; ++i) {
  295.     calibData[i] = int(valSums[i] / nCalibTimes);
  296.   }
  297.   calibData[2] += 16384; //设芯片Z轴竖直向下,设定静态工作点。
  298. }

  299. //算得Roll角。算法见文档。
  300. float GetRoll(float *pRealVals, float fNorm) {
  301.   float fNormXZ = sqrt(pRealVals[0] * pRealVals[0] + pRealVals[2] * pRealVals[2]);
  302.   float fCos = fNormXZ / fNorm;
  303.   return acos(fCos) * fRad2Deg;
  304. }

  305. //算得Pitch角。算法见文档。
  306. float GetPitch(float *pRealVals, float fNorm) {
  307.   float fNormYZ = sqrt(pRealVals[1] * pRealVals[1] + pRealVals[2] * pRealVals[2]);
  308.   float fCos = fNormYZ / fNorm;
  309.   return acos(fCos) * fRad2Deg;
  310. }

  311. //对读数进行纠正,消除偏移,并转换为物理量。公式见文档。
  312. void Rectify(int *pReadout, float *pRealVals) {
  313.   for (int i = 0; i < 3; ++i) {
  314.     pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 16384.0f;
  315.   }
  316.   pRealVals[3] = pReadout[3] / 340.0f + 36.53;
  317.   for (int i = 4; i < 7; ++i) {
  318.     pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 131.0f;
  319.   }
  320. }


  321. //遥控数据处理函数
  322. void math()
  323. {
  324.    /**停止飞行声音提醒 start***/
  325.   if((i==36)&&(p>pp))
  326.   {staus=0;    //是否可以飞行状态值
  327.   
  328.    stop_f();   //停止飞行函数
  329.    for(int d=2;d>0;d--)
  330. {
  331. tone(25,3);
  332.   delay(d*200);
  333.   noTone(25);
  334.   delay(100);
  335. }
  336.   }
  337.   /**停止飞行声音提醒 end***/
  338.   
  339.    if(i==38)
  340.   {
  341.     a=1;
  342.    
  343.   }
  344.   if(i==33)
  345.   {
  346. if(iii==1)
  347. ss[a]=ii[0];
  348. if(iii==2)
  349. ss[a]=ii[0]*10+ii[1];
  350. if(iii==3)
  351. ss[a]=ii[0]*100+ii[1]*10+ii[2];
  352. iii=0;
  353. a=a+1;

  354.   }
  355.   if(i==37)
  356.   {
  357. //  x1=ss[1];  //x轴控制值
  358. //  y1=ss[2];  //x轴控制值

  359.   s=ss[3];     //Speed控制值

  360.   
  361.   //是否可以飞行状态值 设置
  362. if((p>pp)&&(s>0))
  363. staus=1;

  364.    a=0;       //数据接收控制符
  365.   }
  366.   if(i>47)
  367.   {
  368.    iii=iii+1;
  369.    if(iii==1)
  370.    ii[0]=i-48;
  371.     if(iii==2)
  372.    ii[1]=i-48;
  373.   if(iii==3)
  374.    ii[2]=i-48;
  375.       i=0;  
  376.   }
  377. }
  378. /**遥控停止飞行函数 start***/
  379. void stop_f()
  380. {
  381. Serial2.print(p);
  382. if(s>10){
  383. for(int sss=s;sss>0;sss--)
  384.   {  
  385.     analogWrite(pin1,sss);
  386.     analogWrite(pin2,sss);
  387.     analogWrite(pin3,sss);
  388.     analogWrite(pin4,sss);

  389.   delay(10);

  390.   }
  391.    analogWrite(pin1,0);
  392.    analogWrite(pin2,0);
  393.    analogWrite(pin3,0);
  394.    analogWrite(pin4,0);
  395. }
  396. s=0;
  397. staus=0;
  398. }
  399. /**遥控停止飞行函数 end***/

  400.   /**低压停止飞行函数 start***/
  401. void power()
  402. {
  403.   Serial2.print(1);//低压报警值,传至遥控端
  404. if(s>0){
  405. for(int sss=s;sss>0;sss--)
  406.   {
  407.    
  408.     analogWrite(pin1,sss);
  409.     analogWrite(pin2,sss);
  410.     analogWrite(pin3,sss);
  411.     analogWrite(pin4,sss);

  412.   delay(10);

  413.   }
  414.     analogWrite(pin1,0);
  415.     analogWrite(pin2,0);
  416.     analogWrite(pin3,0);
  417.     analogWrite(pin4,0);                                                                                                                                                                                                                                                                                                                                                                                                      
  418.   
  419. }
  420.    s=0;
  421. staus=0;
  422. }
  423.   /**低压停止飞行函数 end***/
复制代码



电路图正在整理ing~


当前飞机飞行调试状态视频
https://pan.baidu.com/s/186_9qj5sfNYck61N9ZJl_Q


回复

使用道具 举报

发表于 2018-8-26 10:15:09 | 显示全部楼层
非常不错的项目,
但是为什么用水平拉线来固定机体呢?是不是出现了比较麻烦的自旋现象?
回复 支持 反对

使用道具 举报

发表于 2018-8-26 10:22:42 | 显示全部楼层
我很想star你的项目,不过没有码云账号,然而用github帐号关联马云原来很麻烦,话说我也要告别github,所以算了。
☆☆只能在这里给你了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-26 19:08:14 | 显示全部楼层
wing 发表于 2018-8-26 10:15
非常不错的项目,
但是为什么用水平拉线来固定机体呢?是不是出现了比较麻烦的自旋现象?

恩,目前有点自旋问题,同时平衡也有问题
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-26 19:09:14 | 显示全部楼层
wing 发表于 2018-8-26 10:22
我很想star你的项目,不过没有码云账号,然而用github帐号关联马云原来很麻烦,话说我也要告别github,所以 ...

哈哈,github后期会补上,最近家里网络不太好
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-26 19:09:51 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2018-8-27 14:08:12 | 显示全部楼层
建议参照APM的改,完全自己写走的弯路太多了。
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-19 23:05 , Processed in 0.037039 second(s), 20 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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