[PIC®/AVR®/dsPIC®产品] 平衡机器人

[复制链接]
2922|11
 楼主| gaoyang9992006 发表于 2021-11-9 10:21 | 显示全部楼层 |阅读模式
       嘿,伙计们。我知道已经有很多平衡机器人项目在互联网上,但我也想做一个。事实上,我想做一些特别的东西,使一个迷你平衡机器人,但我有点失败与继电机,我会解释下面的视频的问题。因此,我最后所做的,是使用相同的PCB,我已经准备了一个迷你平衡机器人,设计一个小的3D打印体,并使用更大的步进电机,这样能够完成我的想法。机器人应该从带有蓝牙连接的自制遥控器获取信息,这样我们就可以四处走动了。但在内部,机器人也应该从IMU模块获取信息,并计算角度的PID值,这样它就不会下降,总是试图保持水平。这是非常有趣的,我想你会学到很多与这个项目,因为我将解释电路的每一步,但也代码。那么,你觉得,这行得通吗?因此,让我们开始吧。

第 1 部分 - 为什么不是迷你机器人呢?
       我的计划是使用这个项目的PCB与这种步进电机,你可以看到下面。我有这些从旧的DVD驱动器, 我认为它们还可以在我的PCB上很好的工作 。很容易用步进电机驱动程序控制它们, 所以这不是问题所在。问题是机械的。你看,这些电机有一个轴连接到里面的磁铁。此轴由两侧支撑。为了给这个轴增加一个轮子,我不得不把它剪小,这样,我们只有一边的支持,这就是问题所在。没有两侧的支持,这个轴将移动,并自动打破里面所有的小线圈和磁铁。我试过在输出时粘合轴承,但没有成功。里面,轴被一个金属球保持在中心,一旦你移动,你可以告别孔电机。所以我别无选择,只能使用NEMA 17电机。因此,在PCB的一侧,我设计了一个3D打印支持。



第 2 部分 - 我们需要什么

      让我们看看这个项目需要什么。首先,PCB。如果您想要相同的 PCB,请从下面的一章中获取 GERBER 文件。我们需要的步进电机驱动程序,这是基于A4988的,但更妙的是,TMC2225驱动器可以更好和无声的运动。我们需要两个 NEMA 17 电机,MPU6050 陀螺仪/acc 模块,一个小型 5V 降压转换器,一个 3S 电池,两个 HC-05 蓝牙模块,一个用于机器人,另一个用于遥控器。此外,我们还可以添加一个小的OLED屏幕,以便为机器人创建人脸。作为小弹头,我们需要一个ATMega328p-AU芯片,16MHz谐振器和一些SMD电阻器和电容器。还有一个小的SMD蜂鸣器和一些LED。



第三部分 原理图



第四部分 PCB


第五部分 组装其他

3D打印文件




第6部分 - 机器人代码

代码几乎和我们对于无刷PID控制器或乒乓球控制器的代码相同,但这次我们使用步进电机。顶部创建应用于继器驱动程序的步进脉冲,在这种情况下,我们使用时间器 TIEMR 2。通过设置一些寄存器,我们使计时器每 20us 单击一次。我们阅读陀螺仪和加速度计的原始数据。为了克服陀螺偏移,在乞讨时,我们从 IMU 模块中读取大约 500 条读取,并将该数据保存为偏移,并在主循环中减去该数据。然后,我们计算每个循环的角度,该角度设置为每个 4000us。使用"gyro_angle"变量,我们可以计算 PID 值。和往常一样,我们发现PID错误是机器人的真实角度和所需角度之间的差异,后者应该是0,这样机器人就可以保持水平。最后,在计时器例程中,根据 PID 输出,我们通过创建或多或少、更快或更慢的应用于继电机的脉冲来计算电机的速度。为了加快代码的速度,我们使用注册控制,例如:PORTD |= 0b00001000;与将数字引脚 D3 设置为 HIGH 相同。有关此的更多信息,请查看我的Arduino 注册控制视频。
我的机器人还在晃来晃
去。这是因为我们必须调整代码中的 PID 值。这是这个项目中最长的部分。我不得不手动去改变PID值,直到我得到更好的结果,即使如此,我不太满意的最终结果。如果你只从P值开始,I和D是0,你会得到某种振荡,车轮根据角度与机器人的倾斜方向旋转。然后,我们添加一些 D 值,它会对角度变化的速度做出反应,并尝试停止振荡,但当误差非常小时,这还不够。最后,为了精细调整位置,我们添加的 I 在错误小时会缓慢增加或减少。超过30次尝试,我有或多或少的好结果,机器人是相当稳定的,但我还没有完全高兴。


  1. /* This code is for the balancing robot project. You can find more about this on https://www.electronoobs.com.
  2. * The code will read data from an IMU module, calculate the PID value in order to balance the robot at 0ยบ and
  3. * then it will create pules using a timer and apply those to some stepper motors and move the robot.
  4. * Kind thanks to Joop Brokking for the help: https://www.youtube.com/user/MacPuffdog
  5. *
  6. * Tutorial: https://electronoobs.com/eng_arduino_tut159.php
  7. * Schematic: https://electronoobs.com/eng_arduino_tut150_sch1.php */
  8.   

  9. //Include Libraries
  10. #include <Wire.h>                                  //Wire.h is used to get i2c data from the MPU6050

  11. /////////////////////////////////////////////////////////////////////////////////////////////////
  12. ///////////////////////////////////////////PID VALUES////////////////////////////////////////////
  13. /////////////////////////////////////////////////////////////////////////////////////////////////
  14. float Kp = 30;                    //P Gain; Mine was 30
  15. float Ki = 0.61;                  //I Gain; Mine was 0.61
  16. float Kd = 9;                     //D Gain; Mine was 9
  17. float Moving_Speed = 20;          //Moving speed with Bluetooth Control; Mine was 20
  18. float Max_Speed = 160;            //Max mooving speed; Mine was 160
  19. int Acc_Offset = 1045;            //Accelerometer offset value (find this before you run the code)
  20. /////////////////////////////////////////////////////////////////////////////////////////////////
  21. /////////////////////////////////////////////////////////////////////////////////////////////////


  22. /////////////////////////////////////////////////////////////////////////////////////////////////
  23. ////////////////////////////////////////////VARIABLES////////////////////////////////////////////
  24. /////////////////////////////////////////////////////////////////////////////////////////////////
  25. byte Activated, Received_byte;
  26. int left_motor;
  27. int Left_Motor_Speed;
  28. int CC_Speed_Left_Motor;
  29. int Left_Motor_Speed_Prev;
  30. int right_motor;
  31. int Right_Motor_Speed;
  32. int CC_Speed_Right_Motor;
  33. int Right_Motor_Speed_Prev;
  34. int Received_Since;
  35. int Gyro_X_Raw, Gyro_Y_Raw, Acc_Raw;
  36. long Gyro_Y_Offset, Gyro_X_Offset;
  37. unsigned long Loop_Time;
  38. float Gyro_Angle, Acc_Angle, Auto_Setpoint;
  39. float Temp_Error, PID_I, Setpoint, gyro_input, PID_Value, Last_D_Error;
  40. float PID_Value_left, PID_Value_right;
  41. int MPU6050_ADDR = 0x68;                          //MPU6050 I2C address (0x68 or sometimes 0x69)



  42. /////////////////////////////////////////////////////////////////////////////////////////////////
  43. //////////////////////////////////////////Input/Output///////////////////////////////////////////
  44. /////////////////////////////////////////////////////////////////////////////////////////////////
  45. int DIR_L = 2;      //Pin for left driver direction pin
  46. int STEP_L = 3;     //Pin for left driver steps pin
  47. int DIR_R = 4;      //Pin for right driver direction pin
  48. int STEP_R = 5;     //Pin for right driver steps pin
  49. int Enable = 6;     //Pin for drivers enable (both use same pin)
  50. int LED1 = 7;       //Left LED is connected on D7
  51. int LED2 = 8;       //Right LED is connected on D8
  52. int Buzzer = 9;     //Buzzer is connected on D9
  53. /////////////////////////////////////////////////////////////////////////////////////////////////
  54. /////////////////////////////////////////////////////////////////////////////////////////////////




  55. /////////////////////////////////////////////////////////////////////////////////////////////////
  56. ///////////////////////////////////////////SETUP LOOP////////////////////////////////////////////
  57. /////////////////////////////////////////////////////////////////////////////////////////////////
  58. void setup() {
  59.   Serial.begin(9600);       //Start the serial port at 9600 kbps
  60.   Wire.begin();             //Start I2C communication
  61.   TWBR = 12;                //Also set I2C clock speed to 400kHz

  62.   //Define the pins mode (Output or Input)
  63.   pinMode(DIR_L, OUTPUT);
  64.   pinMode(STEP_L, OUTPUT);
  65.   pinMode(DIR_R, OUTPUT);
  66.   pinMode(STEP_R, OUTPUT);
  67.   pinMode(LED1, OUTPUT);
  68.   pinMode(LED2, OUTPUT);
  69.   pinMode(Buzzer, OUTPUT);

  70.   /*Read this: Now we define a "timer", timer 2 in this case. This timer will be used to create
  71.   the step pulses for the motors. This timer will click every 20us and make the required calculations.
  72.   The code will be inside the subroutine of TIMER2_COMPA_vect at the end of the code*/
  73.   TCCR2A = 0;               //Start with TCCR2A set to zero
  74.   TCCR2B = 0;               //Start with TCCR2B set to zero
  75.   TIMSK2 |= (1 << OCIE2A);  //Interupt enable bit OCIE2A set to 1
  76.   TCCR2B |= (1 << CS21);    //Set CS21 bit: We set prescaler to 8
  77.   OCR2A = 39;               //Compare register is 39, so...   20us/(1s/(16MHz/8))-1
  78.   TCCR2A |= (1 << WGM21);   //Mode: Clear timer on compare

  79.   //Start MPU6050 communication
  80.   Wire.beginTransmission(MPU6050_ADDR);       //From the datastheet, the address is 0x68, but you can change that above.
  81.   Wire.write(0x6B);                           //Write on 0x6B register
  82.   Wire.write(0x00);                           //Set register to 00000000 and activate gyro
  83.   Wire.endTransmission();                     //End the i2c transmission
  84.   //Change gyro scale to +/-250deg/sec
  85.   Wire.beginTransmission(MPU6050_ADDR);       //My MPU6050 address is 0x68, change it at the begginning of the code
  86.   Wire.write(0x1B);                           //Write on 0x1B register
  87.   Wire.write(0x00);                           //Set scale to 250dps, full scale
  88.   Wire.endTransmission();                     //End the i2c transmission
  89.   //Change accelerometer scale to +/-4g.
  90.   Wire.beginTransmission(MPU6050_ADDR);       //My MPU6050 address is 0x68, change it at the begginning of the code
  91.   Wire.write(0x1C);                           //Write on 0x1C register
  92.   Wire.write(0x08);                           //Set scale to +/-4g
  93.   Wire.endTransmission();                     //End the i2c transmission
  94.   //Enable some filters
  95.   Wire.beginTransmission(MPU6050_ADDR);       //My MPU6050 address is 0x68, change it at the begginning of the code
  96.   Wire.write(0x1A);                           //Write on 0x1A register
  97.   Wire.write(0x03);                           //Set Digital Low Pass Filter to ~43Hz
  98.   Wire.endTransmission();                     //End the i2c transmission

  99.   /*When we start, the gyro might have an offset value. We make 520 readdings and get that calibration value
  100.   We use taht later in the code to substract the raw offset. */
  101.   for (int i = 0; i < 520; i++) {                               //Create 520 loops
  102.     if (i % 20 == 0){
  103.       digitalWrite(LED1, !digitalRead(LED1));                   //Blink the LED every 20 loops
  104.       digitalWrite(Buzzer, !digitalRead(Buzzer));               //Buzz every 20 loops
  105.     }
  106.     Wire.beginTransmission(MPU6050_ADDR);                       //Start i2c communication with MPU6050
  107.     Wire.write(0x43);                                           //We read from register 0x43
  108.     Wire.endTransmission();                                     //End the i2c transmission
  109.     Wire.requestFrom(MPU6050_ADDR, 4);                          //Request 2 bytes from the MPU6050
  110.     Gyro_Y_Offset += Wire.read() << 8 | Wire.read();            //Merge high and low byte and get an integer
  111.     Gyro_X_Offset += Wire.read() << 8 | Wire.read();            //Merge high and low byte and get an integer
  112.     delayMicroseconds(3500);                                    //Small delay
  113.   }
  114.   Gyro_X_Offset /= 520;                                         //Divide the total value by 520 to get the avarage gyro offset
  115.   Gyro_Y_Offset /= 520;                                         //Divide the total value by 520 to get the avarage gyro offset

  116.   delay(200);                                                   //Small Delay
  117.   pinMode(Enable, OUTPUT);                                      //Set Enable pin as OUTPUT
  118.   digitalWrite(Enable, LOW);                                    //Finally, we enable the stepper drivers (drivers are enabled with LOW)

  119.   //Set the Loop_Time variable at the next end loop time
  120.   Loop_Time = micros() + 4000;                                 //Loop time is 4000us
  121. }






  122. /////////////////////////////////////////////////////////////////////////////////////////////////
  123. ////////////////////////////////////////////VOID LOOP////////////////////////////////////////////
  124. /////////////////////////////////////////////////////////////////////////////////////////////////
  125. void loop() {
  126.   if (Serial.available()) {                                     //If there is serial data available from HC-05 module
  127.     Received_byte = Serial.read();                              //Store the received data
  128.     Received_Since = 0;                                         //Reset the counter
  129.   }
  130.   if (Received_Since <= 25) {
  131.     Received_Since ++;                                          //The received data wwill last 25 loops, around 100 milliseconds
  132.   }
  133.   else Received_byte = 0x00;                                    //After 100ms we reset the received data





  134.   /////////////////////////////////////////////////////////////////////////////////////////////////
  135.   /////////////////////////////////////////CALCUALTE ANGLE/////////////////////////////////////////
  136.   /////////////////////////////////////////////////////////////////////////////////////////////////
  137.   Wire.beginTransmission(MPU6050_ADDR);                           //Start communication with MPU6050
  138.   Wire.write(0x3F);                                               //Start reading register 3F
  139.   Wire.endTransmission();                                         //End i2c transmission
  140.   Wire.requestFrom(MPU6050_ADDR, 2);                              //Request 2 bytes from the MPU6050
  141.   Acc_Raw = Wire.read() << 8 | Wire.read();                       //Merge high and low byte and get an integer
  142.   Acc_Raw += Acc_Offset;                                          //Add the accelerometer offset value
  143.   if (Acc_Raw > 8200)Acc_Raw = 8200;                              //Prevent division by zero by limiting the acc data to +/-8200;
  144.   if (Acc_Raw < -8200)Acc_Raw = -8200;                            //Prevent division by zero by limiting the acc data to +/-8200;

  145.   Acc_Angle = asin((float)Acc_Raw / 8200.0) * 57.296;             //Calculate the current angle according to the accelerometer data

  146.   if (Activated == 0 && Acc_Angle > -0.5 && Acc_Angle < 0.5) {    //If the accelerometer angle is almost 0
  147.     Gyro_Angle = Acc_Angle;                                       //Load the accelerometer angle in the Gyro_Angle variable
  148.     Activated = 1;                                                //Set "Activated" variable and start PID control
  149.   }

  150.   Wire.beginTransmission(MPU6050_ADDR);                           //Start communication with MPU6050
  151.   Wire.write(0x43);                                               //Start reading register 43
  152.   Wire.endTransmission();                                         //End i2c transmission
  153.   Wire.requestFrom(MPU6050_ADDR, 4);                              //Request 4 bytes from the gyro
  154.   Gyro_Y_Raw = Wire.read() << 8 | Wire.read();                    ////Merge high and low byte and get an integer
  155.   Gyro_X_Raw = Wire.read() << 8 | Wire.read();                    ////Merge high and low byte and get an integer

  156.   Gyro_X_Raw -= Gyro_X_Offset;                                    //Add the gyro offset value
  157.   Gyro_Angle += Gyro_X_Raw * 0.000031;                            //Calculate traveled angle during this loop
  158.   Gyro_Y_Raw -= Gyro_Y_Offset;                                    //Add gyro offset value
  159.   Gyro_Angle = Gyro_Angle * 0.9996 + Acc_Angle * 0.0004;          //Correct the drift of the gyro angle with the accelerometer angle





  160.   /////////////////////////////////////////////////////////////////////////////////////////////////
  161.   ///////////////////////////////////////////PID CONTROL///////////////////////////////////////////
  162.   /////////////////////////////////////////////////////////////////////////////////////////////////
  163.   /*PID control si almos alwasy the same. We have a setpoint, which is the desired angle in this case (horizontal).
  164.     The PID will adjsut the speed and direction of the motors, so we can always go towards the desired angle. To get
  165.     the PID value, we use a PID algorithm formula.*/

  166.   //First, we calculate the error between the real angle and the value taht we want, in this case would be 0ยบ
  167.   Temp_Error = Gyro_Angle - Auto_Setpoint - Setpoint;

  168.   if (PID_Value > 10 || PID_Value < -10) {
  169.     Temp_Error += PID_Value * 0.015 ;
  170.   }

  171.   //I value
  172.   PID_I += Ki * Temp_Error;                                                 //Calculate the "I" value
  173.   if (PID_I > 400)PID_I = 400;                                              //We limit the "I" to the maximum output
  174.   else if (PID_I < -400)PID_I = -400;


  175.   //Calculate the PID output value
  176.   PID_Value = Kp * Temp_Error + PID_I + Kd * (Temp_Error - Last_D_Error);
  177.   if (PID_Value > 400)PID_Value = 400;                                      //Limit the P+I to the maximum output
  178.   else if (PID_Value < -400)PID_Value = -400;

  179.   Last_D_Error = Temp_Error;                                                //Store the error for the next loop

  180.   if (PID_Value < 6 && PID_Value > - 6)PID_Value = 0;                       //Dead-band where the robot is more or less balanced

  181.   if (Gyro_Angle > 30 || Gyro_Angle < -30 || Activated == 0) {              //If the robot falls or the "Activated" is 0
  182.     PID_Value = 0;                                                          //Set the PID output to 0 so the motors are stopped
  183.     PID_I = 0;                                                              //Reset the I-controller memory
  184.     Activated = 0;                                                          //Set the Activated variable to 0
  185.     Auto_Setpoint = 0;                                                      //Reset the Auto_Setpoint variable
  186.   }

  187.   /////////////////////////////////////////////////////////////////////////////////////////////////
  188.   /////////////////////////////////////////HC-05 CONTROL///////////////////////////////////////////
  189.   /////////////////////////////////////////////////////////////////////////////////////////////////
  190.   PID_Value_left = PID_Value;                               //Get PID output for the left motor
  191.   PID_Value_right = PID_Value;                              //Get PID output for the right motor

  192.   if (Received_byte & B00000001) {                          //We receive a a 00000001 so we turn Right
  193.     PID_Value_left += Moving_Speed;                         //Increase the left motor speed
  194.     PID_Value_right -= Moving_Speed;                        //Decrease the right motor speed
  195.   }
  196.   if (Received_byte & B00000010) {                          //We receive a a 00000010 so we turn Left
  197.     PID_Value_left -= Moving_Speed;                         //Decrease the left motor speed
  198.     PID_Value_right += Moving_Speed;                        //Increase the right motor speed
  199.   }

  200.   if (Received_byte & B00000100) {                          //We receive a a 00000100 so we go forward
  201.     if (Setpoint > -2.5)Setpoint -= 0.05;                   //Change the setpoint angle so the robot leans forwards
  202.     if (PID_Value > Max_Speed * -1)Setpoint -= 0.005;       //Change the setpoint angle so the robot leans forwards
  203.   }
  204.   if (Received_byte & B00001000) {                          //We receive a a 00001000 so we go backwards
  205.     if (Setpoint < 2.5)Setpoint += 0.05;                    //Change the setpoint angle so the robot leans backwards
  206.     if (PID_Value < Max_Speed)Setpoint += 0.005;            //Change the setpoint angle so the robot leans backwards
  207.   }

  208.   if (!(Received_byte & B00001100)) {                       //We receive a a 00001100 so no movement
  209.     if (Setpoint > 0.5)Setpoint -= 0.05;                    //If the PID setpoint is higher than 0.5, reduce setpoint by 0.05 every loop
  210.     else if (Setpoint < -0.5)Setpoint += 0.05;              //If the PID setpoint is lower than -0.5, increase setpoint by 0.05 every loop
  211.     else Setpoint = 0;                                      //If the PID setpoint is lower than 0.5 or highert than -0.5, set the setpoint to 0
  212.   }

  213.   if (Setpoint == 0) {                                      //If the setpoint is zero degrees
  214.     if (PID_Value < 0)Auto_Setpoint += 0.001;               //Increase the Auto_Setpoint if the robot is still moving forewards
  215.     if (PID_Value > 0)Auto_Setpoint -= 0.001;               //Decrease the Auto_Setpoint if the robot is still moving backwards
  216.   }


  217.   /////////////////////////////////////////////////////////////////////////////////////////////////
  218.   ////////////////////////////////////////MOTORS CONTROL///////////////////////////////////////////
  219.   /////////////////////////////////////////////////////////////////////////////////////////////////
  220.   
  221.   if (PID_Value_left > 0){
  222.     PID_Value_left = 405 - (1 / (PID_Value_left + 9)) * 5500;
  223.   }
  224.   else if (PID_Value_left < 0){
  225.     PID_Value_left = -405 - (1 / (PID_Value_left - 9)) * 5500;
  226.   }
  227.   if (PID_Value_right > 0){
  228.     PID_Value_right = 405 - (1 / (PID_Value_right + 9)) * 5500;
  229.   }
  230.   else if (PID_Value_right < 0){
  231.     PID_Value_right = -405 - (1 / (PID_Value_right - 9)) * 5500;
  232.   }

  233.   //Calculate the pulse time for the left and right motor
  234.   if (PID_Value_left > 0){
  235.     left_motor = 400 - PID_Value_left;
  236.   }
  237.   else if (PID_Value_left < 0){
  238.     left_motor = -400 - PID_Value_left;
  239.   }
  240.   else left_motor = 0;

  241.   if (PID_Value_right > 0){
  242.     right_motor = 400 - PID_Value_right;
  243.   }
  244.   else if (PID_Value_right < 0){
  245.     right_motor = -400 - PID_Value_right;
  246.   }
  247.   else right_motor = 0;
  248.   
  249.   Left_Motor_Speed = left_motor;
  250.   Right_Motor_Speed = right_motor;


  251.   /*The angle calculations are tuned for a loop time of 4 milliseconds.
  252.   //We make sure every loop is exactly 4 milliseconds so we set the Loop_Time to +4000 microseconds every loop.*/
  253.   while (Loop_Time > micros());
  254.   Loop_Time += 4000;
  255. }//End of void loop









  256. /////////////////////////////////////////////////////////////////////////////////////////////////
  257. ////////////////////////////////////////TIMER2_COMPA_vect////////////////////////////////////////
  258. /////////////////////////////////////////////////////////////////////////////////////////////////
  259. ISR(TIMER2_COMPA_vect) {
  260.   //Left motor pulses
  261.   CC_Speed_Left_Motor ++;                                       //Increase CC_Speed_Left_Motor by 1 every time this routine is executed
  262.   if (CC_Speed_Left_Motor > Left_Motor_Speed_Prev) {            //If the number of loops is larger then the Left_Motor_Speed_Prev variable
  263.     CC_Speed_Left_Motor = 0;                                    //Reset the CC_Speed_Left_Motor variable
  264.     Left_Motor_Speed_Prev = Left_Motor_Speed;                   //Load the next Left_Motor_Speed variable
  265.     if (Left_Motor_Speed_Prev < 0) {                            //If the Left_Motor_Speed_Prev is negative
  266.       PORTD &= 0b11111011;                                      //Set D2 low. Reverse  direction
  267.       Left_Motor_Speed_Prev *= -1;                              //Invert the Left_Motor_Speed_Prev variable
  268.     }
  269.     else PORTD |= 0b00000100;                                   //Set output D2 high. Forward direction.
  270.   }
  271.   else if (CC_Speed_Left_Motor == 1)PORTD |= 0b00001000;        //Set output D3 high to create a pulse for the stepper
  272.   else if (CC_Speed_Left_Motor == 2)PORTD &= 0b11110111;        //Set output D3 low because the pulse only has to last for 20us



  273.   //Right motor pulses
  274.   CC_Speed_Right_Motor ++;                                      //Increase CC_Speed_Right_Motor by 1 every time the routine is executed
  275.   if (CC_Speed_Right_Motor > Right_Motor_Speed_Prev) {          //If the number of loops is larger then the Right_Motor_Speed_Prev variable
  276.     CC_Speed_Right_Motor = 0;                                   //Reset the CC_Speed_Right_Motor variable
  277.     Right_Motor_Speed_Prev = Right_Motor_Speed;                 //Load the next Right_Motor_Speed variable
  278.     if (Right_Motor_Speed_Prev < 0) {                           //If the Right_Motor_Speed_Prev is negative
  279.       PORTD &= 0b11101111;                                      //Set output D4 low. Reverse the direction
  280.       Right_Motor_Speed_Prev *= -1;                             //Invert the Right_Motor_Speed_Prev variable
  281.     }
  282.     else PORTD |= 0b00010000;                                   //Set D4 high. Forward direction.
  283.   }
  284.   else if (CC_Speed_Right_Motor == 1)PORTD |= 0b00100000;       //Set output D5 high to create a pulse for the stepper controller
  285.   else if (CC_Speed_Right_Motor == 2)PORTD &= 0b11011111;       //Set output D5 low because the pulse only has to last for 20us
  286. }//End of timer rroutine



原文出处
https://electronoobs.com/eng_arduino_tut159.php


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| gaoyang9992006 发表于 2021-11-9 10:22 | 显示全部楼层
感兴趣的赶紧试试吧,Microchip的ATMega328p-AU单片机。很多DIY项目都是用的这个。
hu9jj 发表于 2021-11-9 10:45 | 显示全部楼层
文字是机器翻译过来的吧
 楼主| gaoyang9992006 发表于 2021-11-9 10:56 | 显示全部楼层
hu9jj 发表于 2021-11-9 10:45
文字是机器翻译过来的吧

是的,只有一部分我手动修改了一下。
 楼主| gaoyang9992006 发表于 2021-11-9 10:56 | 显示全部楼层
hu9jj 发表于 2021-11-9 10:45
文字是机器翻译过来的吧

其实不用看文字,看原理图和代码就行了。
提供了3D文件,和PCb 文件,直接弄就行了。
sparrow054 发表于 2021-11-9 13:38 | 显示全部楼层
这个好玩~~
七毛钱 发表于 2021-11-10 09:30 | 显示全部楼层
你这话说的有点像老外啊
 楼主| gaoyang9992006 发表于 2021-11-10 10:07 | 显示全部楼层
七毛钱 发表于 2021-11-10 09:30
你这话说的有点像老外啊

哈哈,是的,老外的电影里喜欢这么做介绍。
yangxiaor520 发表于 2021-11-11 08:05 来自手机 | 显示全部楼层
这个不错啊,看起来。
 楼主| gaoyang9992006 发表于 2021-11-11 11:38 | 显示全部楼层
yangxiaor520 发表于 2021-11-11 08:05
这个不错啊,看起来。

是的,比较简单,可以搞一个玩玩。
sadicy 发表于 2021-11-15 13:52 | 显示全部楼层
还带3D打印的?
没有装备啊
pzsh 发表于 2021-12-14 10:01 | 显示全部楼层
DIY 高手
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:如果你觉得我的分享或者答复还可以,请给我点赞,谢谢。

2052

主题

16405

帖子

222

粉丝
快速回复 在线客服 返回列表 返回顶部