完善阿克曼控制与高速串口遥测
- 校正舵机中位、转向符号和阿克曼后轮差速模型\n- 增加航向角速度辅助及遥控通道调试开关\n- 将速度环提升至 200Hz,并按实际 dt 计算 PI 积分\n- 将 IMU 启动校准缩短为 2 秒\n- 为 USART3 增加 DMA 发送和 MCU 采样时间戳
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
build/
|
||||
.firecrawl/
|
||||
.DS_Store
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,10 +22,10 @@ float target_limit_float(float insert,float low,float high);
|
||||
int target_limit_int(int insert,int low,int high);
|
||||
u8 Turn_Off( int voltage);
|
||||
u32 myabs(long int a);
|
||||
int Incremental_PI_A (float Encoder,float Target);
|
||||
int Incremental_PI_B (float Encoder,float Target);
|
||||
int Incremental_PI_C (float Encoder,float Target);
|
||||
int Incremental_PI_D (float Encoder,float Target);
|
||||
int Incremental_PI_A (float Encoder,float Target,float dt);
|
||||
int Incremental_PI_B (float Encoder,float Target,float dt);
|
||||
int Incremental_PI_C (float Encoder,float Target,float dt);
|
||||
int Incremental_PI_D (float Encoder,float Target,float dt);
|
||||
void Get_RC(void);
|
||||
void Remote_Control(void);
|
||||
void Drive_Motor(float Vx,float Vy,float Vz);
|
||||
@@ -36,4 +36,3 @@ void PS2_control(void);
|
||||
float float_abs(float insert);
|
||||
void robot_mode_check(void);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
#include "system.h"
|
||||
|
||||
//Parameter structure of robot
|
||||
//机器人参数结构体
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ṹ<EFBFBD><EFBFBD>
|
||||
typedef struct
|
||||
{
|
||||
float WheelSpacing; //Wheelspacing, Mec_Car is half wheelspacing //轮距 麦轮车为半轮距
|
||||
float AxleSpacing; //Axlespacing, Mec_Car is half axlespacing //轴距 麦轮车为半轴距
|
||||
int GearRatio; //Motor_gear_ratio //电机减速比
|
||||
int EncoderAccuracy; //Number_of_encoder_lines //编码器精度(编码器线数)
|
||||
float WheelDiameter; //Diameter of driving wheel //主动轮直径
|
||||
float OmniTurnRadiaus; //Rotation radius of omnidirectional trolley //全向轮小车旋转半径
|
||||
float WheelSpacing; //Wheelspacing, Mec_Car is half wheelspacing //<EFBFBD>־<EFBFBD> <20><><EFBFBD>ֳ<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>־<EFBFBD>
|
||||
float AxleSpacing; //Axlespacing, Mec_Car is half axlespacing //<EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ֳ<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD>
|
||||
int GearRatio; //Motor_gear_ratio //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٱ<EFBFBD>
|
||||
int EncoderAccuracy; //Number_of_encoder_lines //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||
float WheelDiameter; //Diameter of driving wheel //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><EFBFBD>
|
||||
float OmniTurnRadiaus; //Rotation radius of omnidirectional trolley //ȫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD>뾶
|
||||
}Robot_Parament_InitTypeDef;
|
||||
|
||||
// Encoder structure
|
||||
//编码器结构体
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ṹ<EFBFBD><EFBFBD>
|
||||
typedef struct
|
||||
{
|
||||
int A;
|
||||
@@ -27,28 +27,74 @@ typedef struct
|
||||
|
||||
//The minimum turning radius of Ackermann models is determined by the mechanical structure:
|
||||
//the maximum Angle of the wheelbase, wheelbase and front wheels
|
||||
//阿克曼车型的最小转弯半径,由机械结构决定:轮距、轴距、前轮最大转角
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD>Сת<EFBFBD><EFBFBD>뾶<EFBFBD><EFBFBD><EFBFBD>ɻ<EFBFBD>е<EFBFBD>ṹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־ࡢ<EFBFBD><EFBFBD>ࡢǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD>
|
||||
#define MINI_AKM_MIN_TURN_RADIUS 0.350f
|
||||
|
||||
//Wheelspacing, Mec_Car is half wheelspacing
|
||||
//轮距 麦轮是一半
|
||||
//<EFBFBD>־<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
|
||||
//#define MEC_wheelspacing 0.109
|
||||
#define MEC_wheelspacing 0.0930 //修正2021.03.30
|
||||
#define Akm_wheelspacing 0.162f
|
||||
#define MEC_wheelspacing 0.0930 //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>2021.03.30
|
||||
#define Akm_wheelspacing 0.160f
|
||||
#define Diff_wheelSpacing 0.177f
|
||||
#define Four_Mortor_wheelSpacing 0.26f
|
||||
#define Tank_wheelSpacing 0.235f
|
||||
|
||||
//Axlespacing, Mec_Car is half axlespacing
|
||||
//轴距 麦轮是一半
|
||||
//<EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
|
||||
#define MEC_axlespacing 0.085
|
||||
#define Akm_axlespacing 0.158f
|
||||
#define Akm_axlespacing 0.160f
|
||||
// Set to 1 to drive the Ackermann servo directly from TIM8 channel 1 (bench debug).
|
||||
// Set to 0 to use the calibrated curvature->servo model in balance.c.
|
||||
#define AKM_SERVO_DEBUG_REMOTE_CH1 0
|
||||
|
||||
// Ackermann control law selector (mutually exclusive with the debug switch above):
|
||||
// 0 = calibrated kinematic model: kappa = wz/Vx -> quadratic servo fit,
|
||||
// rear wheels get Ackermann differential. Physically correct.
|
||||
// 1 = direct passthrough (tuning/debug): Vz is linearly mapped across the
|
||||
// full servo travel, Vx is sent to both drive wheels unchanged (no
|
||||
// differential, no curvature math). Handy for isolating servo/motor.
|
||||
#define AKM_DIRECT_MAP 0
|
||||
// Direct-map input span: |Vz| >= AKM_DIRECT_VZ_FULL maps to the servo end stop.
|
||||
// Vz > 0 = left (ROS), which maps toward AKM_SERVO_MIN (left end).
|
||||
// TUNING KNOB (Mode 1 & Mode 2 share it): set this to the MAX angular.z [rad/s]
|
||||
// your commander actually sends, so a full stick/command uses the full servo
|
||||
// travel. Too high -> steering stays small; too low -> servo saturates (always
|
||||
// full lock) and loses proportional control. Vz arrives in rad/s (usartx.c
|
||||
// XYZ_Target_Speed_transition: raw/1000).
|
||||
#define AKM_DIRECT_VZ_FULL 1.0f
|
||||
|
||||
// Ackermann yaw-rate closed-loop assist (Mode 2), mutually exclusive with
|
||||
// AKM_DIRECT_MAP (direct-map wins if both are 1). "Front wheel does the main
|
||||
// steering, rear wheels add a yaw-rate differential" -- a simplified torque-
|
||||
// vectoring / yaw-rate closed loop:
|
||||
// path -> (Vx, kappa_cmd) -> servo main steering (calibrated fit)
|
||||
// + IMU yaw-rate PI differential on the rear wheels.
|
||||
// Degenerates EXACTLY to the Mode-0 Ackermann differential when
|
||||
// AKM_YAW_FF_ALPHA = 1 and AKM_YAW_KP = AKM_YAW_KI = 0.
|
||||
#define AKM_YAW_ASSIST 1
|
||||
// PI gains on the yaw-rate error e_r = r_ref - r_imu [rad/s], output in m/s.
|
||||
#define AKM_YAW_KP 0.10f
|
||||
#define AKM_YAW_KI 0.00f
|
||||
// Feedforward blend: 0 = pure IMU feedback, 1 = full geometric differential.
|
||||
#define AKM_YAW_FF_ALPHA 0.00f
|
||||
// Below this |Vx| the yaw loop is frozen (integrator reset, no differential).
|
||||
#define AKM_YAW_MIN_SPEED 0.10f
|
||||
// |dv| clamp as a fraction of |Vx|, so the differential cannot stall a wheel.
|
||||
#define AKM_YAW_MAX_DIFF_RATIO 0.35f
|
||||
// gyro[2] LSB -> rad/s at FS +-500 dps (see MPU6050.c: FS_500 -> /3754.9).
|
||||
#define AKM_GYRO_Z_TO_RADPS 3754.9f
|
||||
// Light first-order low-pass on the measured yaw rate (0 = none, 1 = no filter
|
||||
// lag). r_f += beta*(r_meas - r_f). ~0.3 gives gentle smoothing at 200 Hz.
|
||||
#define AKM_YAW_IMU_LPF 0.30f
|
||||
// Flip to -1.0f if the IMU +z spins opposite to the ROS convention (+ = left).
|
||||
// MUST be verified on hardware: command a left turn and confirm gyro[2] > 0.
|
||||
#define AKM_GYRO_Z_SIGN (+1.0f)
|
||||
#define Diff_axlespacing 0.155f
|
||||
#define Four_Mortor__axlespacing 0.28f
|
||||
#define Tank_axlespacing 0.222f
|
||||
|
||||
//Motor_gear_ratio
|
||||
//电机减速比
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٱ<EFBFBD>
|
||||
#define HALL_30F 30
|
||||
#define HALL_60F 60
|
||||
#define MD36N_5_18 5.18
|
||||
@@ -59,12 +105,12 @@ typedef struct
|
||||
#define MD60N_47 47
|
||||
|
||||
//Number_of_encoder_lines
|
||||
//编码器精度
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define Photoelectric_500 500
|
||||
#define Hall_13 13
|
||||
|
||||
//Mecanum wheel tire diameter series
|
||||
//麦轮轮胎直径
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ̥<EFBFBD><EFBFBD>
|
||||
#define Mecanum_60 0.060f
|
||||
#define Mecanum_75 0.075f
|
||||
#define Mecanum_100 0.100f
|
||||
@@ -72,7 +118,7 @@ typedef struct
|
||||
#define Mecanum_152 0.152f
|
||||
|
||||
//Omni wheel tire diameter series
|
||||
//轮径全向轮直径系列
|
||||
//<EFBFBD>־<EFBFBD>ȫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><EFBFBD>ϵ<EFBFBD><EFBFBD>
|
||||
#define FullDirecion_60 0.060
|
||||
#define FullDirecion_75 0.075
|
||||
#define FullDirecion_127 0.127
|
||||
@@ -81,26 +127,26 @@ typedef struct
|
||||
#define FullDirecion_217 0.217
|
||||
|
||||
//Black tire, tank_car wheel diameter
|
||||
//黑色轮胎、履带车轮直径
|
||||
//<EFBFBD><EFBFBD>ɫ<EFBFBD><EFBFBD>̥<EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><EFBFBD>
|
||||
#define Black_WheelDiameter 0.065
|
||||
//#define Tank_WheelDiameter 0.047
|
||||
#define Tank_WheelDiameter 0.043
|
||||
|
||||
//Rotation radius of omnidirectional trolley
|
||||
//全向轮小车旋转半径
|
||||
//ȫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD>뾶
|
||||
#define Omni_Turn_Radiaus_109 0.109
|
||||
#define Omni_Turn_Radiaus_164 0.164
|
||||
#define Omni_Turn_Radiaus_180 0.180
|
||||
#define Omni_Turn_Radiaus_290 0.290
|
||||
|
||||
//The encoder octave depends on the encoder initialization Settings
|
||||
//编码器倍频数,取决于编码器初始化设置
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ڱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define EncoderMultiples 4
|
||||
//Encoder data reading frequency
|
||||
//编码器数据读取频率
|
||||
#define CONTROL_FREQUENCY 100
|
||||
//Wheel-speed control and encoder reading frequency
|
||||
//<EFBFBD><EFBFBD><EFBFBD>ٿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡƵ<EFBFBD><EFBFBD>
|
||||
#define CONTROL_FREQUENCY 200
|
||||
|
||||
//#define PI 3.1415f //PI //圆周率
|
||||
//#define PI 3.1415f //PI //Բ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
void Robot_Select(void);
|
||||
void Robot_Init(double wheelspacing, float axlespacing, float omni_turn_radiaus, float gearratio,float Accuracy,float tyre_diameter);
|
||||
|
||||
@@ -26,8 +26,8 @@ void show_task(void *pvParameters)
|
||||
|
||||
//开机时蜂鸣器短暂蜂鸣,开机提醒
|
||||
//The buzzer will beep briefly when the machine is switched on
|
||||
if(Time_count<50)Buzzer=1;
|
||||
else if(Time_count>=51 && Time_count<100)Buzzer=0;
|
||||
if(Time_count<(CONTROL_FREQUENCY/2))Buzzer=1;
|
||||
else if(Time_count>=(CONTROL_FREQUENCY/2) && Time_count<CONTROL_FREQUENCY)Buzzer=0;
|
||||
|
||||
if(LowVoltage_1==1 || LowVoltage_2==1)Buzzer_count=0;
|
||||
if(Buzzer_count<5)Buzzer_count++;
|
||||
@@ -340,5 +340,3 @@ void APP_Show(void)
|
||||
printf("{B%d:%d:%d}$",(int)gyro[0],(int)gyro[1],(int)gyro[2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
124
BALANCE/system.c
124
BALANCE/system.c
@@ -1,197 +1,203 @@
|
||||
#include "system.h"
|
||||
|
||||
//Robot software fails to flag bits
|
||||
//机器人软件失能标志位
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD>ܱ<EFBFBD>־λ
|
||||
u8 Flag_Stop=1;
|
||||
|
||||
//The ADC value is variable in segments, depending on the number of car models. Currently there are 6 car models
|
||||
//ADC值分段变量,取决于小车型号数量,目前有6种小车型号
|
||||
//ADCֵ<EFBFBD>ֶα<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><EFBFBD><EFBFBD>ͺ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀǰ<EFBFBD><EFBFBD>6<EFBFBD><EFBFBD>С<EFBFBD><EFBFBD><EFBFBD>ͺ<EFBFBD>
|
||||
int Divisor_Mode;
|
||||
|
||||
// Robot type variable
|
||||
//机器人型号变量
|
||||
//0=Mec_Car,1=Omni_Car,2=Akm_Car,3=Diff_Car,4=FourWheel_Car,5=Tank_Car
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͺű<EFBFBD><EFBFBD><EFBFBD>
|
||||
//0=Mec_Car<EFBFBD><EFBFBD>1=Omni_Car<EFBFBD><EFBFBD>2=Akm_Car<EFBFBD><EFBFBD>3=Diff_Car<EFBFBD><EFBFBD>4=FourWheel_Car<EFBFBD><EFBFBD>5=Tank_Car
|
||||
u8 Car_Mode=4;
|
||||
|
||||
//Servo control PWM value, Ackerman car special
|
||||
//舵机控制PWM值,阿克曼小车专用
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>PWMֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><EFBFBD>ר<EFBFBD><EFBFBD>
|
||||
int Servo = SERVO_INIT;
|
||||
|
||||
//Default speed of remote control car, unit: mm/s
|
||||
//遥控小车的默认速度,单位:mm/s
|
||||
//ң<EFBFBD><EFBFBD>С<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD><EFBFBD><EFBFBD>ٶȣ<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>mm/s
|
||||
float RC_Velocity=500;
|
||||
|
||||
//Vehicle three-axis target moving speed, unit: m/s
|
||||
//小车三轴目标运动速度,单位:m/s
|
||||
//С<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><EFBFBD><EFBFBD>˶<EFBFBD><EFBFBD>ٶȣ<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>m/s
|
||||
float Move_X, Move_Y, Move_Z;
|
||||
|
||||
//PID parameters of Speed control
|
||||
//速度控制PID参数
|
||||
float Velocity_KP=300,Velocity_KI=800;
|
||||
//Speed PI parameters: Ki is in PWM/(m/s*s) and multiplies measured dt.
|
||||
//<EFBFBD>ٶ<EFBFBD>PI<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ki<EFBFBD><EFBFBD>λΪPWM/(m/s*s)<29><><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>dt<64><74><EFBFBD>
|
||||
float Velocity_KP=300,Velocity_KI=80000;
|
||||
|
||||
//Smooth control of intermediate variables, dedicated to omni-directional moving cars
|
||||
//平滑控制中间变量,全向移动小车专用
|
||||
//ƽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD>С<EFBFBD><EFBFBD>ר<EFBFBD><EFBFBD>
|
||||
Smooth_Control smooth_control;
|
||||
|
||||
//The parameter structure of the motor
|
||||
//电机的参数结构体
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ṹ<EFBFBD><EFBFBD>
|
||||
Motor_parameter MOTOR_A,MOTOR_B,MOTOR_C,MOTOR_D;
|
||||
|
||||
/************ 小车型号相关变量 **************************/
|
||||
/************ С<EFBFBD><EFBFBD><EFBFBD>ͺ<EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD> **************************/
|
||||
/************ Variables related to car model ************/
|
||||
//Encoder accuracy
|
||||
//编码器精度
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
float Encoder_precision;
|
||||
//Wheel circumference, unit: m
|
||||
//轮子周长,单位:m
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>m
|
||||
float Wheel_perimeter;
|
||||
//Drive wheel base, unit: m
|
||||
//主动轮轮距,单位:m
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־࣬<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>m
|
||||
float Wheel_spacing;
|
||||
//The wheelbase of the front and rear axles of the trolley, unit: m
|
||||
//小车前后轴的轴距,单位:m
|
||||
//С<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>࣬<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>m
|
||||
float Axle_spacing;
|
||||
//All-directional wheel turning radius, unit: m
|
||||
//全向轮转弯半径,单位:m
|
||||
//ȫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD>뾶<EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>m
|
||||
float Omni_turn_radiaus;
|
||||
/************ 小车型号相关变量 **************************/
|
||||
/************ С<EFBFBD><EFBFBD><EFBFBD>ͺ<EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD> **************************/
|
||||
/************ Variables related to car model ************/
|
||||
|
||||
//PS2 controller, Bluetooth APP, aircraft model controller, CAN communication, serial port 1, serial port 5 communication control flag bit.
|
||||
//These 6 flag bits are all 0 by default, representing the serial port 3 control mode
|
||||
//PS2手柄、蓝牙APP、航模手柄、CAN通信、串口1、串口5通信控制标志位。这6个标志位默认都为0,代表串口3控制模式
|
||||
//PS2<EFBFBD>ֱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>APP<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD>ֱ<EFBFBD><EFBFBD><EFBFBD>CANͨ<EFBFBD>š<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>1<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>5ͨ<EFBFBD>ſ<EFBFBD><EFBFBD>Ʊ<EFBFBD>־λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>6<EFBFBD><EFBFBD><EFBFBD><EFBFBD>־λĬ<EFBFBD>϶<EFBFBD>Ϊ0<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ
|
||||
u8 PS2_ON_Flag=0, APP_ON_Flag=0, Remote_ON_Flag=0, CAN_ON_Flag=0, Usart1_ON_Flag, Usart5_ON_Flag;
|
||||
|
||||
//Bluetooth remote control associated flag bits
|
||||
//蓝牙遥控相关的标志位
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ң<EFBFBD><EFBFBD><EFBFBD><EFBFBD>صı<EFBFBD>־λ
|
||||
u8 Flag_Left, Flag_Right, Flag_Direction=0, Turn_Flag;
|
||||
|
||||
//Sends the parameter's flag bit to the Bluetooth APP
|
||||
//向蓝牙APP发送参数的标志位
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>APP<EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD>־λ
|
||||
u8 PID_Send;
|
||||
|
||||
//The PS2 gamepad controls related variables
|
||||
//PS2手柄控制相关变量
|
||||
//PS2<EFBFBD>ֱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD>
|
||||
float PS2_LX,PS2_LY,PS2_RX,PS2_RY,PS2_KEY;
|
||||
|
||||
//Self-check the relevant flag variables
|
||||
//自检相关标志变量
|
||||
//<EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
int Check=0, Checking=0, Checked=0, CheckCount=0, CheckPhrase1=0, CheckPhrase2=0;
|
||||
|
||||
//Check the result code
|
||||
//自检结果代码
|
||||
//<EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
long int ErrorCode=0;
|
||||
|
||||
void systemInit(void)
|
||||
{
|
||||
|
||||
// //Interrupt priority group setti ng
|
||||
// //中断优先级分组设置
|
||||
// //<EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
|
||||
//
|
||||
// //Delay function initialization
|
||||
// //延时函数初始化
|
||||
// //<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||
delay_init(168);
|
||||
|
||||
//Initialize the hardware interface connected to the LED lamp
|
||||
//初始化与LED灯连接的硬件接口
|
||||
//<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>LED<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
||||
LED_Init();
|
||||
|
||||
//Initialize the hardware interface connected to the buzzer
|
||||
//初始化与蜂鸣器连接的硬件接口
|
||||
//<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
||||
Buzzer_Init();
|
||||
|
||||
//Initialize the hardware interface connected to the enable switch
|
||||
//初始化与使能开关连接的硬件接口
|
||||
//<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ܿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
||||
Enable_Pin();
|
||||
|
||||
//Initialize the hardware interface connected to the OLED display
|
||||
//初始化与OLED显示屏连接的硬件接口
|
||||
//<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>OLED<EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
||||
OLED_Init();
|
||||
|
||||
//Initialize the hardware interface connected to the user's key
|
||||
//初始化与用户按键连接的硬件接口
|
||||
//<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
||||
KEY_Init();
|
||||
|
||||
//Serial port 1 initialization, communication baud rate 115200,
|
||||
//can be used to communicate with ROS terminal
|
||||
//串口1初始化,通信波特率115200,可用于与ROS端通信
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD>Ų<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>115200<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ROS<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>
|
||||
uart1_init(115200);
|
||||
|
||||
//Serial port 2 initialization, communication baud rate 9600,
|
||||
//used to communicate with Bluetooth APP terminal
|
||||
//串口2初始化,通信波特率9600,用于与蓝牙APP端通信
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD>Ų<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>9600<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>APP<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>
|
||||
uart2_init(9600);
|
||||
|
||||
//Serial port 3 is initialized and the baud rate is 115200.
|
||||
//Serial port 3 is the default port used to communicate with ROS terminal
|
||||
//串口3初始化,通信波特率115200,串口3为默认用于与ROS端通信的串口
|
||||
uart3_init(115200);
|
||||
//Serial port 3 is initialized and the baud rate is 921600.
|
||||
//Serial port 3 is the default port used to communicate with ROS terminal.
|
||||
//NOTE: the ROS side must open this port at 921600 to match.
|
||||
//<2F><><EFBFBD><EFBFBD>3<EFBFBD><33>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>ͨ<EFBFBD>Ų<EFBFBD><C5B2><EFBFBD><EFBFBD><EFBFBD>921600<30><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3ΪĬ<CEAA><C4AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ROS<4F><53>ͨ<EFBFBD>ŵĴ<C5B5><C4B4>ڡ<EFBFBD>
|
||||
//ע<>⣺ROS <20>˴<CBB4><F2BFAAB4><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD> 921600<30><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0>벻ƥ<EBB2BB>䡣
|
||||
uart3_init(921600);
|
||||
|
||||
//Serial port 5 initialization, communication baud rate 115200,
|
||||
//can be used to communicate with ROS terminal
|
||||
//串口5初始化,通信波特率115200,可用于与ROS端通信
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>5<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD>Ų<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>115200<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ROS<EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>
|
||||
uart5_init(115200);
|
||||
|
||||
//ADC pin initialization, used to read the battery voltage and potentiometer gear,
|
||||
//potentiometer gear determines the car after the boot of the car model
|
||||
//ADC引脚初始化,用于读取电池电压与电位器档位,电位器档位决定小车开机后的小车适配型号
|
||||
//ADC<EFBFBD><EFBFBD><EFBFBD>ų<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD>ȡ<EFBFBD><EFBFBD>ص<EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͺ<EFBFBD>
|
||||
Adc_Init();
|
||||
Adc_POWER_Init();
|
||||
|
||||
//Initialize the CAN communication interface
|
||||
//CAN通信接口初始化
|
||||
//CANͨ<EFBFBD>Žӿڳ<EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||
CAN1_Mode_Init(1,7,6,3,0);
|
||||
|
||||
//According to the tap position of the potentiometer, determine which type of car needs to be matched,
|
||||
//and then initialize the corresponding parameters
|
||||
//根据电位器的档位判断需要适配的是哪一种型号的小车,然后进行对应的参数初始化
|
||||
//<EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>λ<EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ͺŵ<EFBFBD>С<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>Ӧ<EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||
Robot_Select();
|
||||
|
||||
//Encoder A is initialized to read the real time speed of motor C
|
||||
//编码器A初始化,用于读取电机C的实时速度
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>C<EFBFBD><EFBFBD>ʵʱ<EFBFBD>ٶ<EFBFBD>
|
||||
Encoder_Init_TIM2();
|
||||
//Encoder B is initialized to read the real time speed of motor D
|
||||
//编码器B初始化,用于读取电机D的实时速度
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>D<EFBFBD><EFBFBD>ʵʱ<EFBFBD>ٶ<EFBFBD>
|
||||
Encoder_Init_TIM3();
|
||||
//Encoder C is initialized to read the real time speed of motor B
|
||||
//编码器C初始化,用于读取电机B的实时速度
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>C<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><EFBFBD>ʵʱ<EFBFBD>ٶ<EFBFBD>
|
||||
Encoder_Init_TIM4();
|
||||
//Encoder D is initialized to read the real time speed of motor A
|
||||
//编码器D初始化,用于读取电机A的实时速度
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>D<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><EFBFBD>ʵʱ<EFBFBD>ٶ<EFBFBD>
|
||||
Encoder_Init_TIM5();
|
||||
|
||||
//定时器12用作舵机的PWM接口
|
||||
TIM12_SERVO_Init(9999,84-1); //APB1的时钟频率为84M , 频率=84M/((9999+1)*(83+1))=100Hz
|
||||
//<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>12<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>PWM<EFBFBD>ӿ<EFBFBD>
|
||||
TIM12_SERVO_Init(9999,84-1); //APB1<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>Ϊ84M , Ƶ<EFBFBD><EFBFBD>=84M/((9999+1)*(83+1))=100Hz
|
||||
|
||||
//普通小车默认定时器8用作航模接口
|
||||
// TIM8_SERVO_Init(9999,168-1);//APB2的时钟频率为168M , 频率=168M/((9999+1)*(167+1))=100Hz
|
||||
//Initialize the model remote control interface
|
||||
//初始化航模遥控接口
|
||||
TIM8_Cap_Init(9999,168-1); //高级定时器TIM8的时钟频率为168M
|
||||
//<EFBFBD><EFBFBD>ͨС<EFBFBD><EFBFBD>Ĭ<EFBFBD>϶<EFBFBD>ʱ<EFBFBD><EFBFBD>8<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD>ӿ<EFBFBD>
|
||||
// TIM8_SERVO_Init(9999,168-1);//APB2<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>Ϊ168M , Ƶ<EFBFBD><EFBFBD>=168M/((9999+1)*(167+1))=100Hz
|
||||
//Initialize the model remote control interface
|
||||
//<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģң<EFBFBD>ؽӿ<EFBFBD>
|
||||
TIM8_Cap_Init(9999,168-1); //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>TIM8<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>Ϊ168M
|
||||
|
||||
//Free-running 1 MHz microsecond time base for sensor sample timestamps.
|
||||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD> 1MHz <>뼶<EFBFBD><EBBCB6><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><D7BC>
|
||||
TIM7_Init();
|
||||
|
||||
//Initialize motor speed control and, for controlling motor speed, PWM frequency 10kHz
|
||||
//初始化电机速度控制以及,用于控制电机速度,PWM频率10KHZ
|
||||
//APB2时钟频率为168M,满PWM为16799,频率=168M/((16799+1)*(0+1))=10k
|
||||
//<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶȿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD>ٶȣ<EFBFBD>PWMƵ<EFBFBD><EFBFBD>10KHZ
|
||||
//APB2ʱ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>Ϊ168M<EFBFBD><EFBFBD><EFBFBD><EFBFBD>PWMΪ16799<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>=168M/((16799+1)*(0+1))=10k
|
||||
TIM1_PWM_Init(16799,0);
|
||||
TIM9_PWM_Init(16799,0);
|
||||
TIM10_PWM_Init(16799,0);
|
||||
TIM11_PWM_Init(16799,0);
|
||||
|
||||
//IIC initialization for MPU6050
|
||||
//IIC初始化,用于MPU6050
|
||||
//IIC<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>MPU6050
|
||||
I2C_GPIOInit();
|
||||
|
||||
//MPU6050 is initialized to read the vehicle's three-axis attitude,
|
||||
//three-axis angular velocity and three-axis acceleration information
|
||||
//MPU6050 初始化,用于读取小车三轴姿态、三轴角速度、三轴加速度信息
|
||||
//MPU6050 <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD>ȡС<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶ<EFBFBD><EFBFBD><EFBFBD>Ϣ
|
||||
MPU6050_initialize();
|
||||
|
||||
//Initialize the hardware interface to the PS2 controller
|
||||
//初始化与PS2手柄连接的硬件接口
|
||||
//<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>PS2<EFBFBD>ֱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
||||
PS2_Init();
|
||||
|
||||
//PS2 gamepad configuration is initialized and configured in analog mode
|
||||
//PS2手柄配置初始化,配置为模拟量模式
|
||||
//PS2<EFBFBD>ֱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ó<EFBFBD>ʼ<EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD>Ϊģ<CEAA><C4A3><EFBFBD><EFBFBD>ģʽ
|
||||
PS2_SetInit();
|
||||
}
|
||||
|
||||
@@ -94,9 +94,11 @@ extern long int ErrorCode;
|
||||
void systemInit(void);
|
||||
|
||||
/***Macros define***/ /***宏定义***/
|
||||
//After starting the car (1000/100Hz =10) for seconds, it is allowed to control the car to move
|
||||
//开机(1000/100hz=10)秒后才允许控制小车进行运动
|
||||
#define CONTROL_DELAY 1000
|
||||
//Collect IMU zero-bias samples for 2 seconds at 100 Hz before enabling control.
|
||||
//开机后以100Hz采集2秒IMU零偏,再允许控制小车运动
|
||||
#define CONTROL_DELAY 200
|
||||
//Balance_task counter needed to represent the same 2 second startup delay.
|
||||
#define CONTROL_STARTUP_DELAY_COUNT (2 * CONTROL_FREQUENCY)
|
||||
//The number of robot types to determine the value of Divisor_Mode. There are currently 6 car types
|
||||
//机器人型号数量,决定Divisor_Mode的值,目前有6种小车类型
|
||||
#define CAR_NUMBER 6
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
#define FLASH_MEM_START ((void*)0x1800)
|
||||
#define q30 1073741824.0f
|
||||
short gyro[3], accel[3], sensors;
|
||||
//零点漂移计数
|
||||
//<EFBFBD><EFBFBD><EFBFBD>Ư<EFBFBD>Ƽ<EFBFBD><EFBFBD><EFBFBD>
|
||||
int Deviation_Count;
|
||||
|
||||
short sum_gyro[3];
|
||||
short sum_accel[3];
|
||||
|
||||
// Gyro static error, raw data
|
||||
//陀螺仪静差,原始数据
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǿ<EFBFBD><EFBFBD>ԭʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
short Deviation_gyro[3],Original_gyro[3];
|
||||
short Deviation_accel[3],Original_accel[3];
|
||||
float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;
|
||||
@@ -55,11 +55,11 @@ void MPU6050_task(void *pvParameters)
|
||||
while(1)
|
||||
{
|
||||
//This task runs at 100Hz
|
||||
//此任务以100Hz的频率运行
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>100Hz<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
vTaskDelayUntil(&lastWakeTime, F2T(RATE_100_HZ));
|
||||
|
||||
//Read the gyroscope zero before starting
|
||||
//开机前,读取陀螺仪零点
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
if(Deviation_Count<CONTROL_DELAY)
|
||||
{
|
||||
Deviation_Count++;
|
||||
@@ -78,10 +78,14 @@ void MPU6050_task(void *pvParameters)
|
||||
memcpy(Deviation_accel,accel,sizeof(accel));
|
||||
}
|
||||
|
||||
MPU_Get_Gyroscope(); //得到陀螺仪数据
|
||||
MPU_Get_Accelscope(); //获得加速度计值(原始值)
|
||||
//Stamp just before the I2C burst read, as close to the physical IMU
|
||||
//sample as we can get without a data-ready interrupt.
|
||||
//<2F><> I2C <20><>ȡǰ<C8A1><C7B0>㣬<EFBFBD>ھ<EFBFBD><DABE><EFBFBD> DRDY <20>жϵ<D0B6><CFB5><EFBFBD><EFBFBD><EFBFBD>¾<EFBFBD><C2BE><EFBFBD><EFBFBD>ӽ<EFBFBD><D3BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>̡<EFBFBD>
|
||||
g_imu_sample_time_us = mcu_time_us();
|
||||
MPU_Get_Gyroscope(); //<2F>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
MPU_Get_Accelscope(); //<2F><>ü<EFBFBD><C3BC>ٶȼ<D9B6>ֵ(ԭʼֵ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static unsigned short inv_orientation_matrix_to_scalar(
|
||||
// const signed char *mtx)
|
||||
@@ -132,17 +136,17 @@ int16_t Gx_offset=0,Gy_offset=0,Gz_offset=0;
|
||||
|
||||
/**************************************************************************
|
||||
Function: The new ADC data is updated to FIFO array for filtering
|
||||
Input : ax,ay,az:x,y, z-axis acceleration data;gx,gy,gz:x. Y, z-axis angular acceleration data
|
||||
Input : ax<EFBFBD><EFBFBD>ay<EFBFBD><EFBFBD>az<EFBFBD><EFBFBD>x<EFBFBD><EFBFBD>y, z-axis acceleration data<EFBFBD><EFBFBD>gx<EFBFBD><EFBFBD>gy<EFBFBD><EFBFBD>gz<EFBFBD><EFBFBD>x. Y, z-axis angular acceleration data
|
||||
Output : none
|
||||
函数功能:将新的ADC数据更新到 FIFO数组,进行滤波处理
|
||||
入口参数:ax,ay,az:x,y,z轴加速度数据;gx,gy,gz:x,y,z轴角加速度数据
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>ADC<EFBFBD><EFBFBD><EFBFBD>ݸ<EFBFBD><EFBFBD>µ<EFBFBD> FIFO<46><4F><EFBFBD>飬<EFBFBD><E9A3AC><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><CBB2><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ax<EFBFBD><EFBFBD>ay<EFBFBD><EFBFBD>az<EFBFBD><EFBFBD>x<EFBFBD><EFBFBD>y<EFBFBD><EFBFBD>z<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݣ<EFBFBD>gx<EFBFBD><EFBFBD>gy<EFBFBD><EFBFBD>gz<EFBFBD><EFBFBD>x<EFBFBD><EFBFBD>y<EFBFBD><EFBFBD>z<EFBFBD><EFBFBD>Ǽ<EFBFBD><EFBFBD>ٶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
void MPU6050_newValues(int16_t ax,int16_t ay,int16_t az,int16_t gx,int16_t gy,int16_t gz)
|
||||
{
|
||||
unsigned char i ;
|
||||
int32_t sum=0;
|
||||
for(i=1;i<10;i++){ //FIFO 操作
|
||||
for(i=1;i<10;i++){ //FIFO <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
MPU6050_FIFO[0][i-1]=MPU6050_FIFO[0][i];
|
||||
MPU6050_FIFO[1][i-1]=MPU6050_FIFO[1][i];
|
||||
MPU6050_FIFO[2][i-1]=MPU6050_FIFO[2][i];
|
||||
@@ -150,7 +154,7 @@ MPU6050_FIFO[3][i-1]=MPU6050_FIFO[3][i];
|
||||
MPU6050_FIFO[4][i-1]=MPU6050_FIFO[4][i];
|
||||
MPU6050_FIFO[5][i-1]=MPU6050_FIFO[5][i];
|
||||
}
|
||||
MPU6050_FIFO[0][9]=ax;//将新的数据放置到 数据的最后面
|
||||
MPU6050_FIFO[0][9]=ax;//<EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݷ<EFBFBD><EFBFBD>õ<EFBFBD> <20><><EFBFBD>ݵ<EFBFBD><DDB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
MPU6050_FIFO[1][9]=ay;
|
||||
MPU6050_FIFO[2][9]=az;
|
||||
MPU6050_FIFO[3][9]=gx;
|
||||
@@ -158,7 +162,7 @@ MPU6050_FIFO[4][9]=gy;
|
||||
MPU6050_FIFO[5][9]=gz;
|
||||
|
||||
sum=0;
|
||||
for(i=0;i<10;i++){ //求当前数组的合,再取平均值
|
||||
for(i=0;i<10;i++){ //<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĺϣ<EFBFBD><EFBFBD><EFBFBD>ȡƽ<EFBFBD><EFBFBD>ֵ
|
||||
sum+=MPU6050_FIFO[0][i];
|
||||
}
|
||||
MPU6050_FIFO[0][10]=sum/10;
|
||||
@@ -196,11 +200,11 @@ MPU6050_FIFO[5][10]=sum/10;
|
||||
|
||||
/**************************************************************************
|
||||
Function: Setting the clock source of mpu6050
|
||||
Input : source:Clock source number
|
||||
Input : source<EFBFBD><EFBFBD>Clock source number
|
||||
Output : none
|
||||
函数功能:设置 MPU6050 的时钟源
|
||||
入口参数:source:时钟源编号
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> MPU6050 <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>Դ
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>source<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
* CLK_SEL | Clock Source
|
||||
* --------+--------------------------------------
|
||||
* 0 | Internal oscillator
|
||||
@@ -231,27 +235,27 @@ void MPU6050_setFullScaleGyroRange(uint8_t range) {
|
||||
|
||||
/**************************************************************************
|
||||
Function: Setting the maximum range of mpu6050 accelerometer
|
||||
Input : range:Acceleration maximum range number
|
||||
Input : range<EFBFBD><EFBFBD>Acceleration maximum range number
|
||||
Output : none
|
||||
函数功能:设置 MPU6050 加速度计的最大量程
|
||||
入口参数:range:加速度最大量程编号
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> MPU6050 <20><><EFBFBD>ٶȼƵ<C8BC><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>range<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̱<EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
//#define MPU6050_ACCEL_FS_2 0x00 //===最大量程+-2G
|
||||
//#define MPU6050_ACCEL_FS_4 0x01 //===最大量程+-4G
|
||||
//#define MPU6050_ACCEL_FS_8 0x02 //===最大量程+-8G
|
||||
//#define MPU6050_ACCEL_FS_16 0x03 //===最大量程+-16G
|
||||
//#define MPU6050_ACCEL_FS_2 0x00 //===<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+-2G
|
||||
//#define MPU6050_ACCEL_FS_4 0x01 //===<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+-4G
|
||||
//#define MPU6050_ACCEL_FS_8 0x02 //===<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+-8G
|
||||
//#define MPU6050_ACCEL_FS_16 0x03 //===<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+-16G
|
||||
void MPU6050_setFullScaleAccelRange(uint8_t range) {
|
||||
I2C_WriteBits(devAddr, MPU6050_RA_ACCEL_CONFIG, MPU6050_ACONFIG_AFS_SEL_BIT, MPU6050_ACONFIG_AFS_SEL_LENGTH, range);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Function: Set mpu6050 to sleep mode or not
|
||||
Input : enable:1,sleep;0,work;
|
||||
Input : enable<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>sleep<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>work<EFBFBD><EFBFBD>
|
||||
Output : none
|
||||
函数功能:设置 MPU6050 是否进入睡眠模式
|
||||
入口参数:enable:1,睡觉;0,工作;
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> MPU6050 <20>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>˯<EFBFBD><CBAF>ģʽ
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>enable<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>˯<EFBFBD><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
void MPU6050_setSleepEnabled(uint8_t enabled) {
|
||||
I2C_WriteOneBit(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_SLEEP_BIT, enabled);
|
||||
@@ -261,9 +265,9 @@ void MPU6050_setSleepEnabled(uint8_t enabled) {
|
||||
Function: Read identity
|
||||
Input : none
|
||||
Output : 0x68
|
||||
函数功能:读取 MPU6050 WHO_AM_I 标识
|
||||
入口参数:无
|
||||
返回 值:0x68
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD>ȡ MPU6050 WHO_AM_I <EFBFBD><EFBFBD>ʶ
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5>0x68
|
||||
**************************************************************************/
|
||||
uint8_t MPU6050_getDeviceID(void) {
|
||||
|
||||
@@ -277,10 +281,10 @@ uint8_t MPU6050_getDeviceID(void) {
|
||||
/**************************************************************************
|
||||
Function: Check whether mpu6050 is connected
|
||||
Input : none
|
||||
Output : 1:Connected;0:Not connected
|
||||
函数功能:检测MPU6050 是否已经连接
|
||||
入口参数:无
|
||||
返回 值:1:已连接;0:未连接
|
||||
Output : 1<EFBFBD><EFBFBD>Connected<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>Not connected
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>MPU6050 <20>Ƿ<EFBFBD><C7B7>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5>1<EFBFBD><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>0<EFBFBD><30>δ<EFBFBD><CEB4><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
uint8_t MPU6050_testConnection(void) {
|
||||
if(MPU6050_getDeviceID() == 0x68) //0b01101000;
|
||||
@@ -290,11 +294,11 @@ uint8_t MPU6050_testConnection(void) {
|
||||
|
||||
/**************************************************************************
|
||||
Function: Setting whether mpu6050 is the host of aux I2C cable
|
||||
Input : enable:1,yes;0;not
|
||||
Input : enable<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>yes<EFBFBD><EFBFBD>0;not
|
||||
Output : none
|
||||
函数功能:设置 MPU6050 是否为AUX I2C线的主机
|
||||
入口参数:enable:1,是;0:否
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> MPU6050 <EFBFBD>Ƿ<EFBFBD>ΪAUX I2C<EFBFBD>ߵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>enable<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD>0<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
void MPU6050_setI2CMasterModeEnabled(uint8_t enabled) {
|
||||
I2C_WriteOneBit(devAddr, MPU6050_RA_USER_CTRL, MPU6050_USERCTRL_I2C_MST_EN_BIT, enabled);
|
||||
@@ -302,11 +306,11 @@ void MPU6050_setI2CMasterModeEnabled(uint8_t enabled) {
|
||||
|
||||
/**************************************************************************
|
||||
Function: Setting whether mpu6050 is the host of aux I2C cable
|
||||
Input : enable:1,yes;0;not
|
||||
Input : enable<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>yes<EFBFBD><EFBFBD>0;not
|
||||
Output : none
|
||||
函数功能:设置 MPU6050 是否为AUX I2C线的主机
|
||||
入口参数:enable:1,是;0:否
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> MPU6050 <EFBFBD>Ƿ<EFBFBD>ΪAUX I2C<EFBFBD>ߵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>enable<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD>0<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
void MPU6050_setI2CBypassEnabled(uint8_t enabled) {
|
||||
I2C_WriteOneBit(devAddr, MPU6050_RA_INT_PIN_CFG, MPU6050_INTCFG_I2C_BYPASS_EN_BIT, enabled);
|
||||
@@ -316,38 +320,38 @@ void MPU6050_setI2CBypassEnabled(uint8_t enabled) {
|
||||
Function: initialization Mpu6050 to enter the available state
|
||||
Input : none
|
||||
Output : none
|
||||
函数功能:初始化 MPU6050 以进入可用状态
|
||||
入口参数:无
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD> MPU6050 <20>Խ<EFBFBD><D4BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
u8 MPU6050_initialize(void)
|
||||
{
|
||||
u8 res;
|
||||
//IIC_Init(); //Initialize the IIC bus //初始化IIC总线
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_PWR_MGMT_1,0X80); //Reset MPUrobot_select_init.h //复位MPUrobot_select_init.h
|
||||
delay_ms(200); //Delay 200 ms //延时200ms
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_PWR_MGMT_1,0X00); //Wake mpurobot_select_init.h //唤醒MPUrobot_select_init.h
|
||||
//IIC_Init(); //Initialize the IIC bus //<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>IIC<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_PWR_MGMT_1,0X80); //Reset MPUrobot_select_init.h //<EFBFBD><EFBFBD>λMPUrobot_select_init.h
|
||||
delay_ms(200); //Delay 200 ms //<EFBFBD><EFBFBD>ʱ200ms
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_PWR_MGMT_1,0X00); //Wake mpurobot_select_init.h //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>MPUrobot_select_init.h
|
||||
|
||||
//MPU6050_Set_Gyro_Fsr(1); //Gyroscope sensor //陀螺仪传感器,±500dps=±500°/s ±32768 (gyro/32768*500)*PI/180(rad/s)=gyro/3754.9(rad/s)
|
||||
//MPU6050_Set_Gyro_Fsr(1); //Gyroscope sensor //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C><>500dps=<EFBFBD><EFBFBD>500<EFBFBD><EFBFBD>/s <EFBFBD><EFBFBD>32768 (gyro/32768*500)*PI/180(rad/s)=gyro/3754.9(rad/s)
|
||||
MPU6050_setFullScaleGyroRange(MPU6050_GYRO_FS_500);
|
||||
//MPU6050_Set_Accel_Fsr(0); //Acceleration sensor //加速度传感器,±2g=±2*9.8m/s^2 ±32768 accel/32768*19.6=accel/1671.84
|
||||
//MPU6050_Set_Accel_Fsr(0); //Acceleration sensor //<EFBFBD><EFBFBD><EFBFBD>ٶȴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C><>2g=<EFBFBD><EFBFBD>2*9.8m/s^2 <EFBFBD><EFBFBD>32768 accel/32768*19.6=accel/1671.84
|
||||
MPU6050_setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
|
||||
MPU6050_Set_Rate(50); //Set the sampling rate to 50Hz //设置采样率50Hz
|
||||
MPU6050_Set_Rate(50); //Set the sampling rate to 50Hz //<EFBFBD><EFBFBD><EFBFBD>ò<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>50Hz
|
||||
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_INT_ENABLE,0X00); //Turn off all interrupts //关闭所有中断
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_USER_CTRL,0X00); //The I2C main mode is off //I2C主模式关闭
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_FIFO_EN,0X00); //Close the FIFO //关闭FIFO
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_INT_ENABLE,0X00); //Turn off all interrupts //<EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_USER_CTRL,0X00); //The I2C main mode is off //I2C<EFBFBD><EFBFBD>ģʽ<EFBFBD>ر<EFBFBD>
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_FIFO_EN,0X00); //Close the FIFO //<EFBFBD>ر<EFBFBD>FIFO
|
||||
//The INT pin is low, enabling bypass mode to read the magnetometer directly
|
||||
//INT引脚低电平有效,开启bypass模式,可以直接读取磁力计
|
||||
//INT<EFBFBD><EFBFBD><EFBFBD>ŵ͵<EFBFBD>ƽ<EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>bypassģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD>Ӷ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_INT_PIN_CFG,0X80);
|
||||
//Read the ID of MPU6050
|
||||
//读取MPU6050的ID
|
||||
//<EFBFBD><EFBFBD>ȡMPU6050<EFBFBD><EFBFBD>ID
|
||||
res=I2C_ReadOneByte(devAddr,MPU6050_RA_WHO_AM_I);
|
||||
if(res==MPU6050_DEFAULT_ADDRESS) //The device ID is correct, The correct device ID depends on the AD pin //器件ID正确, 器件ID的正确取决于AD引脚
|
||||
if(res==MPU6050_DEFAULT_ADDRESS) //The device ID is correct, The correct device ID depends on the AD pin //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ID<EFBFBD><EFBFBD>ȷ, <20><><EFBFBD><EFBFBD>ID<49><44><EFBFBD><EFBFBD>ȷȡ<C8B7><C8A1><EFBFBD><EFBFBD>AD<41><44><EFBFBD><EFBFBD>
|
||||
{
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_PWR_MGMT_1,0X01); //Set CLKSEL,PLL X axis as reference //设置CLKSEL,PLL X轴为参考
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_PWR_MGMT_2,0X00); //Acceleration and gyroscope both work //加速度与陀螺仪都工作
|
||||
MPU6050_Set_Rate(50); //Set the sampling rate to 50Hz //设置采样率为50Hz
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_PWR_MGMT_1,0X01); //Set CLKSEL,PLL X axis as reference //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>CLKSEL,PLL X<EFBFBD><EFBFBD>Ϊ<EFBFBD>ο<EFBFBD>
|
||||
I2C_WriteOneByte(devAddr,MPU6050_RA_PWR_MGMT_2,0X00); //Acceleration and gyroscope both work //<EFBFBD><EFBFBD><EFBFBD>ٶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
MPU6050_Set_Rate(50); //Set the sampling rate to 50Hz //<EFBFBD><EFBFBD><EFBFBD>ò<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ50Hz
|
||||
}else return 1;
|
||||
return 0;
|
||||
|
||||
@@ -357,9 +361,9 @@ u8 MPU6050_initialize(void)
|
||||
Function: Initialization of DMP in mpu6050
|
||||
Input : none
|
||||
Output : none
|
||||
函数功能:MPU6050内置DMP的初始化
|
||||
入口参数:无
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD>MPU6050<EFBFBD><EFBFBD><EFBFBD><EFBFBD>DMP<EFBFBD>ij<EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
//void DMP_Init(void)
|
||||
//{
|
||||
@@ -395,9 +399,9 @@ Output : none
|
||||
Function: Read the attitude information of DMP in mpu6050
|
||||
Input : none
|
||||
Output : none
|
||||
函数功能:读取MPU6050内置DMP的姿态信息
|
||||
入口参数:无
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD>ȡMPU6050<EFBFBD><EFBFBD><EFBFBD><EFBFBD>DMP<EFBFBD><EFBFBD><EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD>Ϣ
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
//void Read_DMP(void)
|
||||
//{
|
||||
@@ -405,16 +409,16 @@ Output : none
|
||||
// unsigned char more;
|
||||
// long quat[4];
|
||||
|
||||
// dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors, &more); //读取DMP数据
|
||||
// dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors, &more); //<EFBFBD><EFBFBD>ȡDMP<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// if (sensors & INV_WXYZ_QUAT )
|
||||
// {
|
||||
// q0=quat[0] / q30;
|
||||
// q1=quat[1] / q30;
|
||||
// q2=quat[2] / q30;
|
||||
// q3=quat[3] / q30; //四元数
|
||||
// Roll = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; //计算出横滚角
|
||||
// Pitch = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // 计算出俯仰角
|
||||
// Yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3; //计算出偏航角
|
||||
// q3=quat[3] / q30; //<EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD>
|
||||
// Roll = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// Pitch = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// Yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3; //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// }
|
||||
|
||||
//}
|
||||
@@ -422,16 +426,16 @@ Output : none
|
||||
Function: Read mpu6050 built-in temperature sensor data
|
||||
Input : none
|
||||
Output : Centigrade temperature
|
||||
函数功能:读取MPU6050内置温度传感器数据
|
||||
入口参数:无
|
||||
返回 值:摄氏温度
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD>ȡMPU6050<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¶ȴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¶<EFBFBD>
|
||||
**************************************************************************/
|
||||
int Read_Temperature(void)
|
||||
{
|
||||
float Temp;
|
||||
Temp=(I2C_ReadOneByte(devAddr,MPU6050_RA_TEMP_OUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_TEMP_OUT_L);
|
||||
if(Temp>32768) Temp-=65536; //数据类型转换
|
||||
Temp=(36.53f+Temp/340)*10; //温度放大十倍存放
|
||||
if(Temp>32768) Temp-=65536; //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD>
|
||||
Temp=(36.53f+Temp/340)*10; //<EFBFBD>¶ȷŴ<EFBFBD>ʮ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
return (int)Temp;
|
||||
}
|
||||
|
||||
@@ -439,9 +443,9 @@ int Read_Temperature(void)
|
||||
Function: Initialize TIM2 as the encoder interface mode
|
||||
Input : LPF: Digital low-pass filtering frequency (Hz)
|
||||
Output : 0: Settings successful, others: Settings failed
|
||||
函数功能:设置MPUrobot_select_init.h的数字低通滤波器
|
||||
入口参数:lpf:数字低通滤波频率(Hz)
|
||||
返回 值:0:设置成功, 其他:设置失败
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>MPUrobot_select_init.h<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>ͨ<EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>lpf:<3A><><EFBFBD>ֵ<EFBFBD>ͨ<EFBFBD>˲<EFBFBD>Ƶ<EFBFBD><C6B5>(Hz)
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5>0:<3A><><EFBFBD>óɹ<C3B3>, <20><><EFBFBD><EFBFBD>:<3A><><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>
|
||||
**************************************************************************/
|
||||
unsigned char MPU6050_Set_LPF(u16 lpf)
|
||||
{
|
||||
@@ -452,15 +456,15 @@ unsigned char MPU6050_Set_LPF(u16 lpf)
|
||||
else if(lpf>=20)data=4;
|
||||
else if(lpf>=10)data=5;
|
||||
else data=6;
|
||||
return I2C_WriteOneByte(devAddr,MPU6050_RA_CONFIG,data); //Set the digital lowpass filter//设置数字低通滤波器
|
||||
return I2C_WriteOneByte(devAddr,MPU6050_RA_CONFIG,data); //Set the digital lowpass filter//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>ͨ<EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD>
|
||||
}
|
||||
/**************************************************************************
|
||||
Function: Initialize TIM2 as the encoder interface mode
|
||||
Input : rate:4~1000(Hz)
|
||||
Output : 0: Settings successful, others: Settings failed
|
||||
函数功能:设置MPUrobot_select_init.h的采样率(假定Fs=1KHz)
|
||||
入口参数:rate:4~1000(Hz)
|
||||
返回 值:0:设置成功, 其他:设置失败
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>MPUrobot_select_init.h<EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28>ٶ<EFBFBD>Fs=1KHz)
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>rate:4~1000(Hz)
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5>0:<3A><><EFBFBD>óɹ<C3B3>, <20><><EFBFBD><EFBFBD>:<3A><><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>
|
||||
**************************************************************************/
|
||||
unsigned char MPU6050_Set_Rate(u16 rate)
|
||||
{
|
||||
@@ -468,42 +472,42 @@ unsigned char MPU6050_Set_Rate(u16 rate)
|
||||
if(rate>1000)rate=1000;
|
||||
if(rate<4)rate=4;
|
||||
data=1000/rate-1;
|
||||
data=I2C_WriteOneByte(devAddr,MPU6050_RA_SMPLRT_DIV,data); //Set the digital lowpass filter//设置数字低通滤波器
|
||||
return MPU6050_Set_LPF(rate/2); //Automatically sets LPF to half of the sampling rate //自动设置LPF为采样率的一半
|
||||
data=I2C_WriteOneByte(devAddr,MPU6050_RA_SMPLRT_DIV,data); //Set the digital lowpass filter//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>ͨ<EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD>
|
||||
return MPU6050_Set_LPF(rate/2); //Automatically sets LPF to half of the sampling rate //<EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>LPFΪ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>һ<EFBFBD><EFBFBD>
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Function: Initialize TIM2 as the encoder interface mode
|
||||
Input : Gx, Gy, Gz: raw readings (plus or minus) of the x,y, and z axes of the gyroscope
|
||||
Output : 0: success, others: error code
|
||||
函数功能:获得陀螺仪值(原始值)
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ(ԭʼֵ)
|
||||
**************************************************************************/
|
||||
void MPU_Get_Gyroscope(void)
|
||||
{
|
||||
gyro[0]=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_XOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_XOUT_L); //读取X轴陀螺仪
|
||||
gyro[1]=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_L); //读取Y轴陀螺仪
|
||||
gyro[2]=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_L); //读取Z轴陀螺仪
|
||||
gyro[0]=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_XOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_XOUT_L); //<EFBFBD><EFBFBD>ȡX<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
gyro[1]=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_L); //<EFBFBD><EFBFBD>ȡY<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
gyro[2]=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_L); //<EFBFBD><EFBFBD>ȡZ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
if(Deviation_Count<CONTROL_DELAY) // 10 seconds before starting //开机前10秒
|
||||
if(Deviation_Count<CONTROL_DELAY) // 10 seconds before starting //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ10<EFBFBD><EFBFBD>
|
||||
{
|
||||
|
||||
Led_Count=1; //LED high frequency flashing //LED高频闪烁
|
||||
Flag_Stop=1; //The software fails to flag location 1 //软件失能标志位置1
|
||||
Led_Count=1; //LED high frequency flashing //LED<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>˸
|
||||
Flag_Stop=1; //The software fails to flag location 1 //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD>ܱ<EFBFBD>־λ<EFBFBD><EFBFBD>1
|
||||
}
|
||||
else //10 seconds after starting //开机10秒后
|
||||
else //10 seconds after starting //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>10<EFBFBD><EFBFBD><EFBFBD>
|
||||
{
|
||||
if(Deviation_Count==CONTROL_DELAY)
|
||||
Flag_Stop=0; //The software fails to flag location 0 //软件失能标志位置0
|
||||
Led_Count=300; //The LED returns to normal flicker frequency //LED恢复正常闪烁频率
|
||||
Flag_Stop=0; //The software fails to flag location 0 //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD>ܱ<EFBFBD>־λ<EFBFBD><EFBFBD>0
|
||||
Led_Count=300; //The LED returns to normal flicker frequency //LED<EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸Ƶ<EFBFBD><EFBFBD>
|
||||
|
||||
//Save the raw data to update zero by clicking the user button
|
||||
//保存原始数据用于单击用户按键更新零点
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
Original_gyro[0] =gyro[0];
|
||||
Original_gyro[1] =gyro[1];
|
||||
Original_gyro[2]= gyro[2];
|
||||
|
||||
//Removes zero drift data
|
||||
//去除零点漂移的数据
|
||||
//ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ư<EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
gyro[0] =Original_gyro[0]-Deviation_gyro[0];
|
||||
gyro[1] =Original_gyro[1]-Deviation_gyro[1];
|
||||
gyro[2]= Original_gyro[2]-Deviation_gyro[2];
|
||||
@@ -514,28 +518,28 @@ void MPU_Get_Gyroscope(void)
|
||||
Function: Initialize TIM2 as the encoder interface mode
|
||||
Input : Gx, Gy, Gz: raw readings (plus or minus) of the x,y, and z axes of the gyroscope
|
||||
Output : 0: success, others: error code
|
||||
函数功能:获得加速度计值(原始值)
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD>ü<EFBFBD><EFBFBD>ٶȼ<EFBFBD>ֵ(ԭʼֵ)
|
||||
**************************************************************************/
|
||||
void MPU_Get_Accelscope(void)
|
||||
{
|
||||
accel[0]=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_L); //读取X轴加速度计
|
||||
accel[1]=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_YOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_YOUT_L); //读取X轴加速度计
|
||||
accel[2]=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_L); //读取Z轴加速度计
|
||||
accel[0]=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_L); //<EFBFBD><EFBFBD>ȡX<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶȼ<EFBFBD>
|
||||
accel[1]=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_YOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_YOUT_L); //<EFBFBD><EFBFBD>ȡX<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶȼ<EFBFBD>
|
||||
accel[2]=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_L); //<EFBFBD><EFBFBD>ȡZ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶȼ<EFBFBD>
|
||||
|
||||
if(Deviation_Count<CONTROL_DELAY) // 10 seconds before starting //开机前10秒
|
||||
if(Deviation_Count<CONTROL_DELAY) // 10 seconds before starting //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ10<EFBFBD><EFBFBD>
|
||||
{
|
||||
|
||||
}
|
||||
else //10 seconds after starting //开机10秒后
|
||||
else //10 seconds after starting //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>10<EFBFBD><EFBFBD><EFBFBD>
|
||||
{
|
||||
//Save the raw data to update zero by clicking the user button
|
||||
//保存原始数据用于单击用户按键更新零点
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
Original_accel[0] =accel[0];
|
||||
Original_accel[1] =accel[1];
|
||||
Original_accel[2]= accel[2];
|
||||
|
||||
//Removes zero drift data
|
||||
//去除零点漂移的数据
|
||||
//ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ư<EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
accel[0] =Original_accel[0]-Deviation_accel[0];
|
||||
accel[1] =Original_accel[1]-Deviation_accel[1];
|
||||
accel[2]= Original_accel[2]-Deviation_accel[2]+16384;
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#define EN PDin(3)
|
||||
|
||||
#define Servo_PWM TIM12->CCR2
|
||||
#define SERVO_INIT 1590 //Servo zero point //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define SERVO_INIT 1670 //Servo straight-ahead point (calibrated 1/R~=0) //<2F><>ֱ<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>
|
||||
|
||||
void Enable_Pin(void);
|
||||
void Servo_PWM_Init(u16 arr,u16 psc);
|
||||
|
||||
380
HARDWARE/timer.c
380
HARDWARE/timer.c
@@ -2,28 +2,28 @@
|
||||
|
||||
//Input the capture flag for channel 1,
|
||||
//the capture flag for the higher bits, and the overflow flag for the lower 6 bits
|
||||
//通道1输入捕获标志,高两位做捕获标志,低6位做溢出标志
|
||||
//ͨ<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD>6λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־
|
||||
u8 TIM8CH1_CAPTURE_STA = 0;
|
||||
u16 TIM8CH1_CAPTURE_UPVAL;
|
||||
u16 TIM8CH1_CAPTURE_DOWNVAL;
|
||||
|
||||
//Input the capture flag for channel 2,
|
||||
//the capture flag for the higher bits, and the overflow flag for the lower 6 bits
|
||||
//通道2输入捕获标志,高两位做捕获标志,低6位做溢出标志
|
||||
//ͨ<EFBFBD><EFBFBD>2<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD>6λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־
|
||||
u8 TIM8CH2_CAPTURE_STA = 0;
|
||||
u16 TIM8CH2_CAPTURE_UPVAL;
|
||||
u16 TIM8CH2_CAPTURE_DOWNVAL;
|
||||
|
||||
//Input the capture flag for channel 3,
|
||||
//the capture flag for the higher bits, and the overflow flag for the lower 6 bits
|
||||
//通道3输入捕获标志,高两位做捕获标志,低6位做溢出标志
|
||||
//ͨ<EFBFBD><EFBFBD>3<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD>6λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־
|
||||
u8 TIM8CH3_CAPTURE_STA = 0;
|
||||
u16 TIM8CH3_CAPTURE_UPVAL;
|
||||
u16 TIM8CH3_CAPTURE_DOWNVAL;
|
||||
|
||||
//Input the capture flag for channel 4,
|
||||
//the capture flag for the higher bits, and the overflow flag for the lower 6 bits
|
||||
//通道4输入捕获标志,高两位做捕获标志,低6位做溢出标志
|
||||
//ͨ<EFBFBD><EFBFBD>4<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD>6λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־
|
||||
u8 TIM8CH4_CAPTURE_STA = 0;
|
||||
u16 TIM8CH4_CAPTURE_UPVAL;
|
||||
u16 TIM8CH4_CAPTURE_DOWNVAL;
|
||||
@@ -34,19 +34,19 @@ u32 TIM8_T3;
|
||||
u32 TIM8_T4;
|
||||
|
||||
//Variables related to remote control acquisition of model aircraft
|
||||
//航模遥控采集相关变量
|
||||
//<EFBFBD><EFBFBD>ģң<EFBFBD>زɼ<EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD>
|
||||
int Remoter_Ch1=1500,Remoter_Ch2=1500,Remoter_Ch3=1500,Remoter_Ch4=1500;
|
||||
//Model aircraft remote control receiver variable
|
||||
//航模遥控接收变量
|
||||
//<EFBFBD><EFBFBD>ģң<EFBFBD>ؽ<EFBFBD><EFBFBD>ձ<EFBFBD><EFBFBD><EFBFBD>
|
||||
int L_Remoter_Ch1=1500,L_Remoter_Ch2=1500,L_Remoter_Ch3=1500,L_Remoter_Ch4=1500;
|
||||
|
||||
/**************************************************************************
|
||||
Function: Model aircraft remote control initialization function, timer 1 input capture initialization
|
||||
Input : arr: Automatic reload value, psc: clock preset frequency
|
||||
Output : none
|
||||
函数功能:航模遥控初始化函数,定时器1输入捕获初始化
|
||||
入口参数:arr:自动重装值,psc:时钟预分频数
|
||||
返 回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD>ģң<EFBFBD>س<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>arr<EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>װֵ<EFBFBD><EFBFBD>psc<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>Ԥ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD> <20><> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
void TIM8_Cap_Init(u16 arr, u16 psc)
|
||||
{
|
||||
@@ -55,14 +55,14 @@ void TIM8_Cap_Init(u16 arr, u16 psc)
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
TIM_ICInitTypeDef TIM_ICInitStructure;
|
||||
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM1时钟使能
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //使能PORTE时钟
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM1ʱ<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //ʹ<EFBFBD><EFBFBD>PORTEʱ<EFBFBD><EFBFBD>
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; //GPIOC
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
|
||||
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//<EFBFBD><EFBFBD><EFBFBD>ù<EFBFBD><EFBFBD><EFBFBD>
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //<EFBFBD>ٶ<EFBFBD>100MHz
|
||||
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //<EFBFBD><EFBFBD><EFBFBD>츴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
GPIO_Init(GPIOC,&GPIO_InitStructure);
|
||||
|
||||
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM8);
|
||||
@@ -70,104 +70,104 @@ void TIM8_Cap_Init(u16 arr, u16 psc)
|
||||
GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_TIM8);
|
||||
GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_TIM8);
|
||||
|
||||
/*** Initialize timer 1 || 初始化定时器1 ***/
|
||||
//Set the counter to automatically reload //设定计数器自动重装值
|
||||
/*** Initialize timer 1 || <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>1 ***/
|
||||
//Set the counter to automatically reload //<EFBFBD>趨<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>װֵ
|
||||
TIM_TimeBaseStructure.TIM_Period = arr;
|
||||
//Pre-divider //预分频器
|
||||
//Pre-divider //Ԥ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>
|
||||
TIM_TimeBaseStructure.TIM_Prescaler = psc;
|
||||
//Set the clock split: TDTS = Tck_tim //设置时钟分割:TDTS = Tck_tim
|
||||
//Set the clock split: TDTS = Tck_tim //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>ӷָ<EFBFBD>:TDTS = Tck_tim
|
||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||
//TIM up count mode //TIM向上计数模式
|
||||
//TIM up count mode //TIM<EFBFBD><EFBFBD><EFBFBD>ϼ<EFBFBD><EFBFBD><EFBFBD>ģʽ
|
||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||
//Initializes the timebase unit for TIMX based on the parameter specified in TIM_TimeBaseInitStruct
|
||||
//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>TIM_TimeBaseInitStruct<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>TIMx<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ
|
||||
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
|
||||
|
||||
/*** 初始化TIM1输入捕获参数,通道1 || Initialize TIM1 for the capture parameter, channel 1 ***/
|
||||
//Select input //选择输入端
|
||||
/*** <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>TIM1<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>1 || Initialize TIM1 for the capture parameter, channel 1 ***/
|
||||
//Select input //ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
|
||||
//Rising edge capture //上升沿捕获
|
||||
//Rising edge capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
|
||||
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
|
||||
//Configure input frequency division, regardless of frequency //配置输入分频,不分频
|
||||
//Configure input frequency division, regardless of frequency //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ,<2C><><EFBFBD><EFBFBD>Ƶ
|
||||
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
|
||||
//IC1F=0000 Configure input filter //配置输入滤波器
|
||||
//IC1F=0000 Configure input filter //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInitStructure.TIM_ICFilter = 0x0F;
|
||||
TIM_ICInit(TIM8, &TIM_ICInitStructure);
|
||||
|
||||
/*** 初始化TIM1输入捕获参数,通道2 || Initialize TIM1 for the capture parameter, channel 2 ***/
|
||||
//CC1S=01 Select input //选择输入端
|
||||
/*** <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>TIM1<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>2 || Initialize TIM1 for the capture parameter, channel 2 ***/
|
||||
//CC1S=01 Select input //ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
|
||||
//Rising edge capture //上升沿捕获
|
||||
//Rising edge capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
|
||||
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
|
||||
//Configure input frequency division, regardless of frequency //配置输入分频,不分频
|
||||
//Configure input frequency division, regardless of frequency //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ,<2C><><EFBFBD><EFBFBD>Ƶ
|
||||
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
|
||||
TIM_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器
|
||||
TIM_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInit(TIM8, &TIM_ICInitStructure);
|
||||
|
||||
/*** 初始化TIM1输入捕获参数,通道3 || Initialize TIM1 for the capture parameter, channel 3 ***/
|
||||
//Select input //选择输入端
|
||||
/*** <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>TIM1<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>3 || Initialize TIM1 for the capture parameter, channel 3 ***/
|
||||
//Select input //ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
|
||||
//Rising edge capture //上升沿捕获
|
||||
//Rising edge capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
|
||||
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
|
||||
//Configure input frequency division, regardless of frequency //配置输入分频,不分频
|
||||
//Configure input frequency division, regardless of frequency //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ,<2C><><EFBFBD><EFBFBD>Ƶ
|
||||
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
|
||||
//IC1F=0000 Configure input filter //配置输入滤波器,不滤波
|
||||
//IC1F=0000 Configure input filter //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD>
|
||||
TIM_ICInitStructure.TIM_ICFilter = 0x00;
|
||||
TIM_ICInit(TIM8, &TIM_ICInitStructure);
|
||||
|
||||
/*** 初始化TIM1输入捕获参数,通道4 || Initialize TIM1 for the capture parameter, channel 4 ***/
|
||||
//Select input //选择输入端
|
||||
/*** <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>TIM1<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD>4 || Initialize TIM1 for the capture parameter, channel 4 ***/
|
||||
//Select input //ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
|
||||
//Rising edge capture //上升沿捕获
|
||||
//Rising edge capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
|
||||
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
|
||||
//Configure input frequency division, regardless of frequency //配置输入分频,不分频
|
||||
//Configure input frequency division, regardless of frequency //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ,<2C><><EFBFBD><EFBFBD>Ƶ
|
||||
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
|
||||
//IC1F=0000 Configure input filter //配置输入滤波器,不滤波
|
||||
//IC1F=0000 Configure input filter //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD>
|
||||
TIM_ICInitStructure.TIM_ICFilter = 0x00;
|
||||
TIM_ICInit(TIM8, &TIM_ICInitStructure);
|
||||
|
||||
/*** interrupt packet initialization || 中断分组初始化 ***/
|
||||
//TIM1 interrupts //TIM1中断
|
||||
/*** interrupt packet initialization || <EFBFBD>жϷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD> ***/
|
||||
//TIM1 interrupts //TIM1<EFBFBD>ж<EFBFBD>
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn;
|
||||
//Preempt priority 0 //先占优先级0级
|
||||
//Preempt priority 0 //<EFBFBD><EFBFBD>ռ<EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD>0<EFBFBD><EFBFBD>
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
|
||||
//Level 0 from priority //从优先级0级
|
||||
//Level 0 from priority //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD>0<EFBFBD><EFBFBD>
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
|
||||
//IRQ channels are enabled //IRQ通道被使能
|
||||
//IRQ channels are enabled //IRQͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
//Initializes the peripheral NVIC register according to the parameters specified in NVIC_InitStruct
|
||||
//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>NVIC_InitStruct<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>NVIC<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
//Allow CC1IE,CC2IE,CC3IE,CC4IE to catch interrupts, not allowed update_interrupts
|
||||
//不允许更新中断,允许CC1IE,CC2IE,CC3IE,CC4IE捕获中断
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>CC1IE,CC2IE,CC3IE,CC4IE<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
|
||||
TIM_ITConfig(TIM8, TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4, ENABLE);
|
||||
//Advanced timer output must be enabled //高级定时器输出必须使能这句
|
||||
//Advanced timer output must be enabled //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_CtrlPWMOutputs(TIM8,ENABLE);
|
||||
//Enable timer //使能定时器
|
||||
//Enable timer //ʹ<EFBFBD>ܶ<EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
TIM_Cmd(TIM8, ENABLE);
|
||||
}
|
||||
/**************************************************************************
|
||||
Function: Model aircraft remote control receiving interrupt, namely timer 8 input capture interrupt
|
||||
Input : none
|
||||
Output : none
|
||||
函数功能:航模遥控接收中断,即定时器8输入捕获中断
|
||||
入口参数:无
|
||||
返 回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD>ģң<EFBFBD>ؽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>8<EFBFBD><EFBFBD><EFBFBD>벶<EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD> <20><> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
void TIM8_CC_IRQHandler(void)
|
||||
{
|
||||
//连接航模遥遥控器后,需要推下前进杆,才可以正式航模控制小车
|
||||
//<EFBFBD><EFBFBD><EFBFBD>Ӻ<EFBFBD>ģңң<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><EFBFBD>ſ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><EFBFBD>
|
||||
//After connecting the remote controller of the model aircraft,
|
||||
//you need to push down the forward lever to officially control the car of the model aircraft
|
||||
if(Remoter_Ch2>1600&&Remote_ON_Flag==0&&Deviation_Count>=CONTROL_DELAY)
|
||||
{
|
||||
//Model aircraft remote control mark position 1, other marks position 0
|
||||
//航模遥控标志位置1,其它标志位置0
|
||||
//<EFBFBD><EFBFBD>ģң<EFBFBD>ر<EFBFBD>־λ<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־λ<EFBFBD><EFBFBD>0
|
||||
Remote_ON_Flag=1;
|
||||
APP_ON_Flag=0;
|
||||
PS2_ON_Flag=0;
|
||||
@@ -179,131 +179,131 @@ void TIM8_CC_IRQHandler(void)
|
||||
|
||||
|
||||
|
||||
// //Channel 1 //通道一
|
||||
// //Channel 1 //ͨ<EFBFBD><EFBFBD>һ
|
||||
if ((TIM8CH1_CAPTURE_STA & 0X80) == 0)
|
||||
{
|
||||
if (TIM_GetITStatus(TIM8, TIM_IT_CC1) != RESET) //A capture event occurred on channel 1 //通道1发生捕获事件
|
||||
if (TIM_GetITStatus(TIM8, TIM_IT_CC1) != RESET) //A capture event occurred on channel 1 //ͨ<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
||||
{
|
||||
TIM_ClearITPendingBit(TIM8, TIM_IT_CC1); //Clear the interrupt flag bit //清除中断标志位
|
||||
if (TIM8CH1_CAPTURE_STA & 0X40) //A falling edge is caught //捕获到一个下降沿
|
||||
TIM_ClearITPendingBit(TIM8, TIM_IT_CC1); //Clear the interrupt flag bit //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϱ<EFBFBD>־λ
|
||||
if (TIM8CH1_CAPTURE_STA & 0X40) //A falling edge is caught //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD><EFBFBD>
|
||||
{
|
||||
TIM8CH1_CAPTURE_DOWNVAL = TIM_GetCapture1(TIM8); //Record the timer value at this point //记录下此时的定时器计数值
|
||||
TIM8CH1_CAPTURE_DOWNVAL = TIM_GetCapture1(TIM8); //Record the timer value at this point //<EFBFBD><EFBFBD>¼<EFBFBD>´<EFBFBD>ʱ<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
if (TIM8CH1_CAPTURE_DOWNVAL < TIM8CH1_CAPTURE_UPVAL)
|
||||
{
|
||||
TIM8_T1 = 9999;
|
||||
}
|
||||
else
|
||||
TIM8_T1 = 0;
|
||||
Remoter_Ch1 = TIM8CH1_CAPTURE_DOWNVAL - TIM8CH1_CAPTURE_UPVAL + TIM8_T1; //Time to get the total high level //得到总的高电平的时间
|
||||
if(abs(Remoter_Ch1-L_Remoter_Ch1)>500) Remoter_Ch1=L_Remoter_Ch1; //Filter //滤波
|
||||
Remoter_Ch1 = TIM8CH1_CAPTURE_DOWNVAL - TIM8CH1_CAPTURE_UPVAL + TIM8_T1; //Time to get the total high level //<EFBFBD>õ<EFBFBD><EFBFBD>ܵĸߵ<EFBFBD>ƽ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
if(abs(Remoter_Ch1-L_Remoter_Ch1)>500) Remoter_Ch1=L_Remoter_Ch1; //Filter //<EFBFBD>˲<EFBFBD>
|
||||
L_Remoter_Ch1=Remoter_Ch1;
|
||||
|
||||
TIM8CH1_CAPTURE_STA = 0; //Capture flag bit to zero //捕获标志位清零
|
||||
TIM_OC1PolarityConfig(TIM8, TIM_ICPolarity_Rising); //Set to rising edge capture //设置为上升沿捕获
|
||||
TIM8CH1_CAPTURE_STA = 0; //Capture flag bit to zero //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_OC1PolarityConfig(TIM8, TIM_ICPolarity_Rising); //Set to rising edge capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
}
|
||||
else
|
||||
{
|
||||
//When the capture time occurs but not the falling edge, the first time the rising edge is captured, record the timer value at this time
|
||||
//发生捕获时间但不是下降沿,第一次捕获到上升沿,记录此时的定时器计数值
|
||||
TIM8CH1_CAPTURE_UPVAL = TIM_GetCapture1(TIM8); //Obtain rising edge data //获取上升沿数据
|
||||
TIM8CH1_CAPTURE_STA |= 0X40; //The flag has been caught on the rising edge //标记已捕获到上升沿
|
||||
TIM_OC1PolarityConfig(TIM8, TIM_ICPolarity_Falling); //Set to Falling Edge Capture //设置为下降沿捕获
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>䵫<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>β<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>ʱ<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
TIM8CH1_CAPTURE_UPVAL = TIM_GetCapture1(TIM8); //Obtain rising edge data //<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM8CH1_CAPTURE_STA |= 0X40; //The flag has been caught on the rising edge //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_OC1PolarityConfig(TIM8, TIM_ICPolarity_Falling); //Set to Falling Edge Capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>½<EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
}
|
||||
}
|
||||
}
|
||||
//Channel 2 //通道二
|
||||
//Channel 2 //ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
if ((TIM8CH2_CAPTURE_STA & 0X80) == 0)
|
||||
{
|
||||
if (TIM_GetITStatus(TIM8, TIM_IT_CC2) != RESET) //A capture event occurred on channel 2 //通道2发生捕获事件
|
||||
if (TIM_GetITStatus(TIM8, TIM_IT_CC2) != RESET) //A capture event occurred on channel 2 //ͨ<EFBFBD><EFBFBD>2<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
||||
{
|
||||
TIM_ClearITPendingBit(TIM8, TIM_IT_CC2); //Clear the interrupt flag bit //清除中断标志位
|
||||
if (TIM8CH2_CAPTURE_STA & 0X40) //A falling edge is caught //捕获到一个下降沿
|
||||
TIM_ClearITPendingBit(TIM8, TIM_IT_CC2); //Clear the interrupt flag bit //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϱ<EFBFBD>־λ
|
||||
if (TIM8CH2_CAPTURE_STA & 0X40) //A falling edge is caught //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD><EFBFBD>
|
||||
{
|
||||
TIM8CH2_CAPTURE_DOWNVAL = TIM_GetCapture2(TIM8); //Record the timer value at this point //记录下此时的定时器计数值
|
||||
TIM8CH2_CAPTURE_DOWNVAL = TIM_GetCapture2(TIM8); //Record the timer value at this point //<EFBFBD><EFBFBD>¼<EFBFBD>´<EFBFBD>ʱ<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
if (TIM8CH2_CAPTURE_DOWNVAL < TIM8CH2_CAPTURE_UPVAL)
|
||||
{
|
||||
TIM8_T2 = 9999;
|
||||
}
|
||||
else
|
||||
TIM8_T2 = 0;
|
||||
Remoter_Ch2 = TIM8CH2_CAPTURE_DOWNVAL - TIM8CH2_CAPTURE_UPVAL + TIM8_T2; //Time to get the total high level //得到总的高电平的时间
|
||||
if(abs(Remoter_Ch2-L_Remoter_Ch2)>500)Remoter_Ch2=L_Remoter_Ch2; //Filter //滤波
|
||||
Remoter_Ch2 = TIM8CH2_CAPTURE_DOWNVAL - TIM8CH2_CAPTURE_UPVAL + TIM8_T2; //Time to get the total high level //<EFBFBD>õ<EFBFBD><EFBFBD>ܵĸߵ<EFBFBD>ƽ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
if(abs(Remoter_Ch2-L_Remoter_Ch2)>500)Remoter_Ch2=L_Remoter_Ch2; //Filter //<EFBFBD>˲<EFBFBD>
|
||||
L_Remoter_Ch2=Remoter_Ch2;
|
||||
|
||||
TIM8CH2_CAPTURE_STA = 0; //Capture flag bit to zero //捕获标志位清零
|
||||
TIM_OC2PolarityConfig(TIM8, TIM_ICPolarity_Rising); //Set to rising edge capture //设置为上升沿捕获
|
||||
TIM8CH2_CAPTURE_STA = 0; //Capture flag bit to zero //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_OC2PolarityConfig(TIM8, TIM_ICPolarity_Rising); //Set to rising edge capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
}
|
||||
else
|
||||
{
|
||||
//When the capture time occurs but not the falling edge, the first time the rising edge is captured, record the timer value at this time
|
||||
//发生捕获时间但不是下降沿,第一次捕获到上升沿,记录此时的定时器计数值
|
||||
TIM8CH2_CAPTURE_UPVAL = TIM_GetCapture2(TIM8); //Obtain rising edge data //获取上升沿数据
|
||||
TIM8CH2_CAPTURE_STA |= 0X40; //The flag has been caught on the rising edge //标记已捕获到上升沿
|
||||
TIM_OC2PolarityConfig(TIM8, TIM_ICPolarity_Falling); //Set to Falling Edge Capture //设置为下降沿捕获
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>䵫<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>β<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>ʱ<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
TIM8CH2_CAPTURE_UPVAL = TIM_GetCapture2(TIM8); //Obtain rising edge data //<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM8CH2_CAPTURE_STA |= 0X40; //The flag has been caught on the rising edge //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_OC2PolarityConfig(TIM8, TIM_ICPolarity_Falling); //Set to Falling Edge Capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>½<EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
}
|
||||
}
|
||||
}
|
||||
//Channel 3 //通道三
|
||||
//Channel 3 //ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
if ((TIM8CH3_CAPTURE_STA & 0X80) == 0)
|
||||
{
|
||||
if (TIM_GetITStatus(TIM8, TIM_IT_CC3) != RESET) //A capture event occurred on channel 3 //通道3发生捕获事件
|
||||
if (TIM_GetITStatus(TIM8, TIM_IT_CC3) != RESET) //A capture event occurred on channel 3 //ͨ<EFBFBD><EFBFBD>3<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
||||
{
|
||||
TIM_ClearITPendingBit(TIM8, TIM_IT_CC3); //Clear the interrupt flag bit //清除中断标志位
|
||||
if (TIM8CH3_CAPTURE_STA & 0X40) //A falling edge is caught //捕获到一个下降沿
|
||||
TIM_ClearITPendingBit(TIM8, TIM_IT_CC3); //Clear the interrupt flag bit //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϱ<EFBFBD>־λ
|
||||
if (TIM8CH3_CAPTURE_STA & 0X40) //A falling edge is caught //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD><EFBFBD>
|
||||
{
|
||||
TIM8CH3_CAPTURE_DOWNVAL = TIM_GetCapture3(TIM8); //Record the timer value at this point //记录下此时的定时器计数值
|
||||
TIM8CH3_CAPTURE_DOWNVAL = TIM_GetCapture3(TIM8); //Record the timer value at this point //<EFBFBD><EFBFBD>¼<EFBFBD>´<EFBFBD>ʱ<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
if (TIM8CH3_CAPTURE_DOWNVAL < TIM8CH3_CAPTURE_UPVAL)
|
||||
{
|
||||
TIM8_T3 = 9999;
|
||||
}
|
||||
else
|
||||
TIM8_T3 = 0;
|
||||
Remoter_Ch3 = TIM8CH3_CAPTURE_DOWNVAL - TIM8CH3_CAPTURE_UPVAL + TIM8_T3; //Time to get the total high level //得到总的高电平的时间
|
||||
if(abs(Remoter_Ch3-L_Remoter_Ch3)>500)Remoter_Ch3=L_Remoter_Ch3; //Filter //滤波
|
||||
Remoter_Ch3 = TIM8CH3_CAPTURE_DOWNVAL - TIM8CH3_CAPTURE_UPVAL + TIM8_T3; //Time to get the total high level //<EFBFBD>õ<EFBFBD><EFBFBD>ܵĸߵ<EFBFBD>ƽ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
if(abs(Remoter_Ch3-L_Remoter_Ch3)>500)Remoter_Ch3=L_Remoter_Ch3; //Filter //<EFBFBD>˲<EFBFBD>
|
||||
L_Remoter_Ch3=Remoter_Ch3;
|
||||
TIM8CH3_CAPTURE_STA = 0; //Capture flag bit to zero //捕获标志位清零
|
||||
TIM_OC3PolarityConfig(TIM8, TIM_ICPolarity_Rising); //Set to rising edge capture //设置为上升沿捕获
|
||||
TIM8CH3_CAPTURE_STA = 0; //Capture flag bit to zero //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_OC3PolarityConfig(TIM8, TIM_ICPolarity_Rising); //Set to rising edge capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
}
|
||||
else
|
||||
{
|
||||
//When the capture time occurs but not the falling edge, the first time the rising edge is captured, record the timer value at this time
|
||||
//发生捕获时间但不是下降沿,第一次捕获到上升沿,记录此时的定时器计数值
|
||||
TIM8CH3_CAPTURE_UPVAL = TIM_GetCapture3(TIM8); //Obtain rising edge data //获取上升沿数据
|
||||
TIM8CH3_CAPTURE_STA |= 0X40; //The flag has been caught on the rising edge //标记已捕获到上升沿
|
||||
TIM_OC3PolarityConfig(TIM8, TIM_ICPolarity_Falling); //Set to Falling Edge Capture //设置为下降沿捕获
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>䵫<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>β<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>ʱ<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
TIM8CH3_CAPTURE_UPVAL = TIM_GetCapture3(TIM8); //Obtain rising edge data //<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM8CH3_CAPTURE_STA |= 0X40; //The flag has been caught on the rising edge //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_OC3PolarityConfig(TIM8, TIM_ICPolarity_Falling); //Set to Falling Edge Capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>½<EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
//Channel 4 //通道四
|
||||
//Channel 4 //ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
if ((TIM8CH4_CAPTURE_STA & 0X80) == 0)
|
||||
{
|
||||
if (TIM_GetITStatus(TIM8, TIM_IT_CC4) != RESET) //A capture event occurred on channel 4 //通道4发生捕获事件
|
||||
if (TIM_GetITStatus(TIM8, TIM_IT_CC4) != RESET) //A capture event occurred on channel 4 //ͨ<EFBFBD><EFBFBD>4<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
||||
{
|
||||
TIM_ClearITPendingBit(TIM8, TIM_IT_CC4); //Clear the interrupt flag bit //清除中断标志位
|
||||
if (TIM8CH4_CAPTURE_STA & 0X40) //A falling edge is caught //捕获到一个下降沿
|
||||
TIM_ClearITPendingBit(TIM8, TIM_IT_CC4); //Clear the interrupt flag bit //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϱ<EFBFBD>־λ
|
||||
if (TIM8CH4_CAPTURE_STA & 0X40) //A falling edge is caught //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD><EFBFBD>
|
||||
{
|
||||
TIM8CH4_CAPTURE_DOWNVAL = TIM_GetCapture4(TIM8); //Record the timer value at this point //记录下此时的定时器计数值
|
||||
TIM8CH4_CAPTURE_DOWNVAL = TIM_GetCapture4(TIM8); //Record the timer value at this point //<EFBFBD><EFBFBD>¼<EFBFBD>´<EFBFBD>ʱ<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
if (TIM8CH4_CAPTURE_DOWNVAL < TIM8CH4_CAPTURE_UPVAL)
|
||||
{
|
||||
TIM8_T4 = 9999;
|
||||
}
|
||||
else
|
||||
TIM8_T4 = 0;
|
||||
Remoter_Ch4 = TIM8CH4_CAPTURE_DOWNVAL - TIM8CH4_CAPTURE_UPVAL + TIM8_T4; //Time to get the total high level //得到总的高电平的时间
|
||||
if(abs(Remoter_Ch4-L_Remoter_Ch4)>500)Remoter_Ch4=L_Remoter_Ch4; //Filter //滤波
|
||||
Remoter_Ch4 = TIM8CH4_CAPTURE_DOWNVAL - TIM8CH4_CAPTURE_UPVAL + TIM8_T4; //Time to get the total high level //<EFBFBD>õ<EFBFBD><EFBFBD>ܵĸߵ<EFBFBD>ƽ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
if(abs(Remoter_Ch4-L_Remoter_Ch4)>500)Remoter_Ch4=L_Remoter_Ch4; //Filter //<EFBFBD>˲<EFBFBD>
|
||||
L_Remoter_Ch4=Remoter_Ch4;
|
||||
TIM8CH4_CAPTURE_STA = 0; //Capture flag bit to zero //捕获标志位清零
|
||||
TIM_OC4PolarityConfig(TIM8, TIM_ICPolarity_Rising); //Set to rising edge capture //设置为上升沿捕获
|
||||
TIM8CH4_CAPTURE_STA = 0; //Capture flag bit to zero //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_OC4PolarityConfig(TIM8, TIM_ICPolarity_Rising); //Set to rising edge capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
}
|
||||
else
|
||||
{
|
||||
//When the capture time occurs but not the falling edge, the first time the rising edge is captured, record the timer value at this time
|
||||
//发生捕获时间但不是下降沿,第一次捕获到上升沿,记录此时的定时器计数值
|
||||
TIM8CH4_CAPTURE_UPVAL = TIM_GetCapture4(TIM8); //Obtain rising edge data //获取上升沿数据
|
||||
TIM8CH4_CAPTURE_STA |= 0X40; //The flag has been caught on the rising edge //标记已捕获到上升沿
|
||||
TIM_OC4PolarityConfig(TIM8, TIM_ICPolarity_Falling); //Set to Falling Edge Capture //设置为下降沿捕获
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>䵫<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>β<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>ʱ<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
TIM8CH4_CAPTURE_UPVAL = TIM_GetCapture4(TIM8); //Obtain rising edge data //<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM8CH4_CAPTURE_STA |= 0X40; //The flag has been caught on the rising edge //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
TIM_OC4PolarityConfig(TIM8, TIM_ICPolarity_Falling); //Set to Falling Edge Capture //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>½<EFBFBD><EFBFBD>ز<EFBFBD><EFBFBD><EFBFBD>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,25 +312,25 @@ void TIM8_CC_IRQHandler(void)
|
||||
Function: TIM1 Update Interrupt
|
||||
Input : none
|
||||
Output : none
|
||||
函数功能:定时器8更新中断
|
||||
入口参数:无
|
||||
返回 值:无
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>8<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
|
||||
<EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ֵ<><D6B5><EFBFBD><EFBFBD>
|
||||
**************************************************************************/
|
||||
void TIM8_UP_TIM13_IRQHandler(void)
|
||||
{
|
||||
//Clear the interrupt flag bit
|
||||
//清除中断标志位
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϱ<EFBFBD>־λ
|
||||
TIM8->SR&=~(1<<0);
|
||||
}
|
||||
|
||||
void TIM8_SERVO_Init(u16 arr,u16 psc)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure; //IO
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定时器
|
||||
TIM_OCInitTypeDef TIM_OCInitStructure; //PWM输出
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
TIM_OCInitTypeDef TIM_OCInitStructure; //PWM<EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM1时钟使能
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //使能PORTE时钟
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM1ʱ<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //ʹ<EFBFBD><EFBFBD>PORTEʱ<EFBFBD><EFBFBD>
|
||||
|
||||
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
|
||||
@@ -345,55 +345,55 @@ void TIM8_SERVO_Init(u16 arr,u16 psc)
|
||||
GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_TIM8);
|
||||
|
||||
|
||||
/*** Initialize timer 1 || 初始化定时器1 ***/
|
||||
//Set the counter to automatically reload //设定计数器自动重装值
|
||||
/*** Initialize timer 1 || <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>1 ***/
|
||||
//Set the counter to automatically reload //<EFBFBD>趨<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>װֵ
|
||||
TIM_TimeBaseStructure.TIM_Period = arr;
|
||||
//Pre-divider //预分频器
|
||||
//Pre-divider //Ԥ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>
|
||||
TIM_TimeBaseStructure.TIM_Prescaler = psc;
|
||||
//Set the clock split: TDTS = Tck_tim //设置时钟分割:TDTS = Tck_tim
|
||||
//Set the clock split: TDTS = Tck_tim //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>ӷָ<EFBFBD>:TDTS = Tck_tim
|
||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||
//TIM up count mode //TIM向上计数模式
|
||||
//TIM up count mode //TIM<EFBFBD><EFBFBD><EFBFBD>ϼ<EFBFBD><EFBFBD><EFBFBD>ģʽ
|
||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||
//Initializes the timebase unit for TIMX based on the parameter specified in TIM_TimeBaseInitStruct
|
||||
//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>TIM_TimeBaseInitStruct<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>TIMx<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ
|
||||
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
|
||||
|
||||
|
||||
//-----------舵机初始化-----------//
|
||||
//-----------<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>-----------//
|
||||
//Select Timer mode :TIM Pulse Width Modulation mode 1
|
||||
//选择定时器模式:TIM脉冲宽度调制模式1
|
||||
//ѡ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ģʽ:TIM<49><4D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȵ<EFBFBD><C8B5><EFBFBD>ģʽ1
|
||||
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||||
//Compare output enablement
|
||||
//比较输出使能
|
||||
//<EFBFBD>Ƚ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>
|
||||
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
|
||||
//Set the pulse value of the capture comparison register to be loaded
|
||||
//设置待装入捕获比较寄存器的脉冲值
|
||||
//<EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD>װ<EFBFBD>벶<EFBFBD><EFBFBD>ȽϼĴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
TIM_OCInitStructure.TIM_Pulse = 0;
|
||||
//Output polarity :TIM output polarity is higher
|
||||
//输出极性:TIM输出比较极性高
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:TIM<49><4D><EFBFBD><EFBFBD>Ƚϼ<C8BD><CFBC>Ը<EFBFBD>
|
||||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
|
||||
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
|
||||
|
||||
//Initialize the peripheral TIMX based on the parameter specified in TIM_OCINITSTRUCT
|
||||
//根据TIM_OCInitStruct中指定的参数初始化外设TIMx
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>TIM_OCInitStruct<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>TIMx
|
||||
TIM_OC1Init(TIM8, &TIM_OCInitStructure);
|
||||
TIM_OC2Init(TIM8, &TIM_OCInitStructure);
|
||||
TIM_OC3Init(TIM8, &TIM_OCInitStructure);
|
||||
TIM_OC4Init(TIM8, &TIM_OCInitStructure);
|
||||
//Channel preload enable
|
||||
//通道预装载使能
|
||||
//ͨ<EFBFBD><EFBFBD>Ԥװ<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>
|
||||
TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable);
|
||||
TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable);
|
||||
TIM_OC3PreloadConfig(TIM8, TIM_OCPreload_Enable);
|
||||
TIM_OC4PreloadConfig(TIM8, TIM_OCPreload_Enable);
|
||||
//-----------舵机初始化-----------//
|
||||
//-----------<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>-----------//
|
||||
|
||||
TIM_CtrlPWMOutputs(TIM8,ENABLE);
|
||||
//Enable timer //使能定时器
|
||||
//Enable timer //ʹ<EFBFBD>ܶ<EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
TIM_Cmd(TIM8, ENABLE);
|
||||
|
||||
//The channel value is initialized to 1500, corresponding to the steering gear zero
|
||||
//通道值初始化为1500,舵机零点对应值
|
||||
//ͨ<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>Ϊ1500<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧֵ
|
||||
// TIM8->CCR1=1500;
|
||||
// TIM8->CCR2=1500;
|
||||
// TIM8->CCR3=1500;
|
||||
@@ -404,11 +404,11 @@ void TIM8_SERVO_Init(u16 arr,u16 psc)
|
||||
void TIM12_SERVO_Init(u16 arr,u16 psc)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure; //IO
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定时器
|
||||
TIM_OCInitTypeDef TIM_OCInitStructure; //PWM输出
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
TIM_OCInitTypeDef TIM_OCInitStructure; //PWM<EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12,ENABLE); //TIM1时钟使能
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //使能PORTE时钟
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12,ENABLE); //TIM1ʱ<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //ʹ<EFBFBD><EFBFBD>PORTEʱ<EFBFBD><EFBFBD>
|
||||
|
||||
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15;
|
||||
@@ -421,48 +421,48 @@ void TIM12_SERVO_Init(u16 arr,u16 psc)
|
||||
GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_TIM12);
|
||||
|
||||
|
||||
/*** Initialize timer 1 || 初始化定时器1 ***/
|
||||
//Set the counter to automatically reload //设定计数器自动重装值
|
||||
/*** Initialize timer 1 || <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>1 ***/
|
||||
//Set the counter to automatically reload //<EFBFBD>趨<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>װֵ
|
||||
TIM_TimeBaseStructure.TIM_Period = arr;
|
||||
//Pre-divider //预分频器
|
||||
//Pre-divider //Ԥ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>
|
||||
TIM_TimeBaseStructure.TIM_Prescaler = psc;
|
||||
//Set the clock split: TDTS = Tck_tim //设置时钟分割:TDTS = Tck_tim
|
||||
//Set the clock split: TDTS = Tck_tim //<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>ӷָ<EFBFBD>:TDTS = Tck_tim
|
||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||
//TIM up count mode //TIM向上计数模式
|
||||
//TIM up count mode //TIM<EFBFBD><EFBFBD><EFBFBD>ϼ<EFBFBD><EFBFBD><EFBFBD>ģʽ
|
||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||
//Initializes the timebase unit for TIMX based on the parameter specified in TIM_TimeBaseInitStruct
|
||||
//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>TIM_TimeBaseInitStruct<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>TIMx<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ
|
||||
TIM_TimeBaseInit(TIM12, &TIM_TimeBaseStructure);
|
||||
|
||||
|
||||
//-----------舵机初始化-----------//
|
||||
//-----------<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>-----------//
|
||||
//Select Timer mode :TIM Pulse Width Modulation mode 1
|
||||
//选择定时器模式:TIM脉冲宽度调制模式1
|
||||
//ѡ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ģʽ:TIM<49><4D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȵ<EFBFBD><C8B5><EFBFBD>ģʽ1
|
||||
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||||
//Compare output enablement
|
||||
//比较输出使能
|
||||
//<EFBFBD>Ƚ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>
|
||||
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
|
||||
//Set the pulse value of the capture comparison register to be loaded
|
||||
//设置待装入捕获比较寄存器的脉冲值
|
||||
//<EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD>װ<EFBFBD>벶<EFBFBD><EFBFBD>ȽϼĴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||
TIM_OCInitStructure.TIM_Pulse = 0;
|
||||
//Output polarity :TIM output polarity is higher
|
||||
//输出极性:TIM输出比较极性高
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:TIM<49><4D><EFBFBD><EFBFBD>Ƚϼ<C8BD><CFBC>Ը<EFBFBD>
|
||||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
|
||||
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
|
||||
|
||||
//Initialize the peripheral TIMX based on the parameter specified in TIM_OCINITSTRUCT
|
||||
//根据TIM_OCInitStruct中指定的参数初始化外设TIMx
|
||||
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD>TIM_OCInitStruct<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>TIMx
|
||||
TIM_OC1Init(TIM12, &TIM_OCInitStructure);
|
||||
TIM_OC2Init(TIM12, &TIM_OCInitStructure);
|
||||
//Channel preload enable
|
||||
//通道预装载使能
|
||||
//ͨ<EFBFBD><EFBFBD>Ԥװ<EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>
|
||||
TIM_OC1PreloadConfig(TIM12, TIM_OCPreload_Enable);
|
||||
TIM_OC2PreloadConfig(TIM12, TIM_OCPreload_Enable);
|
||||
//-----------舵机初始化-----------//
|
||||
//-----------<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>-----------//
|
||||
|
||||
|
||||
TIM_CtrlPWMOutputs(TIM12,ENABLE);
|
||||
//Enable timer //使能定时器
|
||||
//Enable timer //ʹ<EFBFBD>ܶ<EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
TIM_Cmd(TIM12, ENABLE);
|
||||
|
||||
//Initialize both servo channels to the configured steering center.
|
||||
@@ -471,3 +471,83 @@ void TIM12_SERVO_Init(u16 arr,u16 psc)
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Function: Free-running microsecond time base for sensor timestamps
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>뼶<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||
TIM7 counts at 1 MHz (1 tick = 1 us) and wraps every 65.536 ms. An update
|
||||
interrupt increments a 32-bit high word, extending the clock to 48 usable
|
||||
bits (~8.9 years) that only ever counts up. Timers TIM2-TIM5 are taken by
|
||||
the encoders and TIM8 by input capture, so TIM7 is the free APB1 timer.
|
||||
TIM7 <20><> 1MHz <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 65.536ms <20><><EFBFBD>ƣ<EFBFBD><C6A3><EFBFBD><EFBFBD>¸<EFBFBD><C2B8>ж<EFBFBD><D0B6><EFBFBD>λ<EFBFBD><CEBB> 32λ<32><CEBB><EFBFBD>ָߣ<D6B8>
|
||||
<EFBFBD><EFBFBD>չ<EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>䡣TIM2~TIM5 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD>TIM8 <20><><EFBFBD>벶<EFBFBD><EBB2B6><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD>
|
||||
<EFBFBD><EFBFBD> TIM7 <20><><EFBFBD>С<EFBFBD>
|
||||
**************************************************************************/
|
||||
static volatile uint32_t g_time_high = 0;
|
||||
|
||||
void TIM7_Init(void)
|
||||
{
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
|
||||
|
||||
//APB1 timer clock = 84 MHz, prescaler 84 -> 1 MHz (1 us per tick).
|
||||
//APB1 <20><>ʱ<EFBFBD><CAB1>ʱ<EFBFBD><CAB1> 84MHz<48><7A>Ԥ<EFBFBD><D4A4>Ƶ 84 -> 1MHz<48><7A>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD> 1us<75><73>
|
||||
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
|
||||
TIM_TimeBaseStructure.TIM_Prescaler = 84 - 1;
|
||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||
TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
|
||||
|
||||
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
|
||||
TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);
|
||||
|
||||
//Keep the overflow ISR below configMAX_SYSCALL_INTERRUPT_PRIORITY so it
|
||||
//never calls FreeRTOS APIs; it only bumps a counter.
|
||||
//<2F>жϲ<D0B6><CFB2><EFBFBD><EFBFBD><EFBFBD> FreeRTOS API<50><49><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD><C8BC>ϵͣ<CFB5><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȿ<EFBFBD><C8BF>ơ<EFBFBD>
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
TIM_Cmd(TIM7, ENABLE);
|
||||
}
|
||||
|
||||
void TIM7_IRQHandler(void)
|
||||
{
|
||||
if(TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)
|
||||
{
|
||||
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
|
||||
g_time_high++;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Function: Read the 64-bit monotonic microsecond timestamp
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD>ȡ 64λ<34><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><CEA2>ʱ<EFBFBD><CAB1><EFBFBD>
|
||||
Glitch-free composition: re-read the high word around CNT and, if the
|
||||
update flag is pending while CNT is still low, account for the overflow
|
||||
that the ISR has not serviced yet.
|
||||
<EFBFBD><EFBFBD>ֹ<EFBFBD><EFBFBD>϶<EFBFBD><EFBFBD><EFBFBD>ѣ<EFBFBD><EFBFBD><EFBFBD> CNT <20><>Χ<EFBFBD><CEA7><EFBFBD>ζ<EFBFBD><CEB6>߰<EFBFBD><DFB0>֣<EFBFBD><D6A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ط<EFBFBD><D8B7><EFBFBD><EFBFBD><EFBFBD> CNT <20><>ϵ<EFBFBD>ͣ<EFBFBD>
|
||||
˵<EFBFBD><EFBFBD> ISR <20><>δ<EFBFBD><CEB4><EFBFBD><EFBFBD><EFBFBD>ûأ<C3BB><D8A3>ֶ<EFBFBD><D6B6><EFBFBD>λ<EFBFBD><CEBB>
|
||||
**************************************************************************/
|
||||
uint64_t mcu_time_us(void)
|
||||
{
|
||||
uint32_t high1, high2, cnt, sr;
|
||||
|
||||
do {
|
||||
high1 = g_time_high;
|
||||
cnt = TIM7->CNT;
|
||||
sr = TIM7->SR;
|
||||
high2 = g_time_high;
|
||||
} while(high1 != high2);
|
||||
|
||||
//Overflow happened but the update ISR has not run yet.
|
||||
//<2F>ѻ<EFBFBD><D1BB>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>¸<EFBFBD><C2B8>ж<EFBFBD><D0B6><EFBFBD>δִ<CEB4>С<EFBFBD>
|
||||
if((sr & TIM_SR_UIF) && cnt < 0x8000U)
|
||||
high1++;
|
||||
|
||||
return ((uint64_t)high1 << 16) | cnt;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
void TIM8_Cap_Init(u16 arr, u16 psc);
|
||||
void TIM12_SERVO_Init(u16 arr,u16 psc);
|
||||
void TIM8_SERVO_Init(u16 arr,u16 psc);
|
||||
void TIM7_Init(void);
|
||||
uint64_t mcu_time_us(void);
|
||||
|
||||
extern int L_Remoter_Ch1,L_Remoter_Ch2,L_Remoter_Ch3,L_Remoter_Ch4;
|
||||
extern int Remoter_Ch1,Remoter_Ch2,Remoter_Ch3,Remoter_Ch4;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,33 +10,41 @@
|
||||
|
||||
#define FRAME_HEADER 0X7B //Frame_header //֡ͷ
|
||||
#define FRAME_TAIL 0X7D //Frame_tail //֡β
|
||||
#define SEND_DATA_SIZE 24
|
||||
//Frame grew 24 -> 44: appended session_id(4) + two 64-bit sample
|
||||
//timestamps(8+8) before the checksum/tail. Bytes 0..21 keep the legacy
|
||||
//layout so old parsers stay compatible; new fields live in the tail.
|
||||
//֡<><D6A1> 24 -> 44<34><34><EFBFBD><EFBFBD>У<EFBFBD><D0A3>/֡βǰ<C7B0><D7B7><EFBFBD><EFBFBD> session_id(4) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 64λ<34><CEBB><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>(8+8)<29><>
|
||||
//<2F>ֽ<EFBFBD> 0..21 <20><><EFBFBD>ֽ<EFBFBD>ϲ<EFBFBD><CFB2>֣<EFBFBD><D6A3>¾ֽ<C2BE><D6BD><EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD>
|
||||
#define SEND_DATA_SIZE 44
|
||||
#define RECEIVE_DATA_SIZE 11
|
||||
|
||||
/*****A structure for storing triaxial data of a gyroscope accelerometer*****/
|
||||
/*****用于存放陀螺仪加速度计三轴数据的结构体*********************************/
|
||||
/*****<EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǽ<EFBFBD><EFBFBD>ٶȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵĽṹ<EFBFBD><EFBFBD>*********************************/
|
||||
typedef struct __Mpu6050_Data_
|
||||
{
|
||||
short X_data; //2 bytes //2个字节
|
||||
short Y_data; //2 bytes //2个字节
|
||||
short Z_data; //2 bytes //2个字节
|
||||
short X_data; //2 bytes //2<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
short Y_data; //2 bytes //2<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
short Z_data; //2 bytes //2<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
}Mpu6050_Data;
|
||||
|
||||
/*******The structure of the serial port sending data************/
|
||||
/*******串口发送数据的结构体*************************************/
|
||||
/*******<EFBFBD><EFBFBD><EFBFBD>ڷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵĽṹ<EFBFBD><EFBFBD>*************************************/
|
||||
typedef struct _SEND_DATA_
|
||||
{
|
||||
unsigned char buffer[SEND_DATA_SIZE];
|
||||
struct _Sensor_Str_
|
||||
{
|
||||
unsigned char Frame_Header; //1个字节
|
||||
short X_speed; //2 bytes //2个字节
|
||||
short Y_speed; //2 bytes //2个字节
|
||||
short Z_speed; //2 bytes //2个字节
|
||||
short Power_Voltage; //2 bytes //2个字节
|
||||
Mpu6050_Data Accelerometer; //6 bytes //6个字节
|
||||
Mpu6050_Data Gyroscope; //6 bytes //6个字节
|
||||
unsigned char Frame_Tail; //1 bytes //1个字节
|
||||
unsigned char Frame_Header; //1<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
short X_speed; //2 bytes //2<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
short Y_speed; //2 bytes //2<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
short Z_speed; //2 bytes //2<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
short Power_Voltage; //2 bytes //2<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
Mpu6050_Data Accelerometer; //6 bytes //6<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
Mpu6050_Data Gyroscope; //6 bytes //6<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
unsigned int Session_Id; //4 bytes: MCU boot session ID //<2F><>MCU<43><55><EFBFBD><EFBFBD><EFBFBD>ỰID
|
||||
unsigned long long Speed_Time_us; //8 bytes: encoder sample time //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
|
||||
unsigned long long Imu_Time_us; //8 bytes: IMU sample time //IMU<4D><55><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
|
||||
unsigned char Frame_Tail; //1 bytes //1<><31><EFBFBD>ֽ<EFBFBD>
|
||||
}Sensor_Str;
|
||||
}SEND_DATA;
|
||||
|
||||
@@ -45,14 +53,21 @@ typedef struct _RECEIVE_DATA_
|
||||
unsigned char buffer[RECEIVE_DATA_SIZE];
|
||||
struct _Control_Str_
|
||||
{
|
||||
unsigned char Frame_Header; //1 bytes //1个字节
|
||||
float X_speed; //4 bytes //4个字节
|
||||
float Y_speed; //4 bytes //4个字节
|
||||
float Z_speed; //4 bytes //4个字节
|
||||
unsigned char Frame_Tail; //1 bytes //1个字节
|
||||
unsigned char Frame_Header; //1 bytes //1<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
float X_speed; //4 bytes //4<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
float Y_speed; //4 bytes //4<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
float Z_speed; //4 bytes //4<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
unsigned char Frame_Tail; //1 bytes //1<EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
|
||||
}Control_Str;
|
||||
}RECEIVE_DATA;
|
||||
|
||||
//Sample timestamps captured at acquisition time by their owning tasks, and
|
||||
//the per-boot session ID. Read by data_transition() when packing the frame.
|
||||
//<2F>ɸ<EFBFBD><C9B8>Բɼ<D4B2><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD>˲<EFBFBD><CBB2><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵͳ<CFB5><CDB3><EFBFBD>лỰID<49><44>
|
||||
//<2F><> data_transition() <20><><EFBFBD>֡ʱ<D6A1><CAB1>ȡ<EFBFBD><C8A1>
|
||||
extern volatile unsigned long long g_speed_sample_time_us;
|
||||
extern volatile unsigned long long g_imu_sample_time_us;
|
||||
extern volatile unsigned int g_session_id;
|
||||
|
||||
void data_task(void *pvParameters);
|
||||
void data_transition(void);
|
||||
@@ -64,6 +79,7 @@ void CAN_SEND(void);
|
||||
void uart1_init(u32 bound);
|
||||
void uart2_init(u32 bound);
|
||||
void uart3_init(u32 bound);
|
||||
void uart3_dma_tx_init(void);
|
||||
void uart5_init(u32 bound);
|
||||
|
||||
int USART1_IRQHandler(void);
|
||||
|
||||
3
Makefile
3
Makefile
@@ -31,7 +31,8 @@ FWLIB_SRC := \
|
||||
FWLIB/src/misc.c FWLIB/src/stm32f4xx_gpio.c FWLIB/src/stm32f4xx_rcc.c \
|
||||
FWLIB/src/stm32f4xx_syscfg.c FWLIB/src/stm32f4xx_usart.c \
|
||||
FWLIB/src/stm32f4xx_adc.c FWLIB/src/stm32f4xx_can.c \
|
||||
FWLIB/src/stm32f4xx_tim.c FWLIB/src/stm32f4xx_pwr.c
|
||||
FWLIB/src/stm32f4xx_tim.c FWLIB/src/stm32f4xx_pwr.c \
|
||||
FWLIB/src/stm32f4xx_dma.c
|
||||
|
||||
FREERTOS_SRC := \
|
||||
FreeRTOS/croutine.c FreeRTOS/event_groups.c FreeRTOS/list.c \
|
||||
|
||||
374
doc/ackermann_steering_calibration.md
Normal file
374
doc/ackermann_steering_calibration.md
Normal file
@@ -0,0 +1,374 @@
|
||||
# 阿克曼转向标定与拟合说明
|
||||
|
||||
本文记录阿克曼小车「(Vx, Vz) → 舵机 PWM + 左右后轮速度」控制律的标定数据、
|
||||
拟合方法、单位约定,三种控制模式(标定运动学 / 直接映射 / 横摆闭环),以及
|
||||
串口通信(200 Hz DMA 发送、921600 波特率)。对应代码:
|
||||
- 控制律:`BALANCE/balance.c` 的 `Akm_Car` 分支,
|
||||
`Akm_Curvature_To_Servo()`(拟合)与 `Akm_Norm_To_Servo()`(直接满行程映射)。
|
||||
- 开关宏:`BALANCE/robot_select_init.h`;舵机直行点 `SERVO_INIT` 在 `HARDWARE/motor.h`。
|
||||
- 串口:`HARDWARE/usartx.c`(`data_task` / `USART3_SEND` / `uart3_dma_tx_init`),
|
||||
波特率在 `BALANCE/system.c` 的 `systemInit`。
|
||||
|
||||
## 1. 硬件与坐标约定
|
||||
|
||||
- 后驱阿克曼:`MOTOR_A` = 左后轮,`MOTOR_B` = 右后轮,前轮由舵机(TIM12 CCR2)转向。
|
||||
- 输入语义(上位机下发):
|
||||
- `Vx` = 后轴中心线速度,单位 m/s。
|
||||
- `Vz` = 绕转弯中心的旋转角速度 wz,单位 rad/s。
|
||||
- 符号约定:
|
||||
- 上位机 `Vz` 遵循 ROS 约定:**Vz > 0 = 逆时针 = 左转**。
|
||||
- 标定表 / 舵机拟合使用相反符号:**曲率 κ > 0 = 右转**。
|
||||
- 代码中 `kappa_fit = -Vz/Vx`,使 `Vz > 0` 得到 `kappa_fit < 0`(左转),
|
||||
与拟合域一致。
|
||||
|
||||
## 2. 标定方法(手推法)
|
||||
|
||||
电机失能、舵机使能,手动推动小车走出稳定圆弧,对每个舵机 PWM 记录:
|
||||
|
||||
- `y 向半截距`(弧对应的纵向半截距,cm)
|
||||
- `x 向半弓高`(弦的矢高 / 半弓高,cm)
|
||||
- 由几何反推后轴中心转弯半径 `R`(cm)与 `1/R`
|
||||
|
||||
x 向半弓高的符号用于判定左右:PWM > ~1670 为右转(κ 取正),
|
||||
低于该点为左转(κ 取负)。
|
||||
|
||||
### 三个"中位"值(易混,务必区分)
|
||||
|
||||
| 名称 | 值 | 含义 | 代码位置 |
|
||||
|------|---:|------|----------|
|
||||
| 遥控 CH1 中位 | 1500 | 遥控摇杆物理中点 | `AKM_REMOTER_CH1_MID`(balance.c) |
|
||||
| 舵机机械中位 | 1600 | 舵机行程几何中点 (MIN+MAX)/2 | —(不再直接使用) |
|
||||
| **直行点 SERVO_INIT** | **1670** | **实测 1/R≈0、车真正走直线的点** | `SERVO_INIT`(motor.h:52) |
|
||||
|
||||
关键:**所有控制律的舵机中位都对齐到 `SERVO_INIT = 1670`**(真正的直行点),
|
||||
而非机械中位 1600。开机上电、Mode 1 / Mode 2 的零位、CH1 覆盖都以它为基准:
|
||||
- CH1 覆盖时舵机 = `Remoter_Ch1 + (SERVO_INIT - AKM_REMOTER_CH1_MID)`,即整体
|
||||
平移 `1670 - 1500 = +170`,使摇杆居中 = 车轮回正。
|
||||
- 改 `SERVO_INIT` 一处,下游所有路径自动对齐。
|
||||
|
||||
### 原始标定数据
|
||||
|
||||
| servo(pwm) | y半截距/cm | x半弓高/cm | R/cm | 1/R (1/cm) |
|
||||
|-----------:|----------:|----------:|-----:|-----------:|
|
||||
| 2000 | 34 | 34 | 34.00 | 0.029412 |
|
||||
| 1900 | 52.5 | 49.5 | 52.59 | 0.019015 |
|
||||
| 1800 | 90 | 60 | 97.50 | 0.010256 |
|
||||
| 1700 | 167.2 | 60 | 262.97 | 0.003803 |
|
||||
| 1670 | 120 | -1 | 7200.5 | 0.000139 |
|
||||
| 1600 | 120 | -23 | 324.54 | 0.003081 |
|
||||
| 1500 | 89 | -60 | 96.01 | 0.010416 |
|
||||
| 1400 | 61 | -60 | 61.01 | 0.016391 |
|
||||
| 1300 | 43 | -44 | 43.01 | 0.023250 |
|
||||
| 1200 | 35.5 | -34.3| 35.52 | 0.028152 |
|
||||
| 1100 | 30 | -28.9| 30.02 | 0.033310 |
|
||||
|
||||
> 直行点约在 PWM 1670(1/R ≈ 0,x 半弓高 ≈ 0),并非舵机机械中位 1600。
|
||||
|
||||
## 3. 单位换算(关键,曾导致 100 倍错误)
|
||||
|
||||
标定表 `1/R` 列以 **1/cm** 为单位(R 用厘米)。而代码里的曲率来自
|
||||
`kappa = wz / Vx`(均为 SI),单位是 **1/m**。两者相差 100 倍。
|
||||
|
||||
拟合前必须把 R 从 cm 换算为 m,再取 `kappa = 1/R_m`(并带符号):
|
||||
|
||||
| servo | kappa (1/m, +=右) |
|
||||
|------:|------------------:|
|
||||
| 2000 | +2.9412 |
|
||||
| 1900 | +1.9015 |
|
||||
| 1800 | +1.0256 |
|
||||
| 1700 | +0.3803 |
|
||||
| 1670 | +0.0139 |
|
||||
| 1600 | -0.3081 |
|
||||
| 1500 | -1.0416 |
|
||||
| 1400 | -1.6391 |
|
||||
| 1300 | -2.3250 |
|
||||
| 1200 | -2.8152 |
|
||||
| 1100 | -3.3310 |
|
||||
|
||||
- 曲率量程:κ ∈ [−3.331, +2.941] 1/m。
|
||||
- 最小转弯半径 R_min ≈ 0.30 m(左)/ 0.34 m(右)。
|
||||
- 代码中 `AKM_KAPPA_MAX = 3.331f`。
|
||||
|
||||
## 4. 拟合方法与结果
|
||||
|
||||
以 `servo = f(kappa)`(kappa 为自变量,1/m)做多项式最小二乘。
|
||||
比较一/二/三次,并用留一交叉验证(LOO)评估对未见点的泛化:
|
||||
|
||||
| 拟合 | 全量 max残差 | 全量 rms | LOO max误差 | LOO rms |
|
||||
|------|-----------:|--------:|----------:|-------:|
|
||||
| 一次 | 56.8 | 28.3 | — | — |
|
||||
| 二次 | 12.3 | 7.6 | 15.1 | 10.2 |
|
||||
| 三次 | 12.6 | 7.5 | — | — |
|
||||
|
||||
结论:**二次拟合最优**。三次不再改善(过拟合),一次残差过大。
|
||||
|
||||
### 最终系数(1/m 单位)
|
||||
|
||||
```
|
||||
servo = 1656.373 + 140.548 * kappa - 7.654 * kappa^2
|
||||
```
|
||||
|
||||
代码宏(`BALANCE/balance.c`):
|
||||
|
||||
```c
|
||||
#define AKM_SERVO_C0 1656.373f
|
||||
#define AKM_SERVO_C1 140.548f
|
||||
#define AKM_SERVO_C2 (-7.654f)
|
||||
#define AKM_SERVO_MIN 1100
|
||||
#define AKM_SERVO_MAX 2000
|
||||
#define AKM_KAPPA_MAX 3.331f
|
||||
```
|
||||
|
||||
### 为什么用拟合而非查表 + 线性插值
|
||||
|
||||
- 数据是手推测得,含测量噪声。查表被迫穿过每个噪声点,两点间直线段会
|
||||
放大噪声;LOO 显示查表 max 误差 23 / rms 14,明显差于二次拟合(15 / 10)。
|
||||
- 拟合在端点外推时形状正确(曲线两端明显弯),线性插值只能按最后一段
|
||||
斜率外推,越推越偏。
|
||||
- 拟合在节点处平滑,无斜率突变;运行成本仅两次乘加,比查找区间还省。
|
||||
|
||||
### 轴距 L 去哪了
|
||||
|
||||
标定表端到端直接测了 `servo → R`,已把「舵机 PWM → 前轮转角 →
|
||||
`R = L/tan(δ)`」整条链路及传动比、轮胎侧偏等真实效应吸收进拟合系数。
|
||||
因此无需再显式写 `R = Axle_spacing/tan(δ)`(那反而依赖不准的假设传动比)。
|
||||
后轮差速只用轮距 track 与 κ,本就不含 L。阿克曼几何没有丢,而是以更贴合
|
||||
实车的实测形式嵌入拟合。
|
||||
|
||||
## 5. 控制律(Mode 0:标定运动学,默认)
|
||||
|
||||
`AKM_DIRECT_MAP = 0` 时:
|
||||
|
||||
```
|
||||
kappa_geom = Vz / Vx (Vx≈0 时置 0,阿克曼无前进不能转向)
|
||||
kappa_fit = clamp(-kappa_geom, ±AKM_KAPPA_MAX)
|
||||
Servo = f(kappa_fit) # 二次拟合
|
||||
MOTOR_A(左) = Vx * (1 + 0.5*track*kappa_fit) # 后轮差速
|
||||
MOTOR_B(右) = Vx * (1 - 0.5*track*kappa_fit)
|
||||
```
|
||||
|
||||
物理特性:舵机角只决定转弯半径 R = 1/κ。
|
||||
- 固定舵机角、改 Vx → wz 随之变(走同一圆,快慢不同)。
|
||||
- 固定 wz、改 Vx → κ = wz/Vx 变 → 舵机角变(正确行为)。
|
||||
|
||||
### Vx–wz 可行域(κ_max ≈ 3.33 /m)
|
||||
|
||||
`|wz| <= Vx * κ_max`:
|
||||
|
||||
| Vx (m/s) | 可用 wz 范围 (rad/s) |
|
||||
|---------:|:--------------------|
|
||||
| 0.2 | [−0.67, 0.67] |
|
||||
| 0.3 | [−1.00, 1.00] |
|
||||
| 0.5 | [−1.67, 1.67] |
|
||||
| 1.0 | [−3.33, 3.33] |
|
||||
|
||||
> 例:固定 wz=0.12,需 Vx ≥ 0.036 m/s 才不被夹紧。之前 `AKM_KAPPA_MAX`
|
||||
> 误设为 0.0334(对应 R≈30 m)导致任何速度下都被夹死、改速度舵机不动,
|
||||
> 已随单位修正解决。
|
||||
|
||||
## 6. 控制律(Mode 1:直接映射,调试用)
|
||||
|
||||
`AKM_DIRECT_MAP = 1` 时(脱离阿克曼物理,用于隔离调试舵机/电机):
|
||||
|
||||
```
|
||||
vz_norm = clamp(Vz / AKM_DIRECT_VZ_FULL, ±1)
|
||||
Servo = Akm_Norm_To_Servo(vz_norm) # 以 SERVO_INIT 为零位的分段满行程映射
|
||||
MOTOR_A(左) = Vx # 无差速
|
||||
MOTOR_B(右) = Vx
|
||||
```
|
||||
|
||||
- `Vz` 线性铺满整个舵机行程 [AKM_SERVO_MIN, AKM_SERVO_MAX],与速度无关。
|
||||
- **零位对齐直行点**:`Akm_Norm_To_Servo` 以 `SERVO_INIT=1670`(而非机械中位
|
||||
1600)为中心,左右两侧各自缩放到自己的端点,即使中位偏置也能用满全行程:
|
||||
```
|
||||
span = (norm>=0) ? (SERVO_INIT - AKM_SERVO_MIN) # 左侧行程 1670-1100=570
|
||||
: (AKM_SERVO_MAX - SERVO_INIT) # 右侧行程 2000-1670=330
|
||||
Servo = SERVO_INIT - norm * span
|
||||
```
|
||||
- `Vz > 0`(左)→ `norm>0` → 靠近 AKM_SERVO_MIN(左端),符号与 ROS 一致。
|
||||
- `Vx` 原样给左右电机,不做曲率/差速运算。
|
||||
- 满量程输入由 `AKM_DIRECT_VZ_FULL`(默认 **1.0 rad/s**)设定。
|
||||
|
||||
> **`AKM_DIRECT_VZ_FULL` 的物理含义** = 上位机会发的最大 angular.z,Vz 到该值时
|
||||
> 舵机打满。它只决定"Vz→行程"的比例,不改变峰值转角(峰值由舵机端点 1100/2000
|
||||
> 决定,恒为 ~28°左 / 25°右)。太小→小 Vz 就饱和、失去比例控制;太大→常用区间
|
||||
> 只用到一小段行程、转角偏小。当前定为 1.0(Vz=±1.0 打满),把行程摊到 ±1 rad/s
|
||||
> 全区间,规划分辨率比 0.5 时翻倍。Vz 在 RX 中断里以 rad/s 到达
|
||||
> (usartx.c `XYZ_Target_Speed_transition`: raw/1000)。
|
||||
|
||||
## 7. 控制律(Mode 2:横摆角速度闭环 / 简化扭矩矢量)
|
||||
|
||||
`AKM_DIRECT_MAP = 0` 且 `AKM_YAW_ASSIST = 1` 时启用。
|
||||
|
||||
**动机(为什么要有 Mode 2)**:Mode 0 里 `κ = Vz/Vx`,同一个转向指令 `Vz` 在
|
||||
高速时曲率被 `Vx` 除小,舵机自动回正 —— 这就是"高速转弯打不动"的根源。Mode 2
|
||||
**主动解耦 w 与 v**:舵机由 `Vz` 直接决定(与 Mode 1 一样,不再除以 Vx),
|
||||
所以大 `Vz` 在任何速度都给出大前轮角;阿克曼只作为后轮差速的**前馈参考**,
|
||||
再叠加 IMU 横摆角速度 PI 闭环(简化扭矩矢量)。控制链路:
|
||||
|
||||
```
|
||||
Vz ─(直接满行程映射, 与Vx无关)→ 舵机主转向 Akm_Norm_To_Servo ← 方向主控,解耦
|
||||
Vx ───────────────────────────→ 左右轮基速 ← 驱动主控,解耦
|
||||
(Vx, κ_cmd) ─(阿克曼几何)→ r_ref ─→ 后轮差速前馈 + IMU PI ← akm 仅做前馈
|
||||
```
|
||||
|
||||
计算(fit 域 κ>0=右;ROS Vz>0=左=CCW;r>0=左转):
|
||||
|
||||
```
|
||||
vz_norm = clamp(Vz / AKM_DIRECT_VZ_FULL, ±1) # 转向指令,不含 Vx —— 关键解耦点
|
||||
Servo = Akm_Norm_To_Servo(vz_norm) # 与 Mode 1 完全相同的满行程直接映射
|
||||
# 以 SERVO_INIT 为零位,不走拟合曲线
|
||||
κ_cmd = -vz_norm * AKM_KAPPA_MAX # 仅用于构造下方前馈参考,不驱动舵机
|
||||
|
||||
r_ref = -κ_cmd * Vx # 阿克曼几何前馈的期望横摆角速度
|
||||
r_meas = AKM_GYRO_Z_SIGN * gyro[2] / AKM_GYRO_Z_TO_RADPS
|
||||
r_filt += AKM_YAW_IMU_LPF * (r_meas - r_filt) # 轻度一阶低通
|
||||
|
||||
e_r = r_ref - r_filt
|
||||
dv_ff = AKM_YAW_FF_ALPHA * 0.5 * track * r_ref # 几何前馈
|
||||
dv_fb = AKM_YAW_KP * e_r + AKM_YAW_KI * ∫e_r # PI 反馈(矩形积分, dt=1/200s)
|
||||
dv = clamp(dv_ff + dv_fb, ±AKM_YAW_MAX_DIFF_RATIO*|Vx|) # 带抗积分饱和
|
||||
|
||||
MOTOR_A(左) = Vx - dv
|
||||
MOTOR_B(右) = Vx + dv
|
||||
```
|
||||
|
||||
要点:
|
||||
- **解耦是核心**:`vz_norm` 只由 `Vz` 决定,不再 `Vz/Vx`,所以高速大转向不再被
|
||||
几何"稀释"。`Vx` 独立设定驱动基速。
|
||||
- **舵机走直接满行程映射,不走拟合**:Mode 2 的舵机与 Mode 1 / CH1 调试一致,
|
||||
用 `Akm_Norm_To_Servo(vz_norm)` 把转向指令线性铺满行程(以 `SERVO_INIT` 为
|
||||
零位),**不再调用标定拟合 `f(κ)`**。这样"高速转弯打不动"从根上消失——舵机角
|
||||
只看指令、与速度无关。(早期版本这里错用了 `f(κ_cmd)`,仍隐含耦合,已改正。)
|
||||
- **阿克曼降级为纯前馈**:`κ_cmd = -vz_norm*AKM_KAPPA_MAX` 只用来构造 `r_ref`
|
||||
——"若车按该曲率走出的理想横摆角速度",仅喂给后轮差速前馈;实际横摆由 IMU PI
|
||||
收敛,可克服前轮几何/打滑带来的偏差。`κ_cmd` 不参与舵机计算。
|
||||
- **退化关系**:`AKM_YAW_FF_ALPHA = 1` 且 `AKM_YAW_KP = AKM_YAW_KI = 0` 时,
|
||||
`dv = 0.5*track*r_ref = -0.5*track*κ_cmd*Vx`,即纯几何差速。α 是平滑旋钮:
|
||||
0 = 纯 IMU 反馈,1 = 纯几何前馈。
|
||||
- **低速冻结**:`|Vx| < AKM_YAW_MIN_SPEED` 时清零积分并停用差速(低速横摆角
|
||||
速度信噪比太差)。
|
||||
- 用原始角速度(`gyro[2]` 去零偏后的 LSB),不做航向角积分。
|
||||
|
||||
### 上位机规划用:发布 Vz → 大致前轮转角 δ
|
||||
|
||||
Mode 2 里舵机只由 `Vz` 决定(与 `Vx` 无关),所以上位机可直接按下表估转角。
|
||||
换算链路(非线性,因为 PWM→R 那段是标定曲线):
|
||||
|
||||
```
|
||||
vz_norm = clamp(Vz / AKM_DIRECT_VZ_FULL, ±1) # 默认 VZ_FULL=1.0 → Vz=±1.0 打满
|
||||
Servo = SERVO_INIT - vz_norm * span # 左 span=570, 右 span=330
|
||||
R = 1 / |1/R(Servo)| # 1/R 由 §2 标定表(1/cm)插值再×100
|
||||
δ = atan(L / R) # L = Akm_axlespacing = 0.160 m
|
||||
```
|
||||
|
||||
用当前宏值(`SERVO_INIT=1670`, `MIN=1100`, `MAX=2000`, `VZ_FULL=1.0`)、按 §2 标定表
|
||||
`1/R` 列插值算出的对照表(δ 为后轴等效前轮转角,正数只表大小,方向见末列):
|
||||
|
||||
| Vz (rad/s) | vz_norm | Servo(PWM) | R(m) | δ(°) | 方向 |
|
||||
|-----------:|--------:|-----------:|-----:|-----:|:----:|
|
||||
| +1.0 | +1.0 | 1100 | 0.30 | 28.1 | 左 |
|
||||
| +0.8 | +0.8 | 1214 | 0.36 | 23.7 | 左 |
|
||||
| +0.6 | +0.6 | 1328 | 0.47 | 18.8 | 左 |
|
||||
| +0.5 | +0.5 | 1385 | 0.57 | 15.6 | 左 |
|
||||
| +0.4 | +0.4 | 1442 | 0.72 | 12.5 | 左 |
|
||||
| +0.3 | +0.3 | 1499 | 0.95 | 9.5 | 左 |
|
||||
| +0.2 | +0.2 | 1556 | 1.59 | 5.8 | 左 |
|
||||
| +0.1 | +0.1 | 1613 | 3.95 | 2.3 | 左 |
|
||||
| 0.0 | 0.0 | 1670 | ∞ | 0.0 | 直 |
|
||||
| −0.1 | −0.1 | 1703 | 2.50 | 3.7 | 右 |
|
||||
| −0.2 | −0.2 | 1736 | 1.63 | 5.6 | 右 |
|
||||
| −0.3 | −0.3 | 1769 | 1.21 | 7.5 | 右 |
|
||||
| −0.4 | −0.4 | 1802 | 0.96 | 9.5 | 右 |
|
||||
| −0.5 | −0.5 | 1835 | 0.75 | 12.0 | 右 |
|
||||
| −0.6 | −0.6 | 1868 | 0.62 | 14.5 | 右 |
|
||||
| −0.8 | −0.8 | 1934 | 0.44 | 19.8 | 右 |
|
||||
| −1.0 | −1.0 | 2000 | 0.34 | 25.2 | 右 |
|
||||
|
||||
要点(上位机规划务必注意):
|
||||
- **左右不对称**:直行点 1670 偏向右端,左侧行程 570、右侧仅 330,所以同样
|
||||
`|Vz|` 左转角比右转角略大(满量程 28° 左 vs 25° 右)。这是机械中位偏置导致的,
|
||||
已被 `Akm_Norm_To_Servo` 的分段缩放吸收。
|
||||
- **`|Vz| ≥ 1.0` 全部饱和**到端点(28°左 / 25°右);再大的 Vz 不会有更大转角。
|
||||
`VZ_FULL` 从 0.5 提到 1.0 后,满量程指令 = ±1.0 rad/s,同样的舵机行程摊到更宽的
|
||||
Vz 区间,规划分辨率翻倍(峰值转角不变)。
|
||||
- **非线性**:Vz→δ 不是直线(低 Vz 段每 0.1 约 +3°,高 Vz 段趋缓),规划时按表
|
||||
插值而非线性外推。
|
||||
- R 是**后轴中心转弯半径**,δ = atan(L/R) 是等效前轮转角;实车受轮胎侧偏/打滑
|
||||
影响,表值为标定静推的近似,动态下 IMU 横摆环会再做修正。
|
||||
|
||||
调参顺序(用户建议):
|
||||
1. 先标定陀螺零偏(开机静止采样,代码已做)。
|
||||
2. **实测确认 `gyro[2]` 符号**:命令左转,确认 `gyro[2] > 0`;若相反把
|
||||
`AKM_GYRO_Z_SIGN` 改为 `-1.0f`。
|
||||
3. 小 `Kp`(0.05~0.10)起步,逐步加大到临界前。
|
||||
4. 有稳态误差再加一点 `Ki`。
|
||||
5. 最后引入前馈 `α = 0.2~0.5` 减轻 PI 负担。
|
||||
|
||||
## 8. 开关一览(`BALANCE/robot_select_init.h`)
|
||||
|
||||
| 宏 | 默认 | 含义 |
|
||||
|----|-----:|------|
|
||||
| `AKM_SERVO_DEBUG_REMOTE_CH1` | 1 | 1 = 舵机直接由遥控 CH1 驱动,覆盖所有控制律(板级调试) |
|
||||
| `AKM_DIRECT_MAP` | 1 | 1 = 直接映射调试模式;0 = 交给 Mode 0 / Mode 2 |
|
||||
| `AKM_DIRECT_VZ_FULL` | 1.0f | Mode 1 & Mode 2 共用:Vz 满行程量程(rad/s)= 上位机会发的最大 angular.z |
|
||||
| `AKM_YAW_ASSIST` | 0 | 1 = 横摆闭环(Mode 2);仅在 `AKM_DIRECT_MAP=0` 时生效 |
|
||||
| `AKM_YAW_KP` / `AKM_YAW_KI` | 0.10 / 0.00 | 横摆角速度误差 PI 增益(m/s per rad/s) |
|
||||
| `AKM_YAW_FF_ALPHA` | 0.00f | 几何前馈混合系数(0=纯反馈,1=纯几何差速=Mode 0) |
|
||||
| `AKM_YAW_MIN_SPEED` | 0.10f | 低于此速度冻结横摆环(m/s) |
|
||||
| `AKM_YAW_MAX_DIFF_RATIO` | 0.35f | 差速幅度上限(占 |Vx| 的比例) |
|
||||
| `AKM_GYRO_Z_TO_RADPS` | 3754.9f | gyro[2] LSB→rad/s(FS ±500dps) |
|
||||
| `AKM_GYRO_Z_SIGN` | +1.0f | IMU +z 与 ROS(+=左)符号对齐,实测确认 |
|
||||
| `AKM_YAW_IMU_LPF` | 0.30f | 横摆角速度一阶低通系数(0=无滤波) |
|
||||
|
||||
模式互斥与优先级:
|
||||
- `AKM_SERVO_DEBUG_REMOTE_CH1 = 1` 时,**舵机总是由 CH1 覆盖**,优先于任何控制
|
||||
律计算出的舵机值(电机差速仍按所选模式运行)。
|
||||
- `AKM_DIRECT_MAP` 与 `AKM_YAW_ASSIST` 都作用于整条控制律:`AKM_DIRECT_MAP = 1`
|
||||
优先(直接映射);`= 0` 时再看 `AKM_YAW_ASSIST`(1 = Mode 2 横摆闭环,
|
||||
0 = Mode 0 标定运动学)。
|
||||
|
||||
## 9. 串口通信(ROS ↔ STM32)
|
||||
|
||||
### 频率与方向
|
||||
|
||||
| 方向 | 频率 | 机制 | 代码位置 |
|
||||
|------|-----:|------|----------|
|
||||
| 控制环 | 200 Hz | `Balance_task`,`RATE_200_HZ` | balance.c:350 |
|
||||
| 发送(TX,STM32→ROS) | 200 Hz | **DMA 非阻塞** | usartx.c `data_task` |
|
||||
| 接收(RX,ROS→STM32) | 中断驱动 | `USART3_IRQHandler`(RXNE) | usartx.c |
|
||||
|
||||
- 只保留 **USART3(ROS)**。原先 `data_task` 20 Hz 阻塞式群发 USART1/3/5+CAN,
|
||||
现已删掉 USART1/USART5/CAN 发送,只留 USART3。
|
||||
- 帧长 24 字节(`SEND_DATA_SIZE`),`Vz` 在 RX 中断里由
|
||||
`XYZ_Target_Speed_transition` 解析:`raw/1000 + (raw%1000)*0.001`(rad/s)。
|
||||
|
||||
### 为什么改 DMA 非阻塞发送
|
||||
|
||||
旧的 `usart3_send` 是忙等:`USART3->DR = data; while((USART3->SR&0x40)==0);`。
|
||||
`data_task` 与 `Balance_task` **同为优先级 4**(FreeRTOS 抢占 + 时间片,1ms tick)。
|
||||
同优先级下忙等无法被控制环抢占,20→200 Hz 会放大抖动、白耗 CPU。改成 DMA 后:
|
||||
|
||||
- `USART3_SEND` 只触发一次 DMA 传输(DMA1 Stream3 / Channel4 = USART3_TX),
|
||||
CPU 立即返回,shift-out 期间不占用控制环。
|
||||
- 上一帧未发完则跳过本周期(`DMA_GetCmdStatus != DISABLE` 判定),不忙等。
|
||||
- 需要把 `FWLIB/src/stm32f4xx_dma.c` 加入 Makefile(原先未编译该驱动)。
|
||||
|
||||
### 波特率 921600
|
||||
|
||||
USART3 波特率 **115200 → 921600**(system.c:129,`uart3_init(921600)`)。
|
||||
|
||||
- 一帧 24 字节 = 240 bit(8N1,10 bit/byte)的 shift-out 时间:
|
||||
- 115200:240/115200 ≈ **2.08 ms**
|
||||
- 921600:240/921600 ≈ **0.26 ms**(快 8 倍,远低于 5 ms 周期)
|
||||
- 带宽占用:200 Hz × 24 B = 4800 B/s,两档都绰绰有余;提速主要是留余量。
|
||||
- APB1=42 MHz,16 倍过采样分频后实际约 913 k,偏差 ~0.9%(UART 容忍 <2.5%)。
|
||||
- **ROS 端必须同步改 921600**,否则乱码——这是最易漏的一步。
|
||||
|
||||
## 10. 复现拟合
|
||||
|
||||
标定原始脚本与中间产物在 `calibration/` 目录。核心步骤:
|
||||
1. R(cm) → R(m),`kappa = sign / R_m`(sign 由 x 半弓高定,+ 为右)。
|
||||
2. 对 `(kappa, servo)` 做二次最小二乘,得 C0/C1/C2。
|
||||
3. 用 LOO 交叉验证确认二次优于查表与三次。
|
||||
4. `AKM_KAPPA_MAX = max(|kappa|)`。
|
||||
111
doc/uart_protocol_v2_timestamp.md
Normal file
111
doc/uart_protocol_v2_timestamp.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# 下位机 UART 发送协议 v2(带采样时间戳)
|
||||
|
||||
本文件描述 STM32 下位机通过 **USART3(ROS 口,波特率 921600)** 周期发送给上位机的
|
||||
传感器数据帧格式。v2 在原 24 字节帧的基础上,于**帧尾追加**了会话 ID 与两个采样
|
||||
时间戳字段,用于上位机做 IMU / 轮速 / 雷达的时间对齐。
|
||||
|
||||
- 对应源码:[HARDWARE/usartx.c](../HARDWARE/usartx.c)、[HARDWARE/usartx.h](../HARDWARE/usartx.h)
|
||||
- 时间源实现:[HARDWARE/timer.c](../HARDWARE/timer.c) 的 `TIM7_Init()` / `mcu_time_us()`
|
||||
- 设计背景与总体原则见 [时间戳.md](时间戳.md)
|
||||
|
||||
## 1. 帧总览
|
||||
|
||||
| 项目 | 值 |
|
||||
| ---- | ---- |
|
||||
| 帧头 `FRAME_HEADER` | `0x7B` |
|
||||
| 帧尾 `FRAME_TAIL` | `0x7D` |
|
||||
| 帧长 `SEND_DATA_SIZE` | **44 字节**(v1 为 24 字节) |
|
||||
| 发送周期 | 200 Hz(`data_task`,USART3 非阻塞 DMA 发送) |
|
||||
| 字节序 | 多字节字段一律 **大端**(高字节在前) |
|
||||
| 校验 | 单字节 XOR,覆盖 byte 0..41 |
|
||||
|
||||
设计约束:byte 0..21 与 v1 完全一致,新增字段全部放在校验位之前的尾部,
|
||||
使只读取旧字段的解析器仍然兼容。
|
||||
|
||||
## 2. 字节布局
|
||||
|
||||
| 偏移 | 长度 | 字段 | 类型 | 说明 |
|
||||
| ---- | ---- | ---- | ---- | ---- |
|
||||
| 0 | 1 | Frame_Header | u8 | 帧头 `0x7B` |
|
||||
| 1 | 1 | Flag_Stop | u8 | 软件失能标志(1=停车) |
|
||||
| 2 | 2 | X_speed | int16 | X 轴线速度,单位 mm/s,大端 |
|
||||
| 4 | 2 | Y_speed | int16 | Y 轴线速度,单位 mm/s,大端 |
|
||||
| 6 | 2 | Z_speed | int16 | Z 轴角速度,单位 mm/s(等效),大端 |
|
||||
| 8 | 2 | Accel_X | int16 | 加速度计 X(ROS 坐标),大端 |
|
||||
| 10 | 2 | Accel_Y | int16 | 加速度计 Y(ROS 坐标),大端 |
|
||||
| 12 | 2 | Accel_Z | int16 | 加速度计 Z(ROS 坐标),大端 |
|
||||
| 14 | 2 | Gyro_X | int16 | 陀螺仪 X(ROS 坐标),大端 |
|
||||
| 16 | 2 | Gyro_Y | int16 | 陀螺仪 Y(ROS 坐标),大端 |
|
||||
| 18 | 2 | Gyro_Z | int16 | 陀螺仪 Z(ROS 坐标),大端 |
|
||||
| 20 | 2 | Power_Voltage | int16 | 电池电压×1000,大端 |
|
||||
| **22** | **4** | **session_id** | **uint32** | 本次 MCU 启动会话 ID,大端 |
|
||||
| **26** | **8** | **speed_sample_time_us** | **uint64** | 编码器采样时刻(μs),大端 |
|
||||
| **34** | **8** | **imu_sample_time_us** | **uint64** | IMU 采样时刻(μs),大端 |
|
||||
| 42 | 1 | Checksum | u8 | byte 0..41 的 XOR |
|
||||
| 43 | 1 | Frame_Tail | u8 | 帧尾 `0x7D` |
|
||||
|
||||
加粗行为 v2 相对 v1 的新增字段。
|
||||
|
||||
## 3. 时间源
|
||||
|
||||
时间戳由自由运行的 **TIM7** 提供,见 [HARDWARE/timer.c](../HARDWARE/timer.c):
|
||||
|
||||
- TIM7 挂在 APB1,定时器时钟 84 MHz,预分频 84 → **1 MHz 计数(1 tick = 1 μs)**。
|
||||
- 16 位计数器每 65.536 ms 回绕一次,更新中断把高 32 位软件计数 `g_time_high` 加一。
|
||||
- `mcu_time_us()` 返回 `(g_time_high << 16) | CNT`,即**自上电以来的单调递增微秒数**,
|
||||
可用位宽 48 位(约 8.9 年不回绕)。
|
||||
- TIM2~TIM5 被四路编码器占用、TIM8 被航模遥控输入捕获占用,故选空闲的 TIM7。
|
||||
- TIM7 更新中断优先级设为 5(数值大于 `configMAX_SYSCALL_INTERRUPT_PRIORITY`
|
||||
对应的抢占门限),ISR 内只做自增,不调用任何 FreeRTOS API。
|
||||
|
||||
> 注意:`mcu_time_us()` 只增不减,绝不因校时而跳变。上位机负责维护
|
||||
> `T_host = a·t_mcu + b` 的时钟映射(见 [时间戳.md](时间戳.md) 第 7、8 节)。
|
||||
|
||||
## 4. 两个时间戳分别打在哪里
|
||||
|
||||
v1 只有"发送时刻"隐含语义,无法表达 IMU(100 Hz)与轮速(200 Hz)是**异步采集**的。
|
||||
v2 在各自真实采样点打点,写入全局变量,`data_transition()` 打包时快照:
|
||||
|
||||
| 时间戳 | 打点位置 | 采样率 |
|
||||
| ---- | ---- | ---- |
|
||||
| `speed_sample_time_us` | [balance.c](../BALANCE/balance.c) `Get_Velocity_Form_Encoder()` 读编码器锁存计数器的瞬间 | 200 Hz |
|
||||
| `imu_sample_time_us` | [MPU6050.c](../HARDWARE/MPU6050/MPU6050.c) `MPU6050_task` I2C 读取前 | 100 Hz |
|
||||
|
||||
因此一帧内同时带两个时间戳:上位机应把加速度/角速度对齐到 `imu_sample_time_us`,
|
||||
把 X/Y/Z 速度对齐到 `speed_sample_time_us`,而不是共用一个发送时刻。
|
||||
|
||||
> IMU 打点在 I2C 突发读取之前,是在没有 DRDY(数据就绪)中断条件下能取到的、
|
||||
> 最接近物理采样的时刻。若日后接入 MPU 的 DRDY 引脚中断,可把打点移到中断里进一步减小抖动。
|
||||
|
||||
## 5. session_id
|
||||
|
||||
- 定义在 [usartx.c](../HARDWARE/usartx.c):`g_session_id`。
|
||||
- 当前实现为**固定值 `0xA5A5A5A5`**。
|
||||
- 用途:上位机据此判断下位机是否重启过(重启后 `mcu_time_us()` 从 0 重新计时,
|
||||
时钟映射 `a, b` 必须重新拟合)。
|
||||
- 待办:如需真正区分每次上电,应在启动时用熵源(如未初始化 RAM、启动 tick 等)
|
||||
生成一次性随机值。当前固定值只能表明"协议版本一致",不能区分不同启动会话。
|
||||
|
||||
## 6. 校验与解析建议
|
||||
|
||||
- 校验位 `buffer[42] = XOR(buffer[0..41])`,与 v1 的计算方式相同,只是范围从 22 扩到 42。
|
||||
- 上位机解析步骤:
|
||||
1. 同步帧头 `0x7B`;
|
||||
2. 读满 44 字节;
|
||||
3. 校验 `buffer[43] == 0x7D` 且 `XOR(buffer[0..41]) == buffer[42]`;
|
||||
4. 按上表大端解出各字段。
|
||||
- 多字节字段务必按大端手动组装,不要直接 `memcpy` 结构体(编译器填充/对齐/端序差异)。
|
||||
|
||||
## 7. 其他发送通道
|
||||
|
||||
| 通道 | 现状 |
|
||||
| ---- | ---- |
|
||||
| USART3(ROS 主口,DMA) | 已用 `SEND_DATA_SIZE`,自动发送完整 44 字节 |
|
||||
| USART1 / USART5 | 已改用 `SEND_DATA_SIZE`,发送完整 44 字节 |
|
||||
| CAN | 当前未被调用;`CAN_SEND()` 仍按 8×3=24 字节分包,**不含时间戳字段**。如需经 CAN 传时间戳需另行扩展分包 |
|
||||
|
||||
## 8. 上位机适配提醒
|
||||
|
||||
USART3 收到的帧已从 24 字节变为 **44 字节**。上位机(ROS 端)解析代码必须同步更新:
|
||||
帧长、校验范围、以及尾部三个新字段的读取。否则会因帧长不符导致解析错位。
|
||||
|
||||
349
doc/时间戳.md
Normal file
349
doc/时间戳.md
Normal file
@@ -0,0 +1,349 @@
|
||||
针对现在的“FreeRTOS 下位机 + Linux/ROS 2 上位机 + 后续轮速/IMU/2D雷达融合”,建议直接制定一套统一的时间戳与通信协议。
|
||||
|
||||
最核心的原则是:
|
||||
|
||||
[
|
||||
\boxed{
|
||||
\text{MCU原始单调时间戳永不修改}
|
||||
\quad+\quad
|
||||
\text{上位机维护时钟映射}
|
||||
}
|
||||
]
|
||||
|
||||
即:
|
||||
|
||||
[
|
||||
T_{\rm host}=a,t_{\rm mcu}+b
|
||||
]
|
||||
|
||||
## 1. 下位机统一时间基准
|
||||
|
||||
不要把 `xTaskGetTickCount()` 作为传感器主时间戳。
|
||||
|
||||
它适合:
|
||||
|
||||
* `vTaskDelayUntil()` 周期调度;
|
||||
* 超时判断;
|
||||
* 任务延时;
|
||||
* 毫秒级状态机。
|
||||
|
||||
它不适合:
|
||||
|
||||
* IMU与编码器精确对齐;
|
||||
* 200 Hz以上传感器采样;
|
||||
* 分析通信延迟;
|
||||
* 后续雷达、IMU、轮式里程计融合。
|
||||
|
||||
FreeRTOS Tick 的分辨率由 `configTICK_RATE_HZ` 决定;ISR 中若确实要读 Tick,应使用 `xTaskGetTickCountFromISR()`。[FreeRTOS Task Utilities](https://www.freertos.org/Documentation/02-Kernel/04-API-references/03-Task-utilities/00-Task-utilities)
|
||||
|
||||
### 推荐时间源
|
||||
|
||||
使用一个32位硬件定时器:
|
||||
|
||||
```text
|
||||
计数频率:1 MHz
|
||||
计数单位:1 us
|
||||
自动重装值:0xFFFFFFFF
|
||||
软件扩展:64 bit
|
||||
时间含义:MCU自本次上电以来经过的微秒数
|
||||
```
|
||||
|
||||
例如 STM32 可以使用 TIM2 或 TIM5:
|
||||
|
||||
[
|
||||
t_{\rm mcu}\in uint64_t,\qquad 单位=\mu s
|
||||
]
|
||||
|
||||
32位、1 MHz计数器约每71.58分钟回绕一次,所以用更新中断增加高32位。
|
||||
|
||||
```c
|
||||
static volatile uint32_t g_time_high = 0;
|
||||
|
||||
void TIM2_IRQHandler(void)
|
||||
{
|
||||
if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET) {
|
||||
__HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE);
|
||||
g_time_high++;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t mcu_time_us(void)
|
||||
{
|
||||
uint32_t high1;
|
||||
uint32_t high2;
|
||||
uint32_t low;
|
||||
uint32_t status;
|
||||
|
||||
do {
|
||||
high1 = g_time_high;
|
||||
__DMB();
|
||||
|
||||
low = TIM2->CNT;
|
||||
status = TIM2->SR;
|
||||
|
||||
__DMB();
|
||||
high2 = g_time_high;
|
||||
} while (high1 != high2);
|
||||
|
||||
/*
|
||||
* 计数器已经回绕,但更新中断可能还没有得到执行。
|
||||
* low 小于半量程,说明读取发生在回绕之后。
|
||||
*/
|
||||
if ((status & TIM_SR_UIF) && low < 0x80000000U) {
|
||||
high1++;
|
||||
}
|
||||
|
||||
return ((uint64_t)high1 << 32) | low;
|
||||
}
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
* 定时器时钟必须确认是否受 APB 分频后的“定时器倍频”影响;
|
||||
* 不要直接读取一个由中断写入的普通 `uint64_t`,32位MCU上未必原子;
|
||||
* 如果启用了 STOP 模式或 Tickless Idle,要确认这个定时器休眠时是否继续工作;
|
||||
* 时间戳只能递增,不能因为校时而向前或向后跳变。
|
||||
|
||||
## 2. 时间戳应该在哪里打
|
||||
|
||||
时间戳必须尽可能靠近数据真正产生的位置。
|
||||
|
||||
| 数据 | 推荐时间戳位置 |
|
||||
| -------- | ------------- |
|
||||
| IMU | DRDY中断发生时 |
|
||||
| SPI读取IMU | 不要等SPI读取完成才打点 |
|
||||
| 编码器 | 控制定时器锁存计数器时 |
|
||||
| 电机控制量 | PWM寄存器更新时 |
|
||||
| 控制周期 | 控制周期入口 |
|
||||
| 上位机接收 | 完整帧接收完成时,单独记录 |
|
||||
|
||||
例如:
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
uint64_t sample_time_us;
|
||||
int16_t gyro_raw[3];
|
||||
int16_t accel_raw[3];
|
||||
} ImuSample;
|
||||
```
|
||||
|
||||
IMU中断中只做:
|
||||
|
||||
1. 读取 `mcu_time_us()`;
|
||||
2. 保存时间戳;
|
||||
3. 通知采集任务;
|
||||
4. 立即退出中断。
|
||||
|
||||
不要在中断中完成协议编码、CRC计算和串口发送。
|
||||
|
||||
如果传感器内部启用了低通滤波,DRDY时间仍然可能比真实物理测量晚一个固定群延迟。后续可以增加:
|
||||
|
||||
```c
|
||||
corrected_time_us = drdy_time_us - imu_filter_delay_us;
|
||||
```
|
||||
|
||||
但必须在确定传感器滤波器延迟后再补偿。
|
||||
|
||||
## 3. FreeRTOS任务结构
|
||||
|
||||
建议使用:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["IMU DRDY / 控制定时器 ISR"] --> B["采样环形缓冲区"]
|
||||
B --> C["传感器处理任务"]
|
||||
C --> D["协议发送队列"]
|
||||
D --> E["唯一 UART TX 任务"]
|
||||
F["UART DMA / IDLE ISR"] --> G["接收环形缓冲区"]
|
||||
G --> H["协议解析任务"]
|
||||
```
|
||||
|
||||
关键规则:
|
||||
|
||||
* UART发送只能有一个所有者任务,避免多个任务发送的数据交叉;
|
||||
* UART接收使用DMA、IDLE中断和环形缓冲区;
|
||||
* ISR只负责搬运数据和通知任务;
|
||||
* 二进制协议和 `printf()` 调试日志不要共用同一个UART;
|
||||
* 如果ISR调用 FreeRTOS 的 `...FromISR()` 接口,中断优先级必须符合 `configMAX_SYSCALL_INTERRUPT_PRIORITY` 约束;
|
||||
* 周期任务使用 `vTaskDelayUntil()`,它能避免普通相对延时产生的累计漂移,但实际执行时刻仍应调用硬件微秒时钟记录。[FreeRTOS `vTaskDelayUntil()`](https://freertos.org/xtaskdelayuntiltask-control.html)
|
||||
|
||||
例如200 Hz低精度周期任务:
|
||||
|
||||
```c
|
||||
void SensorTask(void *argument)
|
||||
{
|
||||
TickType_t last_wake = xTaskGetTickCount();
|
||||
const TickType_t period = pdMS_TO_TICKS(5);
|
||||
|
||||
for (;;) {
|
||||
vTaskDelayUntil(&last_wake, period);
|
||||
|
||||
uint64_t actual_time_us = mcu_time_us();
|
||||
|
||||
/* 采集和处理 */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果要求更稳定的200 Hz采样,应由硬件定时器产生中断,再通知任务,而不是完全依赖 FreeRTOS Tick。
|
||||
|
||||
## 4. 推荐二进制帧规范 v1
|
||||
|
||||
假设使用 UART 或 USB CDC,建议采用:
|
||||
|
||||
```text
|
||||
COBS编码(协议头 + 负载 + CRC32) + 0x00帧分隔符
|
||||
```
|
||||
|
||||
COBS的好处是任意解析错误后,都可以在下一个 `0x00` 重新找到帧边界。
|
||||
|
||||
### 统一协议头:24字节
|
||||
|
||||
之前已有的基础上额外增加
|
||||
| session_id | uint32 | 4 | 本次MCU启动会话ID |
|
||||
| sample_time_us | uint64 | 8 | MCU采样时间 |
|
||||
|
||||
|
||||
但不要直接执行:
|
||||
|
||||
```c
|
||||
uart_send((uint8_t *)&header, sizeof(header)); // 不推荐
|
||||
```
|
||||
|
||||
因为不同编译器可能存在:
|
||||
|
||||
* 结构体填充;
|
||||
* 对齐差异;
|
||||
* 大小端差异;
|
||||
* 浮点格式差异。
|
||||
|
||||
|
|
||||
|
||||
|
||||
## 7. 四时间戳同步协议
|
||||
|
||||
每次同步记录:
|
||||
|
||||
* (T_1):上位机发送请求;
|
||||
* (t_2):MCU收到并解析请求;
|
||||
* (t_3):MCU准备发送响应;
|
||||
* (T_4):上位机收到完整响应。
|
||||
|
||||
定义MCU时间减上位机时间为:
|
||||
|
||||
[
|
||||
\theta=
|
||||
\frac{(t_2-T_1)+(t_3-T_4)}{2}
|
||||
]
|
||||
|
||||
往返延迟:
|
||||
|
||||
[
|
||||
d=(T_4-T_1)-(t_3-t_2)
|
||||
]
|
||||
|
||||
初始转换:
|
||||
|
||||
[
|
||||
T_{\rm host}\approx t_{\rm mcu}-\theta
|
||||
]
|
||||
|
||||
运行中收集多组:
|
||||
|
||||
[
|
||||
x_i=\frac{t_{2,i}+t_{3,i}}{2}
|
||||
]
|
||||
|
||||
[
|
||||
y_i=\frac{T_{1,i}+T_{4,i}}{2}
|
||||
]
|
||||
|
||||
拟合:
|
||||
|
||||
[
|
||||
\boxed{T_{\rm host}=a,t_{\rm mcu}+b}
|
||||
]
|
||||
|
||||
推荐参数:
|
||||
|
||||
* 启动时连续同步20~50次;
|
||||
* 初始阶段先令 (a=1),从最小RTT样本估计 (b);
|
||||
* 运行中每1秒同步一次;
|
||||
* 保存最近60~120组;
|
||||
* 丢弃RTT明显偏大的样本;
|
||||
* 使用RTT最小的20%~30%拟合 (a,b);
|
||||
* MCU时间戳本身永远不被“校准”或重写。
|
||||
|
||||
上位机使用 `CLOCK_MONOTONIC_RAW` 或 `std::chrono::steady_clock`,不要使用会被NTP校时改变的墙上时间参与控制。
|
||||
|
||||
## 8. ROS 2时间戳转换
|
||||
|
||||
MCU的“上电微秒数”不能直接填进 ROS 消息的 `header.stamp`,否则无法和激光雷达时间对齐。
|
||||
|
||||
上位机先得到:
|
||||
|
||||
[
|
||||
T_{\rm steady}=a,t_{\rm mcu}+b
|
||||
]
|
||||
|
||||
再在ROS桥接节点中保存一对锚点:
|
||||
|
||||
[
|
||||
(T_{\rm steady,0},T_{\rm ros,0})
|
||||
]
|
||||
|
||||
转换为:
|
||||
|
||||
[
|
||||
T_{\rm ros,sample}
|
||||
==================
|
||||
|
||||
T_{\rm ros,0}
|
||||
+
|
||||
(T_{\rm steady,sample}-T_{\rm steady,0})
|
||||
]
|
||||
|
||||
然后将这个时间填入:
|
||||
|
||||
* `sensor_msgs/Imu.header.stamp`;
|
||||
* `nav_msgs/Odometry.header.stamp`;
|
||||
* 编码器或轮速自定义消息时间戳。
|
||||
|
||||
这样轮速、IMU和激光雷达才能在同一ROS时间轴上融合。
|
||||
|
||||
## 9. 上位机命令不要依赖绝对时间
|
||||
|
||||
普通运动命令建议使用“接收后立即执行+超时”:
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
uint32_t command_sequence;
|
||||
uint32_t valid_for_us;
|
||||
float velocity_ref;
|
||||
float yaw_rate_ref;
|
||||
} MotionCommand;
|
||||
```
|
||||
|
||||
MCU收到时记录:
|
||||
|
||||
```c
|
||||
last_command_rx_us = mcu_time_us();
|
||||
```
|
||||
|
||||
安全判断:
|
||||
|
||||
```c
|
||||
if (mcu_time_us() - last_command_rx_us > command.valid_for_us) {
|
||||
enter_safe_deceleration();
|
||||
}
|
||||
```
|
||||
|
||||
只有真正需要未来定时执行时,才让上位机通过逆映射计算:
|
||||
|
||||
[
|
||||
t_{\rm mcu,execute}
|
||||
===================
|
||||
|
||||
\frac{T_{\rm host,execute}-b}{a}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user