活动介绍

BUZZER_Turn() 这个语句是什么意思

时间: 2025-08-31 16:02:31 AIGC 浏览: 4
<think>好的,我需要回答用户关于BUZZER_Turn()函数的问题。首先,用户想知道这个函数的功能、定义和使用方法。 根据引用[2],蜂鸣器的代码中有Buzzer_Turn函数。这个函数的作用应该是切换蜂鸣器的状态。具体来说,当蜂鸣器处于关闭状态(高电平)时,调用这个函数会打开蜂鸣器(低电平),反之亦然。 接下来,我需要解析函数的定义。函数内部通过读取GPIOB_Pin_12的输出电平来判断当前状态。如果是低电平,说明蜂鸣器正在响,于是设置为高电平关闭;如果是高电平,则设置为低电平开启。这里需要注意的是,用户提供的代码中有两个if语句,但实际上应该使用if-else结构,否则在状态切换时可能会有问题。比如,当电平是低时,先设置为高,然后第二个if条件依然成立,又会设置为低,导致状态没有变化。这可能是个笔误,但根据用户提供的代码,我需要如实反映,不过可以指出潜在的问题。 然后是使用方法部分。用户需要先初始化蜂鸣器,调用Buzzer_Init(),之后在需要切换状态的时候调用Buzzer_Turn()。例如,在按键中断中调用,实现按一次开,再按一次关的效果。引用[4]提到模块化编程,所以这个函数应该被封装在对应的.C和.H文件中,方便主函数调用。 还需要注意代码中的GPIO配置是否正确。根据初始化函数,GPIOB_Pin_12被设置为推挽输出,这适合驱动蜂鸣器。同时,函数使用了GPIO_ReadOutputDataBit来读取当前输出状态,这可能在某些情况下不太准确,因为实际电平可能由于外部电路改变,但在这里假设硬件设计正确,所以直接读取输出寄存器是可行的。 最后,结合引用[1]提到的结构体初始化的方法,这里虽然没有直接使用结构体变量,但GPIO_InitTypeDef结构体的使用符合STM32的标准库函数流程,即定义结构体、配置参数、然后调用GPIO_Init函数。 总结一下,BUZZER_Turn()的功能是切换蜂鸣器状态,定义中通过判断当前电平并翻转,使用方法需要先初始化,然后在需要切换的地方调用。同时需要指出代码中可能的逻辑问题,帮助用户避免错误。</think>### BUZZER_Turn() 函数详解 #### 1. **功能说明** `Buzzer_Turn()` 是用于控制蜂鸣器状态翻转的函数。其核心功能是:**根据蜂鸣器当前状态(响/不响),自动切换为相反状态**。 - 若蜂鸣器当前处于**响铃状态**(低电平),调用该函数后会变为**静音**(高电平)。 - 若蜂鸣器当前处于**静音状态**(高电平),调用后会触发**响铃**(低电平)[^2]。 #### 2. **函数定义解析** ```c void Buzzer_Turn(void) { if(GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0) { GPIO_SetBits(GPIOB, GPIO_Pin_12); // 关闭蜂鸣器(高电平) } if(GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 1) { GPIO_ResetBits(GPIOB, GPIO_Pin_12); // 开启蜂鸣器(低电平) } } ``` - **逻辑流程**: 1. 通过 `GPIO_ReadOutputDataBit` 读取引脚 `GPIOB_Pin_12` 的当前电平状态。 2. 若为低电平(`0`),设置引脚为高电平(静音)。 3. 若为高电平(`1`),设置引脚为低电平(响铃)。 - **注意**:代码中两个 `if` 语句理论上只会执行一个分支,但实际建议改用 `if-else` 结构以提高效率。 #### 3. **使用方法** ##### 步骤 1:初始化蜂鸣器 在程序初始化阶段调用 `Buzzer_Init()`,配置 GPIO 引脚为推挽输出模式: ```c Buzzer_Init(); // 初始化蜂鸣器硬件[^2] ``` ##### 步骤 2:在需要翻转状态时调用 例如,在按键中断或定时器中调用 `Buzzer_Turn()`: ```c // 示例:按键按下时切换蜂鸣器状态 if (Key_Pressed()) { Buzzer_Turn(); // 状态翻转 } ``` #### 4. **典型应用场景** - **状态提示音**:如设备启动/关闭时通过短鸣提示。 - **报警触发**:检测到异常时持续蜂鸣,恢复正常后关闭。 - **交互反馈**:配合按键实现“嘀”声反馈[^4]。 --- ###
阅读全文

相关推荐

#include "balance.h" #include "TrackModule.h" int Time_count=0; //Time variable //计时变量 u8 Lidar_Detect = Lidar_Detect_ON; //电磁巡线模式雷达检测障碍物,默认开启 int RC_Lidar_Avoid_FLAG = RC_Avoid_OFF; //遥控模式雷达避障,默认关闭 u8 Mode; float RC_Velocity_CCD=350,RC_Velocity_ELE=350; float PS2_Velocity,PS2_Turn_Velocity; //遥控控制的速度 Encoder OriginalEncoder; //Encoder raw data //编码器原始数据 u8 Lidar_Success_Receive_flag=0,Lidar_flag_count=0;//雷达在线标志位,雷达掉线计数器 //粗延时函数,微秒 void delay1_us(u16 time) { u16 i=0; while(time--) { i=10; //自己定义 while(i--) ; } } //毫秒级的延时 void delay1_ms(u16 time) { u16 i=0; while(time--) { i=12000; //自己定义 while(i--) ; } } /************************************************************************** Function: The inverse kinematics solution is used to calculate the target speed of each wheel according to the target speed of three axes Input : X and Y, Z axis direction of the target movement speed Output : none 函数功能:运动学逆解,根据三轴目标速度计算各车轮目标转速 入口参数:X和Y、Z轴方向的目标运动速度 返回 值:无 **************************************************************************/ void Drive_Motor(float Vx,float Vy,float Vz) { float amplitude=3.5; //Wheel target speed limit //车轮目标速度限幅 // if((Mode == PS2_Control_Mode||Mode == APP_Control_Mode)&&RC_Lidar_Avoid_FLAG&&Lidar_Success_Receive_flag)//app以及ps2控制下,判断是否开启遥控避障 // { // RC_Lidar_Aviod(&Vx,&Vy,&Vz); // } // //Speed smoothing is enabled when moving the omnidirectional trolley // //全向移动小车才开启速度平滑处理 // if(Car_Mode==Mec_Car||Car_Mode==Omni_Car) // { // Smooth_control(Vx,Vy,Vz); //Smoothing the input speed //对输入速度进行平滑处理 // // //Get the smoothed data // //获取平滑处理后的数据 // Vx=smooth_control.VX; // Vy=smooth_control.VY; // Vz=smooth_control.VZ; // } // // //Mecanum wheel car // //麦克纳姆轮小车 // if (Car_Mode==Mec_Car) // { // //Inverse kinematics //运动学逆解 // MOTOR_A.Target = +Vy+Vx-Vz*(Axle_spacing+Wheel_spacing); // MOTOR_B.Target = -Vy+Vx-Vz*(Axle_spacing+Wheel_spacing); // MOTOR_C.Target = +Vy+Vx+Vz*(Axle_spacing+Wheel_spacing); // MOTOR_D.Target = -Vy+Vx+Vz*(Axle_spacing+Wheel_spacing); // // //Wheel (motor) target speed limit //车轮(电机)目标速度限幅 // MOTOR_A.Target=target_limit_float(MOTOR_A.Target,-amplitude,amplitude); // MOTOR_B.Target=target_limit_float(MOTOR_B.Target,-amplitude,amplitude); // MOTOR_C.Target=target_limit_float(MOTOR_C.Target,-amplitude,amplitude); // MOTOR_D.Target=target_limit_float(MOTOR_D.Target,-amplitude,amplitude); // } // // //Omni car // //全向轮小车 // else if (Car_Mode==Omni_Car) // { // //Inverse kinematics //运动学逆解 // MOTOR_A.Target = Vy + Omni_turn_radiaus*Vz; // MOTOR_B.Target = -X_PARAMETER*Vx - Y_PARAMETER*Vy + Omni_turn_radiaus*Vz; // MOTOR_C.Target = +X_PARAMETER*Vx - Y_PARAMETER*Vy + Omni_turn_radiaus*Vz; // // //Wheel (motor) target speed limit //车轮(电机)目标速度限幅 // MOTOR_A.Target=target_limit_float(MOTOR_A.Target,-amplitude,amplitude); // MOTOR_B.Target=target_limit_float(MOTOR_B.Target,-amplitude,amplitude); // MOTOR_C.Target=target_limit_float(MOTOR_C.Target,-amplitude,amplitude); // MOTOR_D.Target=0; //Out of use //没有使用到 // } // // //Ackermann structure car // //阿克曼小车 // else if (Car_Mode==Akm_Car) // { // //Ackerman car specific related variables //阿克曼小车专用相关变量 // float R, Ratio=636.56, AngleR, Angle_Servo; // // // For Ackerman small car, Vz represents the front wheel steering Angle // //对于阿克曼小车Vz代表右前轮转向角度 // AngleR=Vz; // R=Axle_spacing/tan(AngleR)-0.5f*Wheel_spacing; // // // Front wheel steering Angle limit (front wheel steering Angle controlled by steering engine), unit: rad // //前轮转向角度限幅(舵机控制前轮转向角度),单位:rad // AngleR=target_limit_float(AngleR,-0.49f,0.32f); // // //Inverse kinematics //运动学逆解 // if(AngleR!=0) // { // MOTOR_A.Target = Vx*(R-0.5f*Wheel_spacing)/R; // MOTOR_B.Target = Vx*(R+0.5f*Wheel_spacing)/R; // } // else // { // MOTOR_A.Target = Vx; // MOTOR_B.Target = Vx; // } // // The PWM value of the servo controls the steering Angle of the front wheel // //舵机PWM值,舵机控制前轮转向角度 // //Angle_Servo = -0.628f*pow(AngleR, 3) + 1.269f*pow(AngleR, 2) - 1.772f*AngleR + 1.573f; // Angle_Servo = -0.628f*pow(AngleR, 3) + 1.269f*pow(AngleR, 2) - 1.772f*AngleR + 1.755f; // Servo=SERVO_INIT + (Angle_Servo - 1.755f)*Ratio; // // //Wheel (motor) target speed limit //车轮(电机)目标速度限幅 // MOTOR_A.Target=target_limit_float(MOTOR_A.Target,-amplitude,amplitude); // MOTOR_B.Target=target_limit_float(MOTOR_B.Target,-amplitude,amplitude); // MOTOR_C.Target=0; //Out of use //没有使用到 // MOTOR_D.Target=0; //Out of use //没有使用到 // Servo=target_limit_int(Servo,800,2200); //Servo PWM value limit //舵机PWM值限幅 // } // // //Differential car // //差速小车 // else if (Car_Mode==Diff_Car) // { //Inverse kinematics //运动学逆解 MOTOR_A.Target = Vx - Vz * Wheel_spacing / 2.0f; //计算出左轮的目标速度 MOTOR_B.Target = Vx + Vz * Wheel_spacing / 2.0f; //计算出右轮的目标速度 //Wheel (motor) target speed limit //车轮(电机)目标速度限幅 MOTOR_A.Target=target_limit_float( MOTOR_A.Target,-amplitude,amplitude); MOTOR_B.Target=target_limit_float( MOTOR_B.Target,-amplitude,amplitude); MOTOR_C.Target=0; //Out of use //没有使用到 MOTOR_D.Target=0; //Out of use //没有使用到 // } // // //FourWheel car // //四驱车 // else if(Car_Mode==FourWheel_Car) // { // //Inverse kinematics //运动学逆解 // MOTOR_A.Target = Vx - Vz * (Wheel_spacing + Axle_spacing) / 2.0f; //计算出左轮的目标速度 // MOTOR_B.Target = Vx - Vz * (Wheel_spacing + Axle_spacing) / 2.0f; //计算出左轮的目标速度 // MOTOR_C.Target = Vx + Vz * (Wheel_spacing + Axle_spacing) / 2.0f; //计算出右轮的目标速度 // MOTOR_D.Target = Vx + Vz * (Wheel_spacing + Axle_spacing) / 2.0f; //计算出右轮的目标速度 // // //Wheel (motor) target speed limit //车轮(电机)目标速度限幅 // MOTOR_A.Target=target_limit_float( MOTOR_A.Target,-amplitude,amplitude); // MOTOR_B.Target=target_limit_float( MOTOR_B.Target,-amplitude,amplitude); // MOTOR_C.Target=target_limit_float( MOTOR_C.Target,-amplitude,amplitude); // MOTOR_D.Target=target_limit_float( MOTOR_D.Target,-amplitude,amplitude); // } // // //Tank Car // //履带车 // else if (Car_Mode==Tank_Car) // { // //Inverse kinematics //运动学逆解 // MOTOR_A.Target = Vx - Vz * (Wheel_spacing) / 2.0f; //计算出左轮的目标速度 // MOTOR_B.Target = Vx + Vz * (Wheel_spacing) / 2.0f; //计算出右轮的目标速度 // // //Wheel (motor) target speed limit //车轮(电机)目标速度限幅 // MOTOR_A.Target=target_limit_float( MOTOR_A.Target,-amplitude,amplitude); // MOTOR_B.Target=target_limit_float( MOTOR_B.Target,-amplitude,amplitude); // MOTOR_C.Target=0; //Out of use //没有使用到 // MOTOR_D.Target=0; //Out of use //没有使用到 // } } /************************************************************************** Function: FreerTOS task, core motion control task Input : none Output : none 函数功能:FreeRTOS任务,核心运动控制任务 入口参数:无 返回 值:无 **************************************************************************/ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { static u8 Count_CCD = 0; //调节CCD控制频率 static u8 last_mode = 0; if(htim->Instance==TIM12) { // //TIM12->SR &= ~(0x01); // //Time count is no longer needed after 30 seconds // //时间计数,30秒后不再需要 // if(Time_count<3000)Time_count++; // //Get the encoder data, that is, the real time wheel speed, // //and convert to transposition international units // //获取编码器数据,即车轮实时速度,并转换位国际单位 // Get_Velocity_Form_Encoder(); //// if(++Lidar_flag_count==10) Lidar_Success_Receive_flag=0,Lidar_flag_count=0,RC_Lidar_Avoid_FLAG=RC_Avoid_OFF; //100ms清零雷达接收到数据标志位 //// switch(User_Key_Scan()) //// { //// case 1: //单击用来切换模式 //// Mode++; //// if(Mode == ELE_Line_Patrol_Mode) //// { //// ELE_ADC_Init(); //初始化电磁巡线模式 //// } ////// //// else if(Mode == CCD_Line_Patrol_Mode) //CCD巡线模式 //// { //// CCD_Init(); //CCD初始化,CCD模块和电磁巡线模块共用一个接口,两个不能同时使用 //// } //// else if(Mode > 6) //5种模式循环切换 //// { //// Mode = 0; //// } //// break; //// case 2: //电磁巡线状态时,双击可以打开/关闭雷达检测障碍物,默认打开 //// if(Mode == ELE_Line_Patrol_Mode) //电磁巡线控制模式下 //// { //// Lidar_Detect = !Lidar_Detect; //// if(Lidar_Detect == Lidar_Detect_OFF) //// memset(Dataprocess,0, sizeof(PointDataProcessDef)*225); //用于雷达检测障碍物的数组清零 //// }else if(Mode == APP_Control_Mode||Mode ==PS2_Control_Mode){ //// RC_Lidar_Avoid_FLAG=!RC_Lidar_Avoid_FLAG; //// if(RC_Lidar_Avoid_FLAG == RC_Avoid_OFF) //// memset(Dataprocess,0, sizeof(PointDataProcessDef)*225); //用于雷达检测障碍物的数组清零 //// } //// break; //// } //// if(last_mode != Mode) //每次切换模式需要刷新屏幕 //// { //// last_mode++; //// OLED_Clear(); //// if(last_mode>6) //// last_mode = 0; //// } //// //// if(Mode != ELE_Line_Patrol_Mode) //// Buzzer_Alarm(0); //// if(Mode == APP_Control_Mode) Get_RC(); //Handle the APP remote commands //处理APP遥控命令 //// else if(Mode == PS2_Control_Mode) PS2_Control(); //Handle PS2 controller commands //处理PS2手柄控制命令 //// else if(Mode == Lidar_Avoid_Mode) Lidar_Avoid(); //Avoid Mode //避障模式 //// else if(Mode == Lidar_Follow_Mode) Lidar_Follow(); //Follow Mode //跟随模式 //// else if(Mode == Lidar_Along_Mode) Lidar_along_wall(); //Along Mode //走直线模式 //// else if(Mode == ELE_Line_Patrol_Mode) //// { //// //// //// Get_RC_ELE(); //ELE模式 ////// delay1_ms(2); //// } //// else //CCD模式 //// { //// if(++Count_CCD == 2) //调节控制频率,4*5 = 20ms控制一次 //// { //// Count_CCD = 0; //// //// Get_RC_CCD(); //// } //// else if(Count_CCD>2) //// Count_CCD = 0; //// } // // // IRDM_line_inspection_V2(); // Drive_Motor(Move_X,Move_Y,Move_Z); // // // //If there is no abnormity in the battery voltage, and the enable switch is in the ON position, // //and the software failure flag is 0 // //如果电池电压不存在异常,而且使能开关在ON档位,而且软件失能标志位为0 // if(Turn_Off(Voltage)==0) // { // //Speed closed-loop control to calculate the PWM value of each motor, // //PWM represents the actual wheel speed // //速度闭环控制计算各电机PWM值,PWM代表车轮实际转速 // MOTOR_A.Motor_Pwm=Incremental_PI_A(MOTOR_A.Encoder, MOTOR_A.Target); // MOTOR_B.Motor_Pwm=Incremental_PI_B(MOTOR_B.Encoder, MOTOR_B.Target); // MOTOR_C.Motor_Pwm=Incremental_PI_C(MOTOR_C.Encoder, MOTOR_C.Target); // MOTOR_D.Motor_Pwm=Incremental_PI_D(MOTOR_D.Encoder, MOTOR_D.Target); // Limit_Pwm(16500) ; // //Set different PWM control polarity according to different car models // //根据不同小车型号设置不同的PWM控制极性 // switch(Car_Mode) // { // case Mec_Car: Set_Pwm(-MOTOR_A.Motor_Pwm, -MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //Mecanum wheel car //麦克纳姆轮小车 // case Omni_Car: Set_Pwm( MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //Omni car //全向轮小车 // case Akm_Car: Set_Pwm(-MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, Servo); break; //Ackermann structure car //阿克曼小车 // case Diff_Car: Set_Pwm(-MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //Differential car //两轮差速小车 // case FourWheel_Car: Set_Pwm(-MOTOR_A.Motor_Pwm, -MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //FourWheel car //四驱车 // case Tank_Car: Set_Pwm(-MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm, 0 ); break; //Tank Car //履带车 // } // } // //If Turn_Off(Voltage) returns to 1, the car is not allowed to move, and the PWM value is set to 0 // //如果Turn_Off(Voltage)返回值为1,不允许控制小车进行运动,PWM值设置为0 // else Set_Pwm(0,0,0,0,0); //----------------云台移植测试-------------------// Xianfu_Pwm(); Velocity1=Position_PID_1(Position1,Target1); //舵机PID控制,可以根据目标位置进行速度调整,离目标位置越远速度越快 Velocity2=Position_PID_2(Position2,Target2); //舵机PID控制,可以根据目标位置进行速度调整,离目标位置越远速度越快 Xianfu_Velocity(); Set_Pwm_PTZ(Velocity1,Velocity2); //赋值给PWM寄存器 } } /************************************************************************** Function: Assign a value to the PWM register to control wheel speed and direction Input : PWM Output : none 函数功能:赋值给PWM寄存器,控制车轮转速与方向 入口参数:PWM 返回 值:无 **************************************************************************/ void Set_Pwm(int motor_a,int motor_b,int motor_c,int motor_d,int servo) { if(motor_a<0) PWMA2=16800,PWMA1=16800+motor_a; else PWMA1=16800,PWMA2=16800-motor_a; if(motor_b<0) PWMB1=16800,PWMB2=16800+motor_b; else PWMB2=16800,PWMB1=16800-motor_b; if(motor_c<0) PWMC1=16800,PWMC2=16800+motor_c; else PWMC2=16800,PWMC1=16800-motor_c; if(motor_d<0) PWMD2=16800,PWMD1=16800+motor_d; else PWMD1=16800,PWMD2=16800-motor_d; //Servo control //舵机控制 Servo_PWM = servo; } /************************************************************************** Function: Limit PWM value Input : Value Output : none 函数功能:限制PWM值 入口参数:幅值 返回 值:无 **************************************************************************/ void Limit_Pwm(int amplitude) { MOTOR_A.Motor_Pwm=target_limit_float(MOTOR_A.Motor_Pwm,-amplitude,amplitude); MOTOR_B.Motor_Pwm=target_limit_float(MOTOR_B.Motor_Pwm,-amplitude,amplitude); MOTOR_C.Motor_Pwm=target_limit_float(MOTOR_C.Motor_Pwm,-amplitude,amplitude); MOTOR_D.Motor_Pwm=target_limit_float(MOTOR_D.Motor_Pwm,-amplitude,amplitude); } /************************************************************************** Function: Limiting function Input : Value Output : none 函数功能:限幅函数 入口参数:幅值 返回 值:无 **************************************************************************/ float target_limit_float(float insert,float low,float high) { if (insert < low) return low; else if (insert > high) return high; else return insert; } int target_limit_int(int insert,int low,int high) { if (insert < low) return low; else if (insert > high) return high; else return insert; } /************************************************************************** Function: Check the battery voltage, enable switch status, software failure flag status Input : Voltage Output : Whether control is allowed, 1: not allowed, 0 allowed 函数功能:检查电池电压、使能开关状态、软件失能标志位状态 入口参数:电压 返回 值:是否允许控制,1:不允许,0允许 **************************************************************************/ u8 Turn_Off( int voltage) { u8 temp; if(voltage<10||EN==0||Flag_Stop==1) { temp=1; } else temp=0; return temp; } /************************************************************************** Function: Calculate absolute value Input : long int Output : unsigned int 函数功能:求绝对值 入口参数:long int 返回 值:unsigned int **************************************************************************/ u32 myabs(long int a) { u32 temp; if(a<0) temp=-a; else temp=a; return temp; } /************************************************************************** Function: Incremental PI controller Input : Encoder measured value (actual speed), target speed Output : Motor PWM According to the incremental discrete PID formula pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)] e(k) represents the current deviation e(k-1) is the last deviation and so on PWM stands for incremental output In our speed control closed loop system, only PI control is used pwm+=Kp[e(k)-e(k-1)]+Ki*e(k) 函数功能:增量式PI控制器 入口参数:编码器测量值(实际速度),目标速度 返回 值:电机PWM 根据增量式离散PID公式 pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)] e(k)代表本次偏差 e(k-1)代表上一次的偏差 以此类推 pwm代表增量输出 在我们的速度控制闭环系统里面,只使用PI控制 pwm+=Kp[e(k)-e(k-1)]+Ki*e(k) **************************************************************************/ int Incremental_PI_A (float Encoder,float Target) { static float Bias,Pwm,Last_bias; Bias=Target-Encoder; //Calculate the deviation //计算偏差 Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias; if(Pwm>16800)Pwm=16800; if(Pwm<-16800)Pwm=-16800; Last_bias=Bias; //Save the last deviation //保存上一次偏差 return Pwm; } int Incremental_PI_B (float Encoder,float Target) { static float Bias,Pwm,Last_bias; Bias=Target-Encoder; //Calculate the deviation //计算偏差 Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias; if(Pwm>16800)Pwm=16800; if(Pwm<-16800)Pwm=-16800; Last_bias=Bias; //Save the last deviation //保存上一次偏差 return Pwm; } int Incremental_PI_C (float Encoder,float Target) { static float Bias,Pwm,Last_bias; Bias=Target-Encoder; //Calculate the deviation //计算偏差 Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias; if(Pwm>16800)Pwm=16800; if(Pwm<-16800)Pwm=-16800; Last_bias=Bias; //Save the last deviation //保存上一次偏差 return Pwm; } int Incremental_PI_D (float Encoder,float Target) { static float Bias,Pwm,Last_bias; Bias=Target-Encoder; //Calculate the deviation //计算偏差 Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias; if(Pwm>16800)Pwm=16800; if(Pwm<-16800)Pwm=-16800; Last_bias=Bias; //Save the last deviation //保存上一次偏差 return Pwm; } /************************************************************************** Function: Processes the command sent by APP through usart 2 Input : none Output : none 函数功能:对APP通过串口2发送过来的命令进行处理 入口参数:无 返回 值:无 **************************************************************************/ void Get_RC(void) { u8 Flag_Move=1; if(Car_Mode==Mec_Car||Car_Mode==Omni_Car) //The omnidirectional wheel moving trolley can move laterally //全向轮运动小车可以进行横向移动 { switch(Flag_Direction) //Handle direction control commands //处理方向控制命令 { case 1: Move_X=RC_Velocity; Move_Y=0; Flag_Move=1; break; case 2: Move_X=RC_Velocity; Move_Y=-RC_Velocity; Flag_Move=1; break; case 3: Move_X=0; Move_Y=-RC_Velocity; Flag_Move=1; break; case 4: Move_X=-RC_Velocity; Move_Y=-RC_Velocity; Flag_Move=1; break; case 5: Move_X=-RC_Velocity; Move_Y=0; Flag_Move=1; break; case 6: Move_X=-RC_Velocity; Move_Y=RC_Velocity; Flag_Move=1; break; case 7: Move_X=0; Move_Y=RC_Velocity; Flag_Move=1; break; case 8: Move_X=RC_Velocity; Move_Y=RC_Velocity; Flag_Move=1; break; default: Move_X=0; Move_Y=0; Flag_Move=0; break; } if(Flag_Move==0) { //If no direction control instruction is available, check the steering control status //如果无方向控制指令,检查转向控制状态 if (Flag_Left ==1) Move_Z= PI/2*(RC_Velocity/500); //left rotation //左自转 else if(Flag_Right==1) Move_Z=-PI/2*(RC_Velocity/500); //right rotation //右自转 else Move_Z=0; //stop //停止 } } else //Non-omnidirectional moving trolley //非全向移动小车 { switch(Flag_Direction) //Handle direction control commands //处理方向控制命令 { case 1: Move_X=+RC_Velocity; Move_Z=0; break; case 2: Move_X=+RC_Velocity; Move_Z=-PI/2; break; case 3: Move_X=0; Move_Z=-PI/2; break; case 4: Move_X=-RC_Velocity; Move_Z=-PI/2; break; case 5: Move_X=-RC_Velocity; Move_Z=0; break; case 6: Move_X=-RC_Velocity; Move_Z=+PI/2; break; case 7: Move_X=0; Move_Z=+PI/2; break; case 8: Move_X=+RC_Velocity; Move_Z=+PI/2; break; default: Move_X=0; Move_Z=0; break; } if (Flag_Left ==1) Move_Z= PI/2; //left rotation //左自转 else if(Flag_Right==1) Move_Z=-PI/2; //right rotation //右自转 } //Z-axis data conversion //Z轴数据转化 if(Car_Mode==Akm_Car) { //Ackermann structure car is converted to the front wheel steering Angle system target value, and kinematics analysis is pearformed //阿克曼结构小车转换为前轮转向角度 Move_Z=Move_Z*2/9; } else if(Car_Mode==Diff_Car||Car_Mode==Tank_Car||Car_Mode==FourWheel_Car) { if(Move_X<0) Move_Z=-Move_Z; //The differential control principle series requires this treatment //差速控制原理系列需要此处理 Move_Z=Move_Z*RC_Velocity/500; } //Unit conversion, mm/s -> m/s //单位转换,mm/s -> m/s Move_X=Move_X/1000; Move_Y=Move_Y/1000; Move_Z=Move_Z; //Control target value is obtained and kinematics analysis is performed //得到控制目标值,进行运动学分析 Drive_Motor(Move_X,Move_Y,Move_Z); } /************************************************************************** Function: Read the encoder value and calculate the wheel speed, unit m/s Input : none Output : none 函数功能:读取编码器数值并计算车轮速度,单位m/s 入口参数:无 返回 值:无 **************************************************************************/ void Get_Velocity_Form_Encoder(void) { //Retrieves the original data of the encoder //获取编码器的原始数据 float Encoder_A_pr,Encoder_B_pr,Encoder_C_pr,Encoder_D_pr; OriginalEncoder.A=Read_Encoder(2); OriginalEncoder.B=Read_Encoder(3); OriginalEncoder.C=Read_Encoder(4); OriginalEncoder.D=Read_Encoder(5); //Decide the encoder numerical polarity according to different car models //根据不同小车型号决定编码器数值极性 switch(Car_Mode) { case Mec_Car: Encoder_A_pr=OriginalEncoder.A; Encoder_B_pr=OriginalEncoder.B; Encoder_C_pr= -OriginalEncoder.C; Encoder_D_pr= -OriginalEncoder.D; break; case Omni_Car: Encoder_A_pr=-OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B; Encoder_C_pr= -OriginalEncoder.C; Encoder_D_pr= OriginalEncoder.D; break; case Akm_Car: Encoder_A_pr=OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B; Encoder_C_pr= OriginalEncoder.C; Encoder_D_pr= OriginalEncoder.D; break; case Diff_Car: Encoder_A_pr=OriginalEncoder.A; Encoder_B_pr=-OriginalEncoder.B; Encoder_C_pr= OriginalEncoder.C; Encoder_D_pr= OriginalEncoder.D; break; case FourWheel_Car: Encoder_A_pr=OriginalEncoder.A; Encoder_B_pr=OriginalEncoder.B; Encoder_C_pr= -OriginalEncoder.C; Encoder_D_pr= -OriginalEncoder.D; break; case Tank_Car: Encoder_A_pr=OriginalEncoder.A; Encoder_B_pr= -OriginalEncoder.B; Encoder_C_pr= OriginalEncoder.C; Encoder_D_pr= OriginalEncoder.D; break; } //The encoder converts the raw data to wheel speed in m/s //编码器原始数据转换为车轮速度,单位m/s MOTOR_A.Encoder= Encoder_A_pr*CONTROL_FREQUENCY*Wheel_perimeter/Encoder_precision; MOTOR_B.Encoder= Encoder_B_pr*CONTROL_FREQUENCY*Wheel_perimeter/Encoder_precision; MOTOR_C.Encoder= Encoder_C_pr*CONTROL_FREQUENCY*Wheel_perimeter/Encoder_precision; MOTOR_D.Encoder= Encoder_D_pr*CONTROL_FREQUENCY*Wheel_perimeter/Encoder_precision; } /************************************************************************** Function: Smoothing the three axis target velocity Input : Three-axis target velocity Output : none 函数功能:对三轴目标速度做平滑处理 入口参数:三轴目标速度 返回 值:无 **************************************************************************/ void Smooth_control(float vx,float vy,float vz) { float step=0.05; if (vx>0) smooth_control.VX+=step; else if(vx<0) smooth_control.VX-=step; else if(vx==0) smooth_control.VX=smooth_control.VX*0.9f; if (vy>0) smooth_control.VY+=step; else if(vy<0) smooth_control.VY-=step; else if(vy==0) smooth_control.VY=smooth_control.VY*0.9f; if (vz>0) smooth_control.VZ+=step; else if(vz<0) smooth_control.VZ-=step; else if(vz==0) smooth_control.VZ=smooth_control.VZ*0.9f; smooth_control.VX=target_limit_float(smooth_control.VX,-float_abs(vx),float_abs(vx)); smooth_control.VY=target_limit_float(smooth_control.VY,-float_abs(vy),float_abs(vy)); smooth_control.VZ=target_limit_float(smooth_control.VZ,-float_abs(vz),float_abs(vz)); } /************************************************************************** Function: Floating-point data calculates the absolute value Input : float Output : The absolute value of the input number 函数功能:浮点型数据计算绝对值 入口参数:浮点数 返回 值:输入数的绝对值 **************************************************************************/ float float_abs(float insert) { if(insert>=0) return insert; else return -insert; } /************************************************************************** Function: PS2_Control Input : none Output : none 函数功能:PS2手柄控制 入口参数: 无 返回 值:无 **************************************************************************/ void PS2_Control(void) { int LY,RX,LX; //手柄ADC的值 int Threshold=20; //阈值,忽略摇杆小幅度动作 static float Key1_Count = 0,Key2_Count = 0; //用于控制读取摇杆的速度 //转化为128到-128的数值 LY=-(PS2_LY-128);//左边Y轴控制前进后退 RX=-(PS2_RX-128);//右边X轴控制转向 LX=-(PS2_LX-128);//左边X轴控制转向,麦轮和全向小车专用 if(LY>-Threshold&&LY<Threshold) LY=0; if(RX>-Threshold&&RX<Threshold) RX=0; //忽略摇杆小幅度动作 if(LX>-Threshold&&LX<Threshold) LX=0; if(Strat) //按下start键才可以控制小车 { if (PS2_KEY == PSB_L1) //按下左1键加速(按键在顶上) { if((++Key1_Count) == 20) //调节按键反应速度 { PS2_KEY = 0; Key1_Count = 0; if((PS2_Velocity += X_Step)>MAX_RC_Velocity) //前进最大速度1230 PS2_Velocity = MAX_RC_Velocity; if(Car_Mode != Akm_Car) //非阿克曼车可调节转向速度 { if((PS2_Turn_Velocity += Z_Step)>MAX_RC_Turn_Bias) //转向最大速度325 PS2_Turn_Velocity = MAX_RC_Turn_Bias; } } } else if(PS2_KEY == PSB_R1) //按下右1键减速 { if((++Key2_Count) == 15) { PS2_KEY = 0; Key2_Count = 0; if((PS2_Velocity -= X_Step)<MINI_RC_Velocity) //前后最小速度110 PS2_Velocity = MINI_RC_Velocity; if(Car_Mode != Akm_Car) //非阿克曼车可调节转向速度 { if((PS2_Turn_Velocity -= Z_Step)<MINI_RC_Turn_Velocity)//转向最小速度45 PS2_Turn_Velocity = MINI_RC_Turn_Velocity; } } } else Key2_Count = 0,Key2_Count = 0; //读取到其他按键重新计数 Move_X = (PS2_Velocity/128)*LY; //速度控制,力度表示速度大小 if(Car_Mode == Mec_Car || Car_Mode == Omni_Car) { Move_Y = LX*PS2_Velocity/128; } else { Move_Y = 0; } if(Car_Mode == Akm_Car) //阿克曼车转向控制,力度表示转向角度 Move_Z = RX*(PI/2)/128*2/9; else //其他车型转向控制 { //if(Move_X>=0) Move_Z = (PS2_Turn_Velocity/128)*RX; //转向控制,力度表示转向速度 // else // Move_Z = -(PS2_Turn_Velocity/128)*RX; } } else { Move_X = 0; Move_Y = 0; Move_Z = 0; } Drive_Motor(Move_X,Move_Y,Move_Z); } /************************************************************************** 函数功能:CCD巡线,采集3个电感的数据并提取中线 入口参数:无 返回 值:无 **************************************************************************/ void Get_RC_CCD(void) { static float Bias,Last_Bias; float move_z=0; Move_X=RC_Velocity_CCD; //CCD巡线模式线速度 Bias=CCD_Median-64; //提取偏差,64为巡线的中心点 if(Car_Mode == Omni_Car) move_z=-Bias*Omni_Car_CCD_KP*0.1f-(Bias-Last_Bias)*Omni_Car_CCD_KI*0.1f; //PD控制,原理就是使得小车保持靠近巡线的中心点 else if(Car_Mode == Tank_Car) move_z=-Bias*Tank_Car_CCD_KP*0.1f-(Bias-Last_Bias)*Tank_Car_CCD_KI*0.1f; else move_z=-Bias*CCD_KP*0.1f-(Bias-Last_Bias)*CCD_KI*0.1f; Last_Bias=Bias; //保存上一次的偏差 if(Car_Mode==Mec_Car) { Move_Z=move_z*RC_Velocity_CCD/50000; //差速控制原理需要经过此处处理 } else if(Car_Mode==Omni_Car) { Move_Z=move_z*RC_Velocity_CCD/21000; //差速控制原理需要经过此处处理 } else if(Car_Mode==Akm_Car) { Move_Z=move_z/450; //差速控制原理需要经过此处处理 } else if(Car_Mode==Diff_Car) { if(Move_X<0) move_z=-move_z; Move_Z=move_z*RC_Velocity_CCD/67000; //差速控制原理需要经过此处处理 } else if(Car_Mode==Tank_Car) { if(Move_X<0) move_z=-move_z; Move_Z=move_z*RC_Velocity_CCD/50000; //差速控制原理需要经过此处处理 } else if(Car_Mode==FourWheel_Car) { if(Move_X<0) move_z=-move_z; Move_Z=move_z*RC_Velocity_CCD/20100; //差速控制原理需要经过此处处理 } //Z-axis data conversion //Z轴数据转化 //Unit conversion, mm/s -> m/s //单位转换,mm/s -> m/s Move_X=Move_X/1000; Move_Z=Move_Z; Move_Y=0; //Control target value is obtained and kinematics analysis is performed //得到控制目标值,进行运动学分析 Drive_Motor(Move_X,Move_Y,Move_Z); } /************************************************************************** 函数功能:电磁巡线,采集3个电感的数据并提取中线 入口参数:无 返回 值:无 **************************************************************************/ void Get_RC_ELE(void) { static float Bias,Last_Bias; float move_z=0; if(Detect_Barrier() == No_Barrier) { Move_X=RC_Velocity_ELE; //电磁巡线模式的速度 Bias=100-Sensor; //提取偏差 if(Car_Mode == Omni_Car) move_z=-Bias* Omni_Car_ELE_KP*0.08f-(Bias-Last_Bias)* Omni_Car_ELE_KI*0.05f; else if(Car_Mode == Tank_Car) move_z=-Bias*Tank_Car_ELE_KP*0.1f-(Bias-Last_Bias)*Tank_Car_ELE_KI*0.1f; else move_z=-Bias* ELE_KP*0.08f-(Bias-Last_Bias)* ELE_KI*0.05f; Last_Bias=Bias; Buzzer_Alarm(0); if(Car_Mode==Mec_Car) { Move_Z=move_z*RC_Velocity_ELE/50000; //差速控制原理需要经过此处处理 } else if(Car_Mode==Omni_Car) { Move_Z=move_z*RC_Velocity_ELE/10800; //差速控制原理需要经过此处处理 } else if(Car_Mode==Diff_Car) { if(Move_X<0) move_z=-move_z; Move_Z=move_z*RC_Velocity_ELE/45000; //差速控制原理需要经过此处处理 } else if(Car_Mode==Tank_Car) { if(Move_X<0) move_z=-move_z; Move_Z=move_z*RC_Velocity_ELE/28000; //差速控制原理需要经过此处处理 } else if(Car_Mode==FourWheel_Car) { if(Move_X<0) move_z=-move_z; Move_Z=move_z*RC_Velocity_ELE/20100; //差速控制原理需要经过此处处理 } else if(Car_Mode==Akm_Car) { Move_Z=move_z/450; //差速控制原理需要经过此处处理 } } else //有障碍物 { Buzzer_Alarm(100); //当电机使能的时候,有障碍物则蜂鸣器报警 Move_X = 0; Move_Z = 0; Move_Y = 0; } //Z-axis data conversion //Z轴数据转化 //Unit conversion, mm/s -> m/s //单位转换,mm/s -> m/s Move_X=Move_X/1000; Move_Z=Move_Z; Move_Y=0; //Control target value is obtained and kinematics analysis is performed //得到控制目标值,进行运动学分析 Drive_Motor(Move_X,Move_Y,Move_Z); } /************************************************************************** 函数功能:检测前方是否有障碍物 入口参数:无 返回 值:无 **************************************************************************/ u8 Detect_Barrier(void) { u16 i; u16 point_count = 0; if(Lidar_Detect == Lidar_Detect_ON) { for(i=0;i<1152;i++) //检测是否有障碍物 { if((Dataprocess[i].angle>300)||(Dataprocess[i].angle<60)) { if(0<Dataprocess[i].distance&&Dataprocess[i].distance<700)//700mm内是否有障碍物 point_count++; } } if(point_count > 0)//有障碍物 return Barrier_Detected; else return No_Barrier; } else return No_Barrier; } /************************************************************************** 函数功能:小车避障模式 入口参数:无 返回 值:无 **************************************************************************/ void Lidar_Avoid(void) { u16 i = 0; u8 calculation_angle_cnt = 0; //用于判断225个点中需要做避障的点 float angle_sum = 0; //粗略计算障碍物位于左或者右 u8 distance_count = 0; //距离小于某值的计数 for(i=0;i<1152;i++) //遍历120度范围内的距离数据,共120个点左右的数据 { if((Dataprocess[i].angle>300)||(Dataprocess[i].angle<60)) //避障角度在300-60之间 { if((0<Dataprocess[i].distance)&&(Dataprocess[i].distance<Avoid_Distance)) //距离小于450mm需要避障,只需要120度范围内点 { calculation_angle_cnt++; //计算距离小于避障距离的点个数 if(Dataprocess[i].angle<60) angle_sum += Dataprocess[i].angle; else if(Dataprocess[i].angle>300) angle_sum += (Dataprocess[i].angle-360); //300度到60度转化为-60度到60度 if(Dataprocess[i].distance<Avoid_Min_Distance) //记录小于200mm的点的计数 distance_count++; } } } Move_X = forward_velocity; if(calculation_angle_cnt == 0)//不需要避障 { Move_Z = 0; } else //当距离小于200mm,小车往后退 { if(distance_count>8) { Move_X = -forward_velocity; Move_Z = 0; } else { Move_X = 0; if(angle_sum > 0)//障碍物偏右 { if(Car_Mode == Mec_Car) //麦轮转弯需要把前进速度降低 Move_X = 0; else //其他车型保持原有车速 Move_X = forward_velocity; if(Car_Mode == Akm_Car) Move_Z = PI/4; else if(Car_Mode == Omni_Car) Move_Z=corner_velocity; else Move_Z=other_corner_velocity;//左转 } else //偏左 { if(Car_Mode == Mec_Car) Move_X = 0; else Move_X = forward_velocity; if(Car_Mode == Akm_Car) Move_Z = -PI/4; else if(Car_Mode == Omni_Car) Move_Z=-corner_velocity;//右转 else Move_Z=-other_corner_velocity; } } } Drive_Motor(Move_X,Move_Y,Move_Z); } /************************************************************************** 函数功能:小车跟随模式 入口参数:无 返回 值:无 **************************************************************************/ void Lidar_Follow(void) { static u16 cnt = 0; int i; int calculation_angle_cnt = 0; static float angle = 0; //避障的角度 static float last_angle = 0; // u16 mini_distance = 65535; static u8 data_count = 0; //用于滤除一写噪点的计数变量 //需要找出跟随的那个点的角度 for(i = 0; i < 1152; i++) { if((0<Dataprocess[i].distance)&&(Dataprocess[i].distance<Follow_Distance)) { calculation_angle_cnt++; if(Dataprocess[i].distance<mini_distance) { mini_distance = Dataprocess[i].distance; angle = Dataprocess[i].angle; } } } if(angle > 180) //0--360度转换成0--180;-180--0(顺时针) angle -= 360; if((angle-last_angle > 10)||(angle-last_angle < -10)) //做一定消抖,波动大于10度的需要做判断 { if(++data_count > 30) //连续30次采集到的值(300ms后)和上次的比大于10度,此时才是认为是有效值 { data_count = 0; last_angle = angle; } } else //波动小于10度的可以直接认为是有效值 { if(++data_count > 10) //连续10次采集到的值(100ms后),此时才是认为是有效值 { data_count = 0; last_angle = angle; } } if(calculation_angle_cnt < 8) //跟随距离小于8且当cnt>40的时候,认为在1600内没有跟随目标 { if(cnt < 40) cnt++; if(cnt >= 40) { Move_X = 0; Move_Z = 0; } } else { cnt = 0; if(Move_X > 0.06f || Move_X < -0.06f) //当Move_X有速度时,转向PID开始调整 { if(mini_distance < 700 && (last_angle > 60 || last_angle < -60)) { Move_Z = -0.0098f*last_angle; //当距离偏小且角度差距过大直接快速转向 } else { Move_Z = -Follow_Turn_PID(last_angle,0); //转向PID,车头永远对着跟随物品 } } else { Move_Z = 0; } if(angle>150 || angle<-150) //如果小车在后方60°需要反方向运动以及快速转弯 { Move_X = -Distance_Adjust_PID(mini_distance, Keep_Follow_Distance); Move_Z = -0.0098f*last_angle; } else { Move_X = Distance_Adjust_PID(mini_distance, Keep_Follow_Distance); //保持距离保持在500mm } Move_X = target_limit_float(Move_X,-amplitude_limiting,amplitude_limiting); //对前进速度限幅 } Drive_Motor(Move_X,Move_Y,Move_Z); } /************************************************************************** 函数功能:小车走直线模式 入口参数:无 返回 值:无 **************************************************************************/ void Lidar_along_wall(void) { static int determine; static u32 target_distance=0; u32 distance; u8 data_count = 0; //用于滤除一写噪点的计数变量 Move_X = forward_velocity; //初始速度 for(int j=0;j<1152;j++) //225 { if(Dataprocess[j].angle>268 && Dataprocess[j].angle<272) //取雷达的4度的点 { if(determine300||Dataprocess[i].angle<60) {//车前避障角度 300°-60° if(0<Dataprocess[i].distance&&Dataprocess[i].distance<avoid_distance) { avoid_point_count++;//需要避障的点数 if(Dataprocess[i].angle<60) { right_angle_sum+=Dataprocess[i].angle; } else if(Dataprocess[i].angle>300) { left_angle_sum+=(Dataprocess[i].angle-360);//300°到359°转化为-60°到-1° } if(Dataprocess[i].distance<Avoid_Min_Distance) {//小于最小避障距离 mini_distance_count++; } } } } if(*Vx>0&&avoid_point_count>8){//需要避障 if(mini_distance_count>=8)//距离小于最小转弯距离要求 { *Vx=*Vx*-0.75f;//后退 *Vz=0; } else { if(right_angle_sum+left_angle_sum>0) {//往左避让 *Vx=*Vx*0.5f;//避障的X轴速度是前进速度的一半 if(Car_Mode==Akm_Car){ *Vz=(PI/2)*4/9; }else{ *Vz=1; } }else{//往右避让 *Vx=*Vx*0.5f;//避障的X轴速度是前进速度的一半 if(Car_Mode==Akm_Car){ *Vz=(-PI/2)*4/9; }else{ *Vz=-1; } } } } } /************************************************************************** 函数功能:限制PWM赋值 入口参数:无 返回 值:无 **************************************************************************/ void Xianfu_Pwm(void) { int Amplitude_H1=1200, Amplitude_L1=300; //舵机脉宽极限值,即限制舵机转角13.5°-256.5°中心位置为750,运动范围为±450,(750-250)/90=5.5,5.5*80=450 int Amplitude_H2=1200, Amplitude_L2=300; //舵机脉宽极限值,即限制舵机转角9°-171°,中心位置为750,运动范围为±450,(750-250)/90=5.5,5.5*80=450 if(Target1<Amplitude_L1) Target1=Amplitude_L1; if(Target1>Amplitude_H1) Target1=Amplitude_H1; if(Target2<Amplitude_L2) Target2=Amplitude_L2; if(Target2>Amplitude_H2) Target2=Amplitude_H2; } /************************************************************************* 函数功能:位置式PID控制器 入口参数:编码器测量位置信息,目标位置 返回 值:电机PWM增量 **************************************************************************/ float Position_PID_1(float Position,float Target) { //增量输出 static float Bias,Pwm,Integral_bias,Last_Bias; Bias=Target-Position; //计算偏差 Integral_bias+=Bias; //求出偏差的积分 Pwm=Position_KP*Bias/100+Position_KI*Integral_bias/100+Position_KD*(Bias-Last_Bias)/100; //位置式PID控制器 Last_Bias=Bias; //保存上一次偏差 return Pwm; } /************************************************************************* 函数功能:位置式PID控制器 入口参数:编码器测量位置信息,目标位置 返回 值:电机PWM增量 **************************************************************************/ float Position_PID_2(float Position,float Target) { //增量输出 static float Bias,Pwm,Integral_bias,Last_Bias; Bias=Target-Position; //计算偏差 Integral_bias+=Bias; //求出偏差的积分 Pwm=Position_KP*Bias/100+Position_KI*Integral_bias/100+Position_KD*(Bias-Last_Bias)/100; //位置式PID控制器 Last_Bias=Bias; //保存上一次偏差 return Pwm; } /************************************************************************** 函数功能:限制速度 入口参数:无 返回 值:无 **************************************************************************/ void Xianfu_Velocity(void) { int Amplitude_H=Speed, Amplitude_L=-Speed; if(Velocity1<Amplitude_L) Velocity1=Amplitude_L; if(Velocity1>Amplitude_H) Velocity1=Amplitude_H; if(Velocity2<Amplitude_L) Velocity2=Amplitude_L; if(Velocity2>Amplitude_H) Velocity2=Amplitude_H; } /************************************************************************** 函数功能:赋值给PWM寄存器,并且判断转向 入口参数:左轮PWM、右轮PWM 返回 值:无 **************************************************************************/ void Set_Pwm_PTZ(float velocity1,float velocity2) { Position1+=velocity1; //速度的积分,得到舵机的位置 Position2+=velocity2; //赋值给STM32的寄存器 // TIM12->CCR1=Position1; //GPIOA8,云台舵机 // TIM12->CCR2=Position2; //GPIOA11,外臂舵机 TIM8->CCR1=Position1; //GPIOC6,云台舵机 TIM8->CCR2=Position2; //GPIOC7,外臂舵机 }看不懂啊,逐行解释

最新推荐

recommend-type

Drawingapp1-juxingQZQ.zip

Drawingapp1-juxingQZQ.zip
recommend-type

LASSO-CV与ADMM算法在R语言中的实现

标题:“thesis_admm_lasso-lassocv.glmnet”和描述中的“thesis_admm_lasso-lassocv.glmnet”暗示了本文档与R语言、ADMM(交替方向乘子法)、Lasso回归、Lasso交叉验证和Glmnet包有关。首先,我们将从这些关键词开始探讨,接着分析文件名“thesis_admm_lasso-lassocv.glmnet-main”。 ### 1. R语言 R是一种用于统计计算和图形的语言及环境。它广泛应用于数据挖掘、统计分析、报告撰写和图形展示。R语言有强大的社区支持,提供了大量用于数据分析的包,如Glmnet。 ### 2. ADMM(交替方向乘子法) ADMM是解决大规模优化问题的一种算法,特别适用于分布式计算和大规模问题。它将一个大问题分解为几个较小的子问题,这些子问题可以独立求解,然后交替地更新解。ADMM在处理稀疏编码、压缩感知和网络优化等问题时非常有效。Lasso回归和其他稀疏模型中,ADMM常用来求解优化问题。 ### 3. Lasso回归 Lasso回归(Least Absolute Shrinkage and Selection Operator)是一种回归分析方法,它通过引入L1正则化项对模型的参数进行约束,使得一些系数变为零,从而实现模型的稀疏性,帮助进行特征选择。Lasso回归是解决过拟合问题的常用手段,适用于特征选择和回归问题。 ### 4. Lasso交叉验证 为了得到一个泛化能力较强的Lasso模型,通常需要对模型参数进行选择,而交叉验证是进行模型选择的常用方法。Lasso交叉验证包括在不同的训练集和验证集上评估模型的性能,选择最佳的正则化参数lambda。这可以防止模型过度依赖特定的训练数据,从而在未知数据上具有更好的泛化性能。 ### 5. Glmnet包 Glmnet是R中用于拟合Lasso回归模型的包,它支持L1和L2正则化的广义线性模型。Glmnet实现了一种高效的坐标下降算法来解决Lasso和Elastic Net问题。Glmnet包在数据挖掘、生物信息学和统计学等多个领域有着广泛的应用。 ### 综合分析文件名“thesis_admm_lasso-lassocv.glmnet-main” 文件名暗示了一个以R语言完成的学术论文,研究了应用ADMM算法在Lasso回归模型中进行交叉验证的问题。这个论文可能展示了如何使用Glmnet包来处理大规模数据集,并且讨论了在模型训练过程中正则化参数的选择问题。ADMM算法可能被用来加速Lasso回归模型的训练过程,尤其是当数据集非常庞大时。 在这篇论文中,可能会讨论以下内容: - 如何运用ADMM算法优化Lasso回归模型的求解过程。 - 使用Lasso交叉验证方法来选择最佳的正则化参数。 - 对比传统的Lasso回归算法和使用ADMM优化后的算法在效率和准确性上的差异。 - 分析模型在不同数据集上的性能,包括过拟合情况和预测能力。 - 探讨Glmnet包的使用经验,以及如何通过该包来实现ADMM算法的整合和模型的训练。 - 论文可能还包含了对相关数学理论的深入讲解,例如稀疏模型的理论基础、交叉验证的数学原理以及ADMM算法的收敛性分析等。 总结来说,该文件可能是关于使用R语言和Glmnet包对大规模数据集执行Lasso回归,并运用ADMM算法以及交叉验证技术来优化模型的学术研究。这份研究可能对数据分析、机器学习和统计建模的专家具有较大的参考价值。
recommend-type

数据挖掘:概念、任务与挑战

# 数据挖掘:概念、任务与挑战 ## 一、数据挖掘中的关键分析方法 ### 1.1 异常检测 异常检测是识别数据集中不符合常规模式的数据点的过程。例如,如果数据集中的数字范围在 5 到 7 之间,那么数字 11 就是一个异常值。数据科学家和分析师会对异常检测产生好奇,因为他们想知道这种不规则性是否是由风险或欺诈引起的。他们会对数据进行更深入的分析,并将信息传递给安全团队,以便修复系统中的漏洞。异常检测不仅能让企业了解系统是否存在缺陷,还能帮助企业理解业务策略某些方面失败的原因。在处理大量数据时,尤其是在数据挖掘过程中,小范围的异常情况是不可避免的,这些异常有时是数据模式的偏差,有时则是完全随
recommend-type

口语化一点,我是用来面试的

以下是一些用于面试的口语化Vue知识: ### Vue基础 Vue是一个用于构建用户界面的渐进式JavaScript框架。它的核心库只关注视图层,很容易与其它库或已有项目整合。和其它大型框架不同,Vue 被设计为可以自底向上逐层应用。简单来说,你可以用它来做小的交互组件,也可以用它来构建大型单页面应用。 ### 响应式原理 Vue的响应式原理主要是基于Object.defineProperty()方法。当一个Vue实例创建时,Vue会遍历data选项中的所有属性,使用Object.defineProperty()将这些属性转换为getter/setter。这样,当这些属性的值发生变化时,V
recommend-type

Coursera课程项目:开发数据产品周总结

### 知识点详细解析 #### 标题解析 - **开发数据产品周4**:本标题说明了内容的范围和特定的学习周次。结合描述内容,可以推断这是一个课程项目,重点在于如何开发数据产品,并且是特定于“开发数据产品”课程的第四周所涉及的内容。 #### 描述解析 - **本演示文稿和相关的Shiny应用程序总结了Coursera课程:开发数据产品**:这部分内容告诉我们该文件是关于如何使用Shiny应用程序来总结和展示“开发数据产品”课程的学习成果。Shiny是R语言的一个开源Web应用程序框架,用于创建交互式的数据可视化和Web应用程序。 - **该项目包括**: - **本演示文稿,提供概述,代码示例和链接**:这里提到的演示文稿可能是用于向观众解释项目概念和具体实施步骤的PPT文件或者网页文档,其中包含代码示例和项目中所使用的资源链接。 - **Shinyapp.io上托管的Shiny应用程序**:Shinyapp.io是RStudio公司提供的一个在线平台,允许用户免费托管和分享Shiny应用程序。这说明项目成果可以通过这个平台被访问。 - **通过github托管的相应源代码**:GitHub是一个代码托管平台,支持版本控制和协作,用户可以在上面找到源代码以及相关的代码版本历史。 - **用户界面示例**:这部分描述可能是在讲述如何设计和实现一个用户友好的界面,这是Shiny应用程序开发中的一个重要环节。 - **服务器**:在Shiny应用中,服务器部分负责处理客户端发出的请求,执行相应的R代码,并将结果返回给用户界面。这可能涉及到使用`reactive`表达式和相关的数据处理技术。 - **library( plotly )**:这是R语言中的一个库,专门用于创建交互式图表,用户可以缩放、点击和悬停,以获取更多信息。 - **library( colourpicker )**:该库为R用户提供了一个颜色选择器界面,用于数据可视化中选择颜色。 - **library( ggplot2 )**:ggplot2是R中一个非常流行的绘图系统,用于创建复杂的图形层。 - **library( gapminder )**:这个库提供了一个用于数据可视化的数据集,通常包含世界各国的统计数据。 - **library( shinycustomloader )**:这可能是一个自定义库,用于在Shiny应用中添加自定义加载器,以改善用户体验,特别是在数据处理或加载耗时较长时。 - **library( DT )**:DT是一个用于创建交互式表格的R包,可以实现排序、搜索和翻页等功能。 - **server &lt;- function ( input , output )**:这是定义Shiny应用服务器端逻辑的标准方式,其中`reactive`用于创建响应式表达式,根据用户的输入动态生成数据输出。 #### 标签解析 - **HTML**:标签可能表示文档中涉及到了HTML技术,这可能包括在Shiny应用程序用户界面中使用的HTML代码,或是描述Shiny应用中通过HTML输出的内容。 #### 压缩包子文件的文件名称列表解析 - **Developing-Data-Products-week-4-master**:文件名表明这是一个与“开发数据产品”课程的第四周相关的主项目文件。这可能是包含了所有项目相关文件的主目录,包括演示文稿、源代码、Shiny应用的代码等。 ### 总结 该文件是关于“开发数据产品”课程项目第四周的总结。项目核心内容包括一个演示文稿,通过Shinyapp.io托管的交互式Shiny应用程序,以及通过GitHub托管的源代码。演示文稿详细介绍了如何利用R语言及其相关的库(plotly、colourpicker、ggplot2、gapminder、shinycustomloader、DT)来构建一个数据产品。具体的技术实现涉及到设计用户界面、编写服务器端逻辑、使用各种数据可视化技术,并且考虑到用户体验的优化,如添加加载动画等。此外,内容还涉及到了HTML的使用,可能与Shiny应用的界面布局和内容展示有关。整个项目是一个完整的数据产品开发案例,从概念设计到实际应用都进行了详细的演示和讲解。
recommend-type

数据科学:统计知识与技能要求全解析

### 数据科学:统计知识与技能要求全解析 #### 1. 数据科学中的统计概念 数据科学并非全新概念,多数统计学家可胜任数据科学家一职。数据科学广泛运用统计学概念,因其是处理和解读数据集信息的最佳工具。若想掌握数据科学并成为该领域专家,需深入学习统计学知识。数据科学中重要的统计方面包括描述性统计和推断性统计。 ##### 1.1 描述性统计 描述性统计旨在通过数值表示或图表,对数据进行定量总结,便于轻松读取数据。需学习的相关主题如下: - **正态分布**:也称为高斯分布,是统计学中常用的连续分布。符合正态分布的数据集在图表上呈现为钟形曲线,数据点在曲线中心达到峰值,代表数据集的中心。当
recommend-type

dify本地部署培训课件生成

### 本地部署 Dify 平台的教程与培训资源 Dify 是一个开源的大模型应用开发平台,支持本地部署,为开发者和企业提供了极大的灵活性和安全性。本地部署 Dify 可以实现私有化 AI 应用的构建,适用于企业内部的知识库管理、自动化工作流以及智能助手开发等场景。 #### 本地部署的基本流程 1. **环境准备** Dify 支持多种部署方式,包括 Docker 部署、Kubernetes 部署以及源码部署。推荐使用 Docker 部署以简化依赖管理和环境配置。 系统要求包括: - 操作系统:Linux(推荐 Ubuntu 20.04 或更高版本)、macO
recommend-type

GitHub入门教程与Java实践

从提供的文件信息来看,标题为 "aula1-github" 且描述同标题,标签为 "Java",而压缩包子文件的文件名称列表包含 "aula1-github-master"。这意味着当前讨论的主题很可能是一个与Java相关的GitHub项目,而且项目名称可能就是 "aula1-github"。以下将从多个角度详细探讨与该主题相关知识点。 ### 1. GitHub 概述 GitHub是一个基于Git的代码托管平台,它允许开发者存储和管理他们的源代码,并支持版本控制和协作。GitHub提供免费账户以及私人仓库的付费计划。开发者可以在此平台上创建项目仓库,进行代码的提交、分支管理、合并请求、问题跟踪和代码审查等功能。 ### 2. Git 基础知识 Git是一个分布式版本控制系统,最初由Linus Torvalds为协助Linux内核开发而设计。其核心功能是版本控制,记录源代码文件的变更历史。Git使用的是仓库的概念,一个仓库包含了所有的文件记录、提交历史等信息。开发者通过克隆仓库到本地,进行代码修改和提交,最终将改动推送回远程仓库。 ### 3. Java 语言概述 Java是一种广泛使用的面向对象的编程语言,具有跨平台的特性。它由Sun Microsystems公司于1995年发布,后被Oracle公司收购。Java语言设计哲学强调安全性、复用性和面向对象性。Java的开发和运行需要Java虚拟机(JVM),它负责将Java字节码转换为具体操作系统的机器码。 ### 4. Git 与 GitHub 在 Java 开发中的应用 在使用Java语言开发过程中,开发者往往将GitHub作为代码的托管中心。通过Git与GitHub,Java开发者可以: - 创建项目仓库,并管理代码版本。 - 同事之间进行代码的共享和协作。 - 使用分支(Branch)功能进行新特性的开发或修复bug,而不影响主分支。 - 发起和处理合并请求(Pull Requests),以便他人审核代码改动。 - 利用GitHub的Issue跟踪问题,管理软件缺陷和用户反馈。 - 利用GitHub Pages创建项目文档或个人主页。 ### 5. Java 开发者在 GitHub 上的实践 - **项目初始化**: 开发者首先需要创建一个项目仓库,然后通过Git命令将项目代码克隆到本地。 - **代码编写**: 在本地编写或修改Java代码,并利用IDE(如Eclipse或IntelliJ IDEA)等工具进行编译和运行。 - **版本控制**: 开发者会定期将代码提交到本地仓库,并使用Git命令进行版本控制。 - **分支管理**: 为了隔离功能开发和bug修复,Java开发者会在不同的分支上工作。 - **代码共享**: 完成开发后,开发者会将本地仓库的改动推送(push)到GitHub上的远程仓库。 - **代码审查**: 在发起合并请求时,其他团队成员会进行代码审查,以保证代码质量和一致性。 ### 6. GitHub 特色功能 - **Wiki**: 许多Java项目会使用GitHub的Wiki功能来编写项目文档,帮助用户和开发者了解项目信息。 - **Pages**: GitHub Pages可以用来托管项目网页、个人博客或展示站点。 - **Webhooks 和 API**: 通过这些高级功能,Java开发者可以集成外部工具或服务,实现自动化构建、测试和部署等。 - **Actions**: GitHub Actions为Java项目提供了持续集成和持续部署(CI/CD)的工作流自动化。 ### 7. 版本控制最佳实践 对于使用Git进行版本控制的Java项目,以下是一些最佳实践建议: - 定期提交代码到本地仓库,保持提交历史清晰。 - 在提交前进行代码审查,以减少错误和提升代码质量。 - 使用描述清晰的提交信息,说明所做改动的目的和内容。 - 避免将大型文件直接提交到仓库,使用.gitignore文件忽略这些文件。 - 在推送改动到GitHub之前,尽量保持本地分支与远程主分支同步。 ### 结语 综上所述,"aula1-github" 项目很可能是一个Java开发者使用GitHub作为代码托管和版本控制的平台。通过Git和GitHub,开发者不仅能够更好地管理代码版本,还能实现高效协作。了解和掌握这些工具和技术对于现代软件开发至关重要。
recommend-type

数据挖掘与分析:从数据中洞察价值

# 数据挖掘与分析:从数据中洞察价值 ## 一、数据挖掘的重要性与基础概念 在当今世界,一切决策都围绕着数据展开。优质的数据决策能够推动世界朝着更有利于人类的方向发展。如今,我们拥有海量的数据,但这些数据需要进行整理和解读,若能完美完成这项任务,人类将从中受益匪浅。Python 及其数据可视化库为热衷于引领组织走向成功的数据科学家们提供了强大的工具。 ### (一)数据与挖掘的定义 要更好地理解数据挖掘,我们可以将其拆分为“数据”和“挖掘”两个词。信息以特定方式格式化和结构化后被称为数据,在 21 世纪,数据大多指通过数字媒介存储和传输的信息。而“挖掘”通常指从地球深处提取物质,如煤矿开采
recommend-type

selenium 对应的edge浏览器版本

Selenium 支持的 Microsoft Edge 浏览器版本主要取决于 Edge 浏览器的内核变化以及 WebDriver 的更新情况。以下是关于 Selenium 与 Microsoft Edge 浏览器兼容性的详细说明: Microsoft Edge 在 2020 年之前使用的是 EdgeHTML 内核,而在 2020 年之后改用 Chromium 内核。这一变化对 Selenium 的支持方式产生了重要影响。基于 Chromium 内核的 Edge 浏览器与 Chrome 浏览器的兼容性更高,因此 Selenium 可以通过 `msedgedriver` 来实现对 Edge 浏览