分析一下这段程序,其中data_input大小是256 // 计算移动平均 float current_filtered = 0; for (int i = 0; i < FILTER_SIZE; i++) { current_filtered += filter_buffer[i]; } current_filtered /= FILTER_SIZE; current_filtered *= 1000; /* 将采集到的数据传入data_input中 */ data_input[data_index] = current_filtered; status = tss_ad_predict(data_input, &probability); if(probability >= 0.9) { PRINTF("motor healthy!\r\n"); PRINTF("probability value is %f\r\n",probability); }else{ PRINTF("motor clog !\r\n"); PRINTF("probability value is %f\r\n",probability); } // PRINTF("%f\r\n", current_filtered ); // PRINTF("adc raw is:%d\r\n",adc_raw); // PRINTF("adc voltage is:%fV\r\n",voltage); PRINTF("current is:%f ma \r\n",current);

时间: 2025-06-10 17:04:19 浏览: 18
<think>嗯,用户给了一段程序代码,需要我帮忙分析。让我仔细看看这段代码是做什么的。首先,代码里有一个计算移动平均的部分,然后是将处理后的数据存入data_input数组,接着调用tss_ad_predict函数进行预测,根据返回的概率值判断电机状态。 好的,先看移动平均的计算部分。定义了一个current_filtered变量,初始化为0。然后循环FILTER_SIZE次,累加filter_buffer数组中的值,然后除以FILTER_SIZE得到平均值,再乘以1000。这可能是在做滤波处理,比如去除噪声,得到更平滑的电流信号。因为电流通常以毫安为单位,乘以1000可能将单位从安转换为毫安。 接下来,把current_filtered存入data_input数组的data_index位置。这里data_input的大小是256,可能是一个滑动窗口,用于存储最近256个滤波后的数据点。然后调用tss_ad_predict函数,传入data_input和probability的地址。这个函数可能是某种机器学习模型或者统计方法,用于分析输入数据,输出一个概率值,表示电机健康的概率。 判断probability是否大于等于0.9,如果是,打印电机健康,否则提示堵塞。这里可能0.9是设定的阈值,超过则认为正常,否则需要预警。后面的PRINTF语句打印电流值,但注释掉了其他调试信息,比如adc_raw和voltage,可能只在调试时开启。 需要确认的几个点:FILTER_SIZE的值是多少?这会直接影响滤波效果。如果FILTER_SIZE较大,平滑效果更好但响应延迟;较小则反之。另外,data_index如何更新?是否在每次循环后递增并取模256,确保数据正确覆盖旧数据。tss_ad_predict函数的具体实现是什么?可能涉及时间序列分析或异常检测算法,比如自编码器、统计阈值等。 潜在的问题:如果FILTER_SIZE与filter_buffer的大小不匹配,可能导致数组越界。data_input是否被正确填充,比如是否每次更新一个元素,并维持256个最新数据点。概率阈值的设定是否合理,是否需要根据实际情况调整。此外,电流值的单位转换是否正确,比如是否真的需要乘以1000,或者传感器输出的单位是否已经是毫安。 可能的优化点:使用环形缓冲区来管理filter_buffer和data_input,避免数组越界。考虑实时性,如果FILTER_SIZE太大,可能会影响系统响应速度。另外,异常检测算法的选择是否适合当前应用场景,是否需要定期更新模型或调整参数。 总结来说,这段程序的主要功能是对电流信号进行滤波,收集一段时间的数据,通过模型判断电机状态,并根据概率输出健康或堵塞的提示。需要确保各个参数设置合理,数据管理正确,以及模型的有效性。</think>这段程序主要实现了电机电流信号的滤波处理和健康状态监测功能,以下是详细分析: $\boxed{\text{代码结构分析}}$ 1. **移动平均滤波**: - 使用$FILTER\_SIZE$点滑动窗口对原始信号滤波 - 计算公式:$$current\_filtered = \frac{1}{FILTER\_SIZE}\sum_{i=0}^{FILTER\_SIZE-1}filter\_buffer[i] \times 1000$$ - 作用:消除高频噪声,输出平滑的毫安级电流信号 2. **数据缓存机制**: - `data_input[256]`构成环形缓冲区 - `data_index`指针循环递增,实现先进先出的数据更新策略 3. **健康状态预测**: ```c tss_ad_predict(data_input, &probability); ``` - 输入:最近256个滤波后的电流样本 - 输出:电机健康概率值$probability \in [0,1]$ - 决策阈值:$P \geq 0.9$判定为健康,否则报堵塞 $\boxed{\text{关键参数说明}}$ | 参数 | 单位 | 说明 | |--------------------|--------|-------------------------------| | FILTER_SIZE | 点 | 滤波窗口宽度,影响平滑效果 | | 1000 | 倍 | 单位转换系数(A→mA) | | 0.9 | 无 | 故障判定阈值 | $\boxed{\text{潜在问题与改进建议}}$ 1. **滤波器设计**: - 当前使用简单移动平均(SMA),可考虑改用指数加权平均(EMA)或数字滤波器(如IIR) - 缺少滤波缓冲区初始化逻辑,可能导致启动瞬态误差 2. **异常检测**: ```c if(probability >= 0.9) // 固定阈值可能不适应所有工况 ``` - 建议增加动态阈值调整机制 - 可添加故障计数器和去抖动逻辑,避免瞬时误报 3. **数据管理**: - `data_index`需进行模256运算,防止数组越界 - 建议使用`volatile`修饰共享变量,确保数据完整性 $\boxed{\text{系统运行流程}}$ ``` 电流采样 → 滤波处理 → 数据缓存 → 状态预测 → 阈值判断 → 输出报警 ``` 该程序实现了从原始信号采集到状态判断的完整处理链路,适用于电机健康监测等工业物联网场景。实际部署时建议补充信号标定和模型验证环节。
阅读全文

相关推荐

#include "control.h" #include "Lidar.h" float Move_X = 0, Move_Z = 0; // Ä¿±êËٶȺÍÄ¿±êתÏòËÙ¶È float PWM_Left, PWM_Right; // ×óÓÒµç»úPWMÖµ float RC_Velocity, RC_Turn_Velocity; // Ò£¿Ø¿ØÖƵÄËÙ¶È u8 Mode = Normal_Mode; // ģʽѡÔñ£¬Ä¬ÈÏÊÇÆÕͨµÄ¿ØÖÆÄ£Ê½ Motor_parameter MotorA, MotorB; // ×óÓÒµç»úÏà¹Ø±äÁ¿ int Servo_PWM = SERVO_INIT; // °¢¿ËÂü¶æ»úÏà¹Ø±äÁ¿ u8 Lidar_Detect = Lidar_Detect_ON; // µç´ÅѲÏßģʽÀ×´ï¼ì²âÕϰ­ÎĬÈÏ¿ªÆô float CCD_Move_X = 0.3; // CCDѲÏßËÙ¶È float ELE_Move_X = 0.3; // µç´ÅѲÏßËÙ¶È u8 Ros_count = 0, Lidar_flag_count = 0; u8 cnt = 0; Encoder OriginalEncoder; // Encoder raw data //±àÂëÆ÷ԭʼÊý¾Ý short Accel_Y, Accel_Z, Accel_X, Accel_Angle_x, Accel_Angle_y, Gyro_X, Gyro_Z, Gyro_Y; int forward_cnt = 800; int left_cnt = 120; int right_cnt = 125; int stop_cnt = 200; int stop_flag = 0; int mode_cnt = 0; int state_cnt = 0; int stop_protect = 0; /************************************************************************** Function: Control Function Input : none Output : none º¯Êý¹¦ÄÜ£º5ms¶¨Ê±ÖжϿØÖƺ¯Êý Èë¿Ú²ÎÊý: ÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void forward(){ MotorA.Motor_Pwm = 1999; MotorB.Motor_Pwm = 2040; } void left(){ MotorA.Motor_Pwm = 0; MotorB.Motor_Pwm = 2050; } void right(){ MotorA.Motor_Pwm = 1999; MotorB.Motor_Pwm = 0; } void stop(){ MotorA.Motor_Pwm = 0; MotorB.Motor_Pwm = 0; } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim == &htim5) { Get_KeyVal(); if(mode_cnt == 0) stop(); //ģʽһ if(mode_cnt == 1){ if(forward_cnt > 0){ forward(); forward_cnt--; // if(left_cnt > 0){ // left(); // left_cnt--; // if(right_cnt > 0){ // right(); // right_cnt--; } else{ stop(); } } //ģʽ¶þ else if(mode_cnt == 2){ if(forward_cnt > 0){ forward(); forward_cnt--; } else if(stop_cnt > 0 && forward_cnt == 0){ stop(); stop_cnt--; } else if(stop_cnt == 0 && stop_flag == 0){ forward_cnt = 800; stop_flag = 1; } else{ stop(); } } //ģʽÈý else if(mode_cnt == 3){ if(forward_cnt > 0 && state_cnt == 0){//µÚ1״̬£ºÖ±ÐÐ forward(); forward_cnt--; } else if(right_cnt > 0 && state_cnt == 1){//µÚ2״̬£ºÓÒת right(); right_cnt--; } else if(forward_cnt > 0 && state_cnt == 2){//µÚ3״̬£ºÖ±ÐÐ forward(); forward_cnt--; } else if(left_cnt > 0 && state_cnt == 3){//µÚ4״̬£º×óת left(); left_cnt--; } else if(forward_cnt > 0 && state_cnt == 4){//µÚ5״̬£ºÖ±ÐÐ forward(); forward_cnt--; } else if(left_cnt > 0 && state_cnt == 5){//µÚ6״̬£º×óת left(); left_cnt--; } else if(forward_cnt > 0 && state_cnt == 6){//µÚ7״̬£ºÖ±ÐÐ forward(); forward_cnt--; } else{ if(stop_protect == 0 && stop_cnt == 0){ stop_cnt = 100; stop_protect = 1; } else if(stop_cnt > 0){ stop(); stop_cnt--; } else if(stop_protect == 1 && stop_cnt == 0){ stop_protect = 0; if(state_cnt == 0){//״̬1Çл»×´Ì¬2 state_cnt++; right_cnt = 125; } else if(state_cnt == 1){//״̬2Çл»×´Ì¬3 state_cnt++; forward_cnt = 585; } else if(state_cnt == 2){//״̬3Çл»×´Ì¬4 state_cnt++; left_cnt = 120; } else if(state_cnt == 3){//״̬4Çл»×´Ì¬5 state_cnt++; forward_cnt = 585; } else if(state_cnt == 4){//״̬5Çл»×´Ì¬6 state_cnt++; left_cnt = 120; } else if(state_cnt == 5){//״̬6Çл»×´Ì¬7 state_cnt++; forward_cnt = 585; } } } } Set_Pwm(-MotorA.Motor_Pwm, MotorB.Motor_Pwm); // Çý¶¯µç»ú } } /************************************************************************** Function: Bluetooth_Control Input : none Output : none º¯Êý¹¦ÄÜ£ºÊÖ»úÀ¶ÑÀ¿ØÖÆ Èë¿Ú²ÎÊý: ÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void Bluetooth_Control(void) { if (Flag_Direction == 0) Move_X = 0, Move_Z = 0; // Í£Ö¹ else if (Flag_Direction == 1) Move_X = RC_Velocity, Move_Z = 0; // ǰ½ø else if (Flag_Direction == 2) Move_X = RC_Velocity, Move_Z = Pi / 2; // ÓÒǰ else if (Flag_Direction == 3) Move_X = 0, Move_Z = Pi / 2; // ÏòÓÒ else if (Flag_Direction == 4) Move_X = -RC_Velocity, Move_Z = Pi / 2; // ÓÒºó else if (Flag_Direction == 5) Move_X = -RC_Velocity, Move_Z = 0; // ºóÍË else if (Flag_Direction == 6) Move_X = -RC_Velocity, Move_Z = -Pi / 2; // ×óºó else if (Flag_Direction == 7) Move_X = 0, Move_Z = -Pi / 2; // Ïò×ó else if (Flag_Direction == 8) Move_X = RC_Velocity, Move_Z = -Pi / 2; // ×óǰ else Move_X = 0, Move_Z = 0; if (Car_Num == Akm_Car) { // Ackermann structure car is converted to the front wheel steering Angle system target value, and kinematics analysis is pearformed // °¢¿ËÂü½á¹¹Ð¡³µ×ª»»ÎªÇ°ÂÖתÏò½Ç¶È Move_Z = Move_Z * 2 / 10; } Move_X = Move_X / 1000; Move_Z = -Move_Z; // ת»»ÎªËÙ¶ÈתΪm/s } /************************************************************************** Function: PS2_Control Input : none Output : none º¯Êý¹¦ÄÜ£ºPS2ÊÖ±ú¿ØÖÆ Èë¿Ú²ÎÊý: ÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void PS2_Control(void) { int LY, RX; // ÊÖ±úADCµÄÖµ int Threshold = 20; // ãÐÖµ£¬ºöÂÔÒ¡¸ËС·ù¶È¶¯×÷ static u8 Key1_Count = 0, Key2_Count = 0; // ÓÃÓÚ¿ØÖƶÁȡҡ¸ËµÄËÙ¶È // ת»¯Îª128µ½-128µÄÊýÖµ LY = -(PS2_LY - 128); // ×ó±ßYÖá¿ØÖÆÇ°½øºóÍË RX = -(PS2_RX - 128); // ÓÒ±ßXÖá¿ØÖÆ×ªÏò if (LY > -Threshold && LY < Threshold) LY = 0; if (RX > -Threshold && RX < Threshold) RX = 0; // ºöÂÔÒ¡¸ËС·ù¶È¶¯×÷ Move_X = (RC_Velocity / 128) * LY; // ËÙ¶È¿ØÖÆ£¬Á¦¶È±íʾËÙ¶È´óС if (Car_Num == Akm_Car) // °¢¿ËÂü³µ×ªÏò¿ØÖÆ£¬Á¦¶È±íʾתÏò½Ç¶È Move_Z = -(RC_Turn_Velocity / 128) * RX; else // ÆäËû³µÐÍתÏò¿ØÖÆ { if (Move_X >= 0) Move_Z = -(RC_Turn_Velocity / 128) * RX; // תÏò¿ØÖÆ£¬Á¦¶È±íʾתÏòËÙ¶È else Move_Z = (RC_Turn_Velocity / 128) * RX; } if (PS2_KEY == PSB_L1) // °´ÏÂ×ó1¼ü¼ÓËÙ£¨°´¼üÔÚ¶¥ÉÏ£© { if ((++Key1_Count) == 20) // µ÷½Ú°´¼ü·´Ó¦ËÙ¶È { PS2_KEY = 0; Key1_Count = 0; if ((RC_Velocity += X_Step) > MAX_RC_Velocity) // ǰ½ø×î´óËÙ¶È800mm/s RC_Velocity = MAX_RC_Velocity; if (Car_Num != Akm_Car) // ·Ç°¢¿ËÂü³µ¿Éµ÷½ÚתÏòËÙ¶È { if ((RC_Turn_Velocity += Z_Step) > MAX_RC_Turn_Bias) // תÏò×î´óËÙ¶È325 RC_Turn_Velocity = MAX_RC_Turn_Bias; } } } else if (PS2_KEY == PSB_R1) // °´ÏÂÓÒ1¼ü¼õËÙ { if ((++Key2_Count) == 20) { PS2_KEY = 0; Key2_Count = 0; if ((RC_Velocity -= X_Step) < MINI_RC_Velocity) // ǰºó×îСËÙ¶È210mm/s RC_Velocity = MINI_RC_Velocity; if (Car_Num != Akm_Car) // ·Ç°¢¿ËÂü³µ¿Éµ÷½ÚתÏòËÙ¶È { if ((RC_Turn_Velocity -= Z_Step) < MINI_RC_Turn_Velocity) // תÏò×îСËÙ¶È45 RC_Turn_Velocity = MINI_RC_Turn_Velocity; } } } else Key2_Count = 0, Key2_Count = 0; // ¶ÁÈ¡µ½ÆäËû°´¼üÖØÐ¼ÆÊý Move_X = Move_X / 1000; Move_Z = -Move_Z; // ËÙ¶ÈMove_XתΪm/s } /************************************************************************** Function: Get_Velocity_From_Encoder Input : none Output : none º¯Êý¹¦ÄÜ£º¶ÁÈ¡±àÂëÆ÷ºÍת»»³ÉËÙ¶È Èë¿Ú²ÎÊý: ÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void Get_Velocity_From_Encoder(void) { // Retrieves the original data of the encoder // »ñÈ¡±àÂëÆ÷µÄԭʼÊý¾Ý float Encoder_A_pr, Encoder_B_pr; OriginalEncoder.A = Read_Encoder(Encoder1); OriginalEncoder.B = Read_Encoder(Encoder2); // Decide the encoder numerical polarity according to different car models // ¸ù¾Ý²»Í¬Ð¡³µÐͺžö¶¨±àÂëÆ÷ÊýÖµ¼«ÐÔ switch (Car_Num) { case Akm_Car: Encoder_A_pr = OriginalEncoder.A; Encoder_B_pr = -OriginalEncoder.B; break; case Diff_Car: Encoder_A_pr = OriginalEncoder.A; Encoder_B_pr = -OriginalEncoder.B; break; case Small_Tank_Car: Encoder_A_pr = OriginalEncoder.A; Encoder_B_pr = -OriginalEncoder.B; break; case Big_Tank_Car: Encoder_A_pr = OriginalEncoder.A; Encoder_B_pr = -OriginalEncoder.B; break; } // The encoder converts the raw data to wheel speed in m/s // ±àÂëÆ÷ԭʼÊý¾Ýת»»Îª³µÂÖËÙ¶È£¬µ¥Î»m/s MotorA.Current_Encoder = Encoder_A_pr * Frequency * Perimeter / 60000.0f; // 60000 = 4*500*30 MotorB.Current_Encoder = Encoder_B_pr * Frequency * Perimeter / 60000.0f; // 1560=4*13*30=2£¨Á½Â·Âö³å£©*2£¨ÉÏÏÂÑØ¼ÆÊý£©*»ô¶û±àÂëÆ÷13Ïß*µç»úµÄ¼õËÙ±È // MotorA.Current_Encoder= Encoder_A_pr*CONTROL_FREQUENCY*Akm_wheelspacing//(4*13*30); // MotorB.Current_Encoder= Encoder_B_pr*CONTROL_FREQUENCY*Akm_wheelspacing/Encoder_precision; } /************************************************************************** Function: Drive_Motor Input : none Output : none º¯Êý¹¦ÄÜ£ºÔ˶¯Ñ§Äæ½â Èë¿Ú²ÎÊý: ÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ // Ô˶¯Ñ§Äæ½â£¬ÓÉxºÍyµÄËٶȵõ½±àÂëÆ÷µÄËÙ¶È,VxÊÇm/s,Vzµ¥Î»ÊǶÈ/s(½Ç¶ÈÖÆ) // °¢¿ËÂü³µVzÊǶæ»úתÏòµÄ½Ç¶È(»¡¶ÈÖÆ) void Get_Target_Encoder(float Vx, float Vz) { float MotorA_Velocity, MotorB_Velocity; float amplitude = 3.5f; // Wheel target speed limit //³µÂÖÄ¿±êËÙ¶ÈÏÞ·ù Move_X = target_limit_float(Move_X, -1.2, 1.2); Move_Z = target_limit_float(Move_Z, -Pi / 3, Pi / 3); if (Car_Num == Akm_Car) // °¢¿ËÂü³µ { // Ackerman car specific related variables //°¢¿ËÂüС³µ×¨ÓÃÏà¹Ø±äÁ¿ float R, ratio = 636.56, AngleR, Angle_Servo; // For Ackerman small car, Vz represents the front wheel steering Angle // ¶ÔÓÚ°¢¿ËÂüС³µVz´ú±íÓÒǰÂÖתÏò½Ç¶È AngleR = Vz; R = Akm_axlespacing / tan(AngleR) - 0.5f * Wheelspacing; // Front wheel steering Angle limit (front wheel steering Angle controlled by steering engine), unit: rad // ǰÂÖתÏò½Ç¶ÈÏÞ·ù(¶æ»ú¿ØÖÆÇ°ÂÖתÏò½Ç¶È)£¬µ¥Î»£ºrad AngleR = target_limit_float(AngleR, -0.49f, 0.32f); // Inverse kinematics //Ô˶¯Ñ§Äæ½â if (AngleR != 0) { MotorA.Target_Encoder = Vx * (R - 0.081f) / R; MotorB.Target_Encoder = Vx * (R + 0.081f) / R; } else { MotorA.Target_Encoder = Vx; MotorB.Target_Encoder = Vx; } // The PWM value of the servo controls the steering Angle of the front wheel // ¶æ»úPWMÖµ£¬¶æ»ú¿ØÖÆÇ°ÂÖתÏò½Ç¶È Angle_Servo = -0.628f * pow(AngleR, 3) + 1.269f * pow(AngleR, 2) - 1.772f * AngleR + 1.573f; Servo_PWM = SERVO_INIT + (Angle_Servo - 1.572f) * ratio; // printf("%d\r\n",Servo_PWM); // Wheel (motor) target speed limit //³µÂÖ(µç»ú)Ä¿±êËÙ¶ÈÏÞ·ù MotorA.Target_Encoder = target_limit_float(MotorA.Target_Encoder, -amplitude, amplitude); MotorB.Target_Encoder = target_limit_float(MotorB.Target_Encoder, -amplitude, amplitude); Servo_PWM = target_limit_int(Servo_PWM, 800, 2200); // Servo PWM value limit //¶æ»úPWMÖµÏÞ·ù } else if (Car_Num == Diff_Car) // ²îËÙС³µ { if (Vx < 0) Vz = -Vz; else Vz = Vz; // Inverse kinematics //Ô˶¯Ñ§Äæ½â MotorA.Target_Encoder = Vx - Vz * Wheelspacing / 2.0f; // ¼ÆËã³ö×óÂÖµÄÄ¿±êËÙ¶È MotorB.Target_Encoder = Vx + Vz * Wheelspacing / 2.0f; // ¼ÆËã³öÓÒÂÖµÄÄ¿±êËÙ¶È // Wheel (motor) target speed limit //³µÂÖ(µç»ú)Ä¿±êËÙ¶ÈÏÞ·ù MotorA.Target_Encoder = target_limit_float(MotorA.Target_Encoder, -amplitude, amplitude); MotorB.Target_Encoder = target_limit_float(MotorB.Target_Encoder, -amplitude, amplitude); } else if (Car_Num == Small_Tank_Car) { if (Vx < 0) Vz = -Vz; else Vz = Vz; MotorA.Target_Encoder = Vx - Vz * Wheelspacing / 2.0f; // ¼ÆËã³ö×óÂÖµÄÄ¿±êËÙ¶È MotorB.Target_Encoder = Vx + Vz * Wheelspacing / 2.0f; // ¼ÆËã³öÓÒÂÖµÄÄ¿±êËÙ¶È // Wheel (motor) target speed limit //³µÂÖ(µç»ú)Ä¿±êËÙ¶ÈÏÞ·ù MotorA.Target_Encoder = target_limit_float(MotorA.Target_Encoder, -amplitude, amplitude); MotorB.Target_Encoder = target_limit_float(MotorB.Target_Encoder, -amplitude, amplitude); } else if (Car_Num == Big_Tank_Car) { if (Vx < 0) Vz = -Vz; else Vz = Vz; MotorA.Target_Encoder = Vx - Vz * Wheelspacing / 2.0f; // ¼ÆËã³ö×óÂÖµÄÄ¿±êËÙ¶È MotorB.Target_Encoder = Vx + Vz * Wheelspacing / 2.0f; // ¼ÆËã³öÓÒÂÖµÄÄ¿±êËÙ¶È MotorA.Target_Encoder = target_limit_float(MotorA.Target_Encoder, -amplitude, amplitude); MotorB.Target_Encoder = target_limit_float(MotorB.Target_Encoder, -amplitude, amplitude); } } /************************************************************************** Function: Get_Motor_PWM Input : none Output : none º¯Êý¹¦ÄÜ£º×ª»»³ÉÇý¶¯µç»úµÄPWM Èë¿Ú²ÎÊý: ÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void Get_Motor_PWM(void) { // ¼ÆËã×óÓÒµç»ú¶ÔÓ¦µÄPWM MotorA.Motor_Pwm = Incremental_PI_Left(MotorA.Current_Encoder, MotorA.Target_Encoder); MotorB.Motor_Pwm = Incremental_PI_Right(MotorB.Current_Encoder, MotorB.Target_Encoder); if (Mode == Normal_Mode || Mode == Measure_Distance_Mode) { // Â˲¨£¬Ê¹Æð²½ºÍÍ£Ö¹ÉÔ΢ƽ»¬Ò»Ð© MotorA.Motor_Pwm = Mean_Filter_Left(MotorA.Motor_Pwm); MotorB.Motor_Pwm = Mean_Filter_Right(MotorB.Motor_Pwm); } // ÏÞ·ù MotorA.Motor_Pwm = PWM_Limit(MotorA.Motor_Pwm, PWM_MAX, PWM_MIN); MotorB.Motor_Pwm = PWM_Limit(MotorB.Motor_Pwm, PWM_MAX, PWM_MIN); } /************************************************************************** Function: PWM_Limit Input : IN;max;min Output : OUT º¯Êý¹¦ÄÜ£ºÏÞÖÆPWM¸³Öµ Èë¿Ú²ÎÊý: IN£ºÊäÈë²ÎÊý max£ºÏÞ·ù×î´óÖµ min£ºÏÞ·ù×îСֵ ·µ»Ø Öµ£ºÏÞ·ùºóµÄÖµ **************************************************************************/ float PWM_Limit(float IN, int max, int min) { float OUT = IN; if (OUT > max) OUT = max; if (OUT < min) OUT = min; return OUT; } /************************************************************************** Function: Limiting function Input : Value Output : none º¯Êý¹¦ÄÜ£ºÏÞ·ùº¯Êý Èë¿Ú²ÎÊý£º·ùÖµ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ float target_limit_float(float insert, float low, float high) { if (insert < low) return low; else if (insert > high) return high; else return insert; } int target_limit_int(int insert, int low, int high) { if (insert < low) return low; else if (insert > high) return high; else return insert; } /************************************************************************** Function: Check whether it is abnormal Input : none Output : 1:Abnormal;0:Normal º¯Êý¹¦ÄÜ£ºÒì³£¹Ø±Õµç»ú Èë¿Ú²ÎÊý: ÎÞ ·µ»Ø Öµ£º1£ºÒì³£ 0£ºÕý³£ **************************************************************************/ u8 Turn_Off(void) { u8 temp = Normal; Flag_Stop = KEY2_STATE; // ¶ÁÈ¡°´¼ü2״̬£¬°´¼ü2¿ØÖƵç»úµÄ¿ª¹Ø if (Voltage < 1000) // µç³ØµçѹµÍÓÚ10V¹Ø±Õµç»ú,LEDµÆ¿ìËÙÉÁ˸ LED_Flash(50), temp = Abnormal; else LED_Flash(200); // ÿһÃëÉÁÒ»´Î£¬Õý³£ÔËÐÐ if (Flag_Stop) temp = Abnormal; return temp; } /************************************************************************** Function: Data sliding filtering Input : data Output : Filtered data º¯Êý¹¦ÄÜ£ºÊý¾Ý»¬¶¯Â˲¨ Èë¿Ú²ÎÊý£ºÊý¾Ý ·µ»Ø Öµ£ºÂ˲¨ºóµÄÊý¾Ý **************************************************************************/ float Mean_Filter_Left(float data) { u8 i; float Sum_Data = 0; float Filter_Data; static float Speed_Buf[FILTERING_TIMES] = {0}; for (i = 1; i < FILTERING_TIMES; i++) { Speed_Buf[i - 1] = Speed_Buf[i]; } Speed_Buf[FILTERING_TIMES - 1] = data; for (i = 0; i < FILTERING_TIMES; i++) { Sum_Data += Speed_Buf[i]; } Filter_Data = (s32)(Sum_Data / FILTERING_TIMES); return Filter_Data; } /************************************************************************** Function: Data sliding filtering Input : data Output : Filtered data º¯Êý¹¦ÄÜ£ºÊý¾Ý»¬¶¯Â˲¨ Èë¿Ú²ÎÊý£ºÊý¾Ý ·µ»Ø Öµ£ºÂ˲¨ºóµÄÊý¾Ý **************************************************************************/ float Mean_Filter_Right(float data) { u8 i; float Sum_Data = 0; float Filter_Data; static float Speed_Buf[FILTERING_TIMES] = {0}; for (i = 1; i < FILTERING_TIMES; i++) { Speed_Buf[i - 1] = Speed_Buf[i]; } Speed_Buf[FILTERING_TIMES - 1] = data; for (i = 0; i < FILTERING_TIMES; i++) { Sum_Data += Speed_Buf[i]; } Filter_Data = (s32)(Sum_Data / FILTERING_TIMES); return Filter_Data; } /************************************************************************** Function: Lidar_Avoid Input : none Output : none º¯Êý¹¦ÄÜ£ºÀ×´ï±ÜÕÏģʽ Èë¿Ú²ÎÊý£ºÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void Lidar_Avoid(void) { int i = 0; u8 calculation_angle_cnt = 0; // ÓÃÓÚÅжÏ100¸öµãÖÐÐèÒª×ö±ÜÕϵĵã float angle_sum = 0; // ´ÖÂÔ¼ÆËãÕϰ­ÎïλÓÚ×ó»òÕßÓÒ u8 distance_count = 0; // ¾àÀëСÓÚijֵµÄ¼ÆÊý int distance = 350; // É趨±ÜÕϾàÀë,ĬÈÏÊÇ300 if (Car_Num == Akm_Car) distance = 400; // °¢¿ËÂü³µÉ趨ÊÇ400mm else if (Car_Num == Big_Tank_Car) distance = 500; // ´óÂÄ´ø³µÉ趨ÊÇ500mm for (i = 0; i < lap_count; i++) { if ((Dataprocess[i].angle > 310) || (Dataprocess[i].angle < 50)) { if ((0 < Dataprocess[i].distance) && (Dataprocess[i].distance < distance)) // ¾àÀëСÓÚ350mmÐèÒª±ÜÕÏ,Ö»ÐèÒª100¶È·¶Î§ÄÚµã { calculation_angle_cnt++; // ¼ÆËã¾àÀëСÓÚ±ÜÕϾàÀëµÄµã¸öÊý if (Dataprocess[i].angle < 50) angle_sum += Dataprocess[i].angle; else if (Dataprocess[i].angle > 310) angle_sum += (Dataprocess[i].angle - 360); // 310¶Èµ½50¶Èת»¯Îª-50¶Èµ½50¶È if (Dataprocess[i].distance < 200) // ¼Ç¼СÓÚ200mmµÄµãµÄ¼ÆÊý distance_count++; } } } if (calculation_angle_cnt < 8) // СÓÚ8µã²»ÐèÒª±ÜÕÏ£¬È¥³ýһЩÔëµã { if ((Move_X += 0.1) >= Aovid_Speed) // ±ÜÕϵÄËÙ¶ÈÉ趨Ϊ260£¬Öð½¥Ôö¼Óµ½260¿ÉÉÔ΢ƽ»¬Ò»Ð© Move_X = Aovid_Speed; Move_Z = 0; // ²»±ÜÕÏʱ²»ÐèҪתÍä } else // ÐèÒª±ÜÕÏ£¬¼òµ¥µØÅжÏÕϰ­Î﷽λ { if (Car_Num == Akm_Car) // °¢¿ËÂü³µÐÍÓжæ»ú£¬ÐèÒªÌØÊâ´¦Àí { if (distance_count > 8) // ¾àÀëСÓÚ±ÜÕ½¾àÀë Move_X = -Aovid_Speed, Move_Z = 0; // ÍùºóÍË else { if ((Move_X -= 0.1) <= (Aovid_Speed * 0.5)) // ±ÜÕÏʱËٶȽµµ½µÍËÙ0.25 Move_X = Aovid_Speed * 0.5; if (angle_sum > 0) // Õϰ­ÎïÆ«ÓÒ Move_Z = -Pi / 5; // ÿ´ÎתÍä½Ç¶ÈΪPI/5£¬Ö±µ½100¶È·¶Î§ÄÚÎÞÕϰ­Îï¾ÍÍ£Ö¹ else // Æ«×ó Move_Z = Pi / 5; } } else { if (distance_count > 8) // СÓÚ±ÜÕ½¾àÀëµÄʱºò Move_X = -Aovid_Speed, Move_Z = 0; // ÍùºóÍË else { if ((Move_X -= 0.1) <= (Aovid_Speed * 0.5)) // ±ÜÕÏʱËٶȽµµ½µÍËÙ¶È0.15 Move_X = (Aovid_Speed * 0.5); if (angle_sum > 0) // Õϰ­ÎïÆ«ÓÒ { if (Car_Num == Diff_Car) // ÿ´ÎתÍäËÙ¶ÈΪX¶È£¬Ö±µ½100¶È·¶Î§ÄÚÎÞÕϰ­Îï¾ÍÍ£Ö¹ Move_Z = -1; else if (Car_Num == Small_Tank_Car) Move_Z = -1; else Move_Z = -1; } else // Æ«×ó { if (Car_Num == Diff_Car) // ÿ´ÎתÍäËÙ¶ÈΪX¶È£¬Ö±µ½100¶È·¶Î§ÄÚÎÞÕϰ­Îï¾ÍÍ£Ö¹ Move_Z = 1; else if (Car_Num == Small_Tank_Car) Move_Z = 1; else Move_Z = 1; } } } } Move_Z = -Move_Z; } /************************************************************************** Function: Lidar_Follow Input : none Output : none º¯Êý¹¦ÄÜ£ºÀ×´ï¸úËæÄ£Ê½ Èë¿Ú²ÎÊý£ºÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ float angle1 = 0; // ¸úËæµÄ½Ç¶È u16 mini_distance1; void Lidar_Follow(void) { static u16 cnt = 0; int i; int calculation_angle_cnt = 0; static float angle = 0; // ¸úËæµÄ½Ç¶È static float last_angle = 0; // u16 mini_distance = 65535; static u8 data_count = 0; // ÓÃÓÚÂ˳ýһдÔëµãµÄ¼ÆÊý±äÁ¿ // ÐèÒªÕÒ³ö¸úËæµÄÄǸöµãµÄ½Ç¶È for (i = 0; i < lap_count; i++) { if (100 < Dataprocess[i].distance && Dataprocess[i].distance < Follow_Distance) // 1200·¶Î§ÄÚ¾ÍÐèÒª¸úËæ { calculation_angle_cnt++; if (Dataprocess[i].distance < mini_distance) // ÕÒ³ö¾àÀë×îСµÄµã { mini_distance = Dataprocess[i].distance; angle = Dataprocess[i].angle; } } } if (angle > 180) angle -= 360; // 0--360¶Èת»»³É0--180£»-180--0£¨Ë³Ê±Õ룩 if (angle - last_angle > 10 || angle - last_angle < -10) // ×öÒ»¶¨Ïû¶¶£¬²¨¶¯´óÓÚ10¶ÈµÄÐèÒª×öÅÐ¶Ï { if (++data_count == 60) // Á¬Ðø60´Î²É¼¯µ½µÄÖµ(300msºó)ºÍÉϴεıȴóÓÚ10¶È£¬´Ëʱ²ÅÊÇÈÏΪÊÇÓÐЧֵ { data_count = 0; last_angle = angle; } } else // ²¨¶¯Ð¡ÓÚ10¶ÈµÄ¿ÉÒÔÖ±½ÓÈÏΪÊÇÓÐЧֵ { data_count = 0; last_angle = angle; } if (calculation_angle_cnt < 6) // ÔÚ¸úËæ·¶Î§ÄڵĵãÉÙÓÚ6¸ö { if (cnt < 40) // Á¬Ðø¼ÆÊý³¬40´ÎûÓÐÒª¸úËæµÄµã£¬´Ëʱ²ÅÊDz»ÓøúËæ cnt++; if (cnt >= 40) { Move_X = 0; // ËÙ¶ÈΪ0 Move_Z = 0; } } else { cnt = 0; if (Car_Num == Akm_Car) { if ((((angle > 15) && (angle < 180)) || ((angle > -180) && angle < -15)) && (mini_distance < 500)) // °¢¿¨Âü³µÐÍ´¦Àí³µÍ·²»¶ÔןúËæÎÏ൱ÓÚºó³µÒ»Ñù£¬Ò»´Î²»¶Ô×¼£¬ÄǺóÍËÔÙÀ´¶Ô×¼ { Move_X = -0.20; Move_Z = -Follow_Turn_PID(last_angle, 0); } else { Move_X = Distance_Adjust_PID(mini_distance, Keep_Follow_Distance); // ±£³Ö¾àÀë±£³ÖÔÚ400mm Move_Z = Follow_Turn_PID(last_angle, 0); } } else // ÆäÓà³µÐÍ { if ((angle > 50 || angle < -50) && (mini_distance > 400)) { Move_Z = -0.0298f * last_angle; // ½Ç¶È²î¾à¹ý´óÖ±½Ó¿ìËÙתÏò Move_X = 0; // ²îËÙС³µºÍÂÄ´øÐ¡³µ¿ÉÒÔʵÏÖÔ­µØ×ª¶¯ } else { Move_X = Distance_Adjust_PID(mini_distance, Keep_Follow_Distance); // ±£³Ö¾àÀë±£³ÖÔÚ400mm Move_Z = Follow_Turn_PID(last_angle, 0); // תÏòPID£¬³µÍ·ÓÀÔ¶¶ÔןúËæÎïÆ· } } } Move_Z = target_limit_float(Move_Z, -Pi / 6, Pi / 6); // ÏÞ·ù Move_X = target_limit_float(Move_X, -0.6, 0.6); } /************************************************************************** º¯Êý¹¦ÄÜ£ºÐ¡³µ×ßÖ±Ïßģʽ Èë¿Ú²ÎÊý£ºÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void Lidar_along_wall(void) { static u32 target_distance = 0; static int n = 0; u32 distance; u8 data_count = 0; // ÓÃÓÚÂ˳ýһдÔëµãµÄ¼ÆÊý±äÁ¿ for (int i = 0; i < lap_count; i++) { if (Dataprocess[i].angle > 75 && Dataprocess[i].angle < 77) { if (n == 0) { target_distance = Dataprocess[i].distance; // »ñÈ¡µÄµÚÒ»¸öµã×÷ΪĿ±ê¾àÀë n++; } if (Dataprocess[i].distance < target_distance + 100) //+100ÏÞÖÆ»ñÈ¡¾àÀëµÄ·¶Î§Öµ { distance = Dataprocess[i].distance; // »ñȡʵʱ¾àÀë data_count++; } } } // if(data_count <= 0) // Move_X = 0; // Move_X = forward_velocity; // ³õʼËÙ¶È Move_Z = -Along_Adjust_PID(distance, target_distance); if (Car_Num == Akm_Car) { Move_Z = target_limit_float(Move_Z, -Pi / 4, Pi / 4); // ÏÞ·ù } else if (Car_Num == Diff_Car) Move_Z = target_limit_float(Move_Z, -Pi / 5, Pi / 5); // ÏÞ·ù } /************************************************************************** Function: Car_Perimeter_Init Input : none Output : none º¯Êý¹¦ÄÜ£º¼ÆËãС³µ¸÷ÂÖ×ÓµÄÖܳ¤ Èë¿Ú²ÎÊý£ºÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void Car_Perimeter_Init(void) { if (Car_Num == Diff_Car || Car_Num == Akm_Car) { Perimeter = Diff_Car_Wheel_diameter * Pi; Wheelspacing = Diff_wheelspacing; } else if (Car_Num == Small_Tank_Car) { Perimeter = Small_Tank_WheelDiameter * Pi; Wheelspacing = Small_Tank_wheelspacing; } else { Perimeter = Big_Tank_WheelDiameter * Pi; Wheelspacing = Big_Tank_wheelspacing; } } /************************************************************************** Function: Ultrasonic_Follow Input : none Output : none º¯Êý¹¦ÄÜ£º³¬Éù²¨¸úËæÄ£Ê½ Èë¿Ú²ÎÊý£ºÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void Ultrasonic_Follow(void) // ³¬Éù²¨¸úËæ£¬Ö»Äܵ¥·½Ïò¸úËæ { Move_Z = 0; Read_Distane(); // ¶ÁÈ¡³¬Éù²¨µÄ¾àÀë if (Distance1 < 200) // ¾àÀëСÓÚ200mm£¬Í˺ó { if ((Move_X -= 3) < -210) Move_X = -210; // ¸øÒ»210ºóÍËËÙ¶È } else if (Distance1 > 270 && Distance1 < 750) // ¾àÀëÔÚ270µ½750Ö®¼äÊÇÐèÒª¸úËæÇ°½ø { if ((Move_X += 3) > 210) // ËÙ¶ÈÖð½¥Ôö¼Ó£¬¸øÇ°½øËÙ¶È Move_X = 210; } else { if (Move_X > 0) { if ((Move_X -= 20) < 0) // ËÙ¶ÈÖð½¥¼õµ½0 Move_X = 0; } else { if ((Move_X += 20) > 0) // ËÙ¶ÈÖð½¥¼õµ½0 Move_X = 0; } } } /************************************************************************** Function: Get angle Input : way£ºThe algorithm of getting angle 1£ºDMP 2£ºkalman 3£ºComplementary filtering Output : none º¯Êý¹¦ÄÜ£º»ñÈ¡½Ç¶È Èë¿Ú²ÎÊý£ºway£º»ñÈ¡½Ç¶ÈµÄËã·¨ 1£ºDMP 2£º¿¨¶ûÂü 3£º»¥²¹Â˲¨ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void Get_Angle(u8 way) { if (way == 1) // DMPµÄ¶ÁÈ¡ÔÚÊý¾Ý²É¼¯Öж϶ÁÈ¡£¬Ñϸñ×ñѭʱÐòÒªÇó { Read_DMP(); // ¶ÁÈ¡¼ÓËÙ¶È¡¢½ÇËÙ¶È¡¢Çã½Ç } else { Gyro_X = (I2C_ReadOneByte(devAddr, MPU6050_RA_GYRO_XOUT_H) << 8) + I2C_ReadOneByte(devAddr, MPU6050_RA_GYRO_XOUT_L); // ¶ÁÈ¡XÖáÍÓÂÝÒÇ Gyro_Y = (I2C_ReadOneByte(devAddr, MPU6050_RA_GYRO_YOUT_H) << 8) + I2C_ReadOneByte(devAddr, MPU6050_RA_GYRO_YOUT_L); // ¶ÁÈ¡YÖáÍÓÂÝÒÇ Gyro_Z = (I2C_ReadOneByte(devAddr, MPU6050_RA_GYRO_ZOUT_H) << 8) + I2C_ReadOneByte(devAddr, MPU6050_RA_GYRO_ZOUT_L); // ¶ÁÈ¡ZÖáÍÓÂÝÒÇ Accel_X = (I2C_ReadOneByte(devAddr, MPU6050_RA_ACCEL_XOUT_H) << 8) + I2C_ReadOneByte(devAddr, MPU6050_RA_ACCEL_XOUT_L); // ¶ÁÈ¡XÖá¼ÓËÙ¶È¼Æ Accel_Y = (I2C_ReadOneByte(devAddr, MPU6050_RA_ACCEL_YOUT_H) << 8) + I2C_ReadOneByte(devAddr, MPU6050_RA_ACCEL_YOUT_L); // ¶ÁÈ¡XÖá¼ÓËÙ¶È¼Æ Accel_Z = (I2C_ReadOneByte(devAddr, MPU6050_RA_ACCEL_ZOUT_H) << 8) + I2C_ReadOneByte(devAddr, MPU6050_RA_ACCEL_ZOUT_L); // ¶ÁÈ¡ZÖá¼ÓËÙ¶È¼Æ // if(Gyro_X>32768) Gyro_X-=65536; //Êý¾ÝÀàÐÍת»» Ò²¿Éͨ¹ýshortÇ¿ÖÆÀàÐÍת»» // if(Gyro_Y>32768) Gyro_Y-=65536; //Êý¾ÝÀàÐÍת»» Ò²¿Éͨ¹ýshortÇ¿ÖÆÀàÐÍת»» // if(Gyro_Z>32768) Gyro_Z-=65536; //Êý¾ÝÀàÐÍת»» // if(Accel_X>32768) Accel_X-=65536; //Êý¾ÝÀàÐÍת»» // if(Accel_Y>32768) Accel_Y-=65536; //Êý¾ÝÀàÐÍת»» // if(Accel_Z>32768) Accel_Z-=65536; //Êý¾ÝÀàÐÍת»» Accel_Angle_x = atan2(Accel_Y, Accel_Z) * 180 / Pi; // ¼ÆËãÇã½Ç£¬×ª»»µ¥Î»Îª¶È Accel_Angle_y = atan2(Accel_X, Accel_Z) * 180 / Pi; // ¼ÆËãÇã½Ç£¬×ª»»µ¥Î»Îª¶È Gyro_X = Gyro_X / 65.5; // ÍÓÂÝÒÇÁ¿³Ìת»»£¬Á¿³Ì¡À500¡ã/s¶ÔÓ¦ÁéÃô¶È65.5£¬¿É²éÊÖ²á Gyro_Y = Gyro_Y / 65.5; // ÍÓÂÝÒÇÁ¿³Ìת»» if (way == 2) { Roll = -Kalman_Filter_x(Accel_Angle_x, Gyro_X); // ¿¨¶ûÂüÂ˲¨ Pitch = -Kalman_Filter_y(Accel_Angle_y, Gyro_Y); } else if (way == 3) { Roll = -Complementary_Filter_x(Accel_Angle_x, Gyro_X); // »¥²¹Â˲¨ Pitch = -Complementary_Filter_y(Accel_Angle_y, Gyro_Y); } } } /************************************************************************** Function: The remote control command of model aircraft is processed Input : none Output : none º¯Êý¹¦ÄÜ£º¶Ôº½Ä£Ò£¿Ø¿ØÖÆÃüÁî½øÐд¦Àí Èë¿Ú²ÎÊý£ºÎÞ ·µ»Ø Öµ£ºÎÞ **************************************************************************/ void Remote_Control(void) { // Data within 1 second after entering the model control mode will not be processed // ¶Ô½øÈ뺽ģ¿ØÖÆÄ£Ê½ºó1ÃëÄÚµÄÊý¾Ý²»´¦Àí static u8 thrice = 200; int Threshold = 100; // limiter //ÏÞ·ù int LX, RY; // static float Target_LX,Target_LY,Target_RY,Target_RX; Remoter_Ch1 = target_limit_int(Remoter_Ch1, 1000, 2000); Remoter_Ch2 = target_limit_int(Remoter_Ch2, 1000, 2000); // Front and back direction of left rocker. Control forward and backward. // ×óÒ¡¸Ëǰºó·½Ïò¡£¿ØÖÆÇ°½øºóÍË¡£ LX = Remoter_Ch2 - 1500; // //Left joystick left and right. Control left and right movement. // //×óÒ¡¸Ë×óÓÒ·½Ïò¡£¿ØÖÆ×óÓÒÒÆ¶¯¡£¡£ // LY=Remoter_Ch2-1500; // Right stick left and right. To control the rotation. // ÓÒÒ¡¸Ë×óÓÒ·½Ïò¡£¿ØÖÆ×Ôת¡£ RY = Remoter_Ch1 - 1500; // if (LX > -Threshold && LX < Threshold) LX = 0; if (RY > -Threshold && RY < Threshold) RY = 0; // if(LX==0) Target_LX=Target_LX/1.2f; // if(LY==0) Target_LY=Target_LY/1.2f; // if(RY==0) Target_RY=Target_RY/1.2f; // //Throttle related //ÓÍÃÅÏà¹Ø // Remote_RCvelocity=RC_Velocity+RX; // if(Remote_RCvelocity<0)Remote_RCvelocity=0; // The remote control command of model aircraft is processed // ¶Ôº½Ä£Ò£¿Ø¿ØÖÆÃüÁî½øÐд¦Àí Move_X = LX; Move_Z = -RY; Move_X = Move_X * 1.3; //*1.3ÊÇΪÁËÀ«´óËÙ¶È if (Car_Num == Akm_Car) Move_Z = Move_Z * (Pi / 8) / 350.0; else Move_Z = Move_Z * 2 * (Pi / 4) / 350.0; // Unit conversion, mm/s -> m/s // µ¥Î»×ª»»£¬mm/s -> m/s Move_X = Move_X / 1000; // ZÖáÊý¾Ýת»¯ #if _4WD if (Move_X < 0) Move_Z = -Move_Z; #endif // Data within 1 second after entering the model control mode will not be processed // ¶Ô½øÈ뺽ģ¿ØÖÆÄ£Ê½ºó1ÃëÄÚµÄÊý¾Ý²»´¦Àí if (thrice > 0) Move_X = 0, Move_Z = 0, thrice--; // Control target value is obtained and kinematics analysis is performed // µÃµ½¿ØÖÆÄ¿±êÖµ£¬½øÐÐÔ˶¯Ñ§·ÖÎö // Get_Target_Encoder(Move_X,Move_Z); } 怎么把OpenMV与STM32串口通信实现二维码/APRILTag码识别及控制的代码加到上述代码中,现在openmv的二维码识别已做好,二维码采用的是Apriltag的36h11类型,id:0表示停止,id:1表示直行,id:2表示左转,id:3表示右转,现在需要再在STM32中修改或添加代码,使其能在接收到openmv识别到的指令后作出相应的动作

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "adc.h" #include "tim.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define TRIG_PULSE_WIDTH 10 // 10us触发脉冲 #define MEASURE_TIMEOUT 30 // 30ms测量超时 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ volatile uint32_t icVal1 = 0, icVal2 = 0; volatile uint8_t isFirstCaptured = 0; volatile float distance_cm = 0; int Turn_Pwm = 0; uint8_t stop_flag = 0; // 停止标志位 uint8_t void_flag = 0; // 停止标志位 float feature_time = 0; // 特征区域经过时间 int baoguang_count=10; float dis = 0; // 存放测距距离 int main_count=5; /* USER CODE BEGIN PV */ typedef enum { US_IDLE, US_TRIGGER_START, US_WAIT_ECHO } US_State_t; volatile US_State_t us_state = US_IDLE; volatile uint32_t us_trigger_time = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ void trigger_ultrasonic_non_blocking() { if (us_state == US_IDLE) { HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4); // 启动TIM2 PWM触发脉冲 us_state = US_WAIT_ECHO; us_trigger_time = HAL_GetTick(); }} void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim); float calibration(float raw_cm); float median_filter(float new_val); void trigger_ultrasonic(); void delay_us(uint16_t us); void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim); /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_ADC1_Init(); MX_TIM3_Init(); MX_TIM4_Init(); MX_TIM1_Init(); MX_TIM2_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4); // 启动TIM2 PWM HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1); // 启动TIM1输入捕获中断 // HAL_Delay(3000); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { if (us_state == US_WAIT_ECHO) { // 超时检测(30ms未收到回波) if (HAL_GetTick() - us_trigger_time > MEASURE_TIMEOUT) { us_state = US_IDLE; } } static uint32_t last_measure = 0; if (HAL_GetTick() - last_measure >= 100 && us_state == US_IDLE) { trigger_ultrasonic_non_blocking(); last_measure = HAL_GetTick(); } /* 距离数据处理 --------------------------------------- */ static float filtered_distance = 0; filtered_distance = median_filter(distance_cm); filtered_distance = calibration(filtered_distance); if(filtered_distance < 10.0f) {HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET); } // if (main_count>5){ // // // dis = get_distance(); // if(dis < 20.0) { // 距离小于20cm亮灯 // void_flag = 1;} // main_count=0; // } int pwmVal_R = 200; int pwmVal_L = 200; RD_TSL(baoguang_count); Find_CCD_Zhongzhi(); // 计算特征区域经过时间(假设采样频率为100Hz) if (main_count>5){ feature_time = ccd_data_process(ADV, 50.0f); // 检查是否达到积分阈值 if (feature_time >= INTEGRATION_THRESHOLD) { stop_flag = 1; }} if (main_count>50000){ main_count=50000; } if (!stop_flag) { Turn_Pwm = turn(CCD_Zhongzhi, 0); // 右侧电机控制 if (pwmVal_R - Turn_Pwm > 0) { HAL_GPIO_WritePin(GPIOA, R1_Pin, 1); HAL_GPIO_WritePin(GPIOA, R2_Pin, 0); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, pwmVal_R - Turn_Pwm); } else if (pwmVal_R - Turn_Pwm < 0) { HAL_GPIO_WritePin(GPIOA, R1_Pin, 0); HAL_GPIO_WritePin(GPIOA, R2_Pin, 1); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, -pwmVal_R + Turn_Pwm); } else { HAL_GPIO_WritePin(GPIOA, R1_Pin, 0); HAL_GPIO_WritePin(GPIOA, R2_Pin, 0); } // 左侧电机控制 if (pwmVal_L + Turn_Pwm > 0) { HAL_GPIO_WritePin(GPIOA, L1_Pin, 1); HAL_GPIO_WritePin(GPIOA, L2_Pin, 0); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, pwmVal_L + Turn_Pwm); } else if (pwmVal_L + Turn_Pwm < 0) { HAL_GPIO_WritePin(GPIOA, L1_Pin, 0); HAL_GPIO_WritePin(GPIOA, L2_Pin, 1); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, -pwmVal_L - Turn_Pwm); } else { HAL_GPIO_WritePin(GPIOA, L1_Pin, 0); HAL_GPIO_WritePin(GPIOA, L2_Pin, 0); } } else if(void_flag==1){ HAL_GPIO_WritePin(GPIOA, R1_Pin, 1); HAL_GPIO_WritePin(GPIOA, R2_Pin, 0); HAL_GPIO_WritePin(GPIOA, L1_Pin, 1); HAL_GPIO_WritePin(GPIOA, L2_Pin, 0); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, 350); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2,100);//右边 HAL_Delay(300); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 350);//右边 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4,100); HAL_Delay(300); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 220);//右边 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4,200); HAL_Delay(100); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 350);//右边 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4,100); HAL_Delay(300); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, 350); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2,100);//右边 HAL_Delay(290); stop_flag = 0; // __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, -pwmVal_R); // __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, pwmVal_L); } else { static uint8_t is_first_run = 1; // 首次运行标志 if (is_first_run) { HAL_GPIO_WritePin(GPIOA, R1_Pin, 1); HAL_GPIO_WritePin(GPIOA, R2_Pin, 0); HAL_GPIO_WritePin(GPIOA, L1_Pin, 1); HAL_GPIO_WritePin(GPIOA, L2_Pin, 0); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 210);//右边 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4,200); HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); HAL_Delay(400); is_first_run = 0; // 清除首次标志 } // 停止小车 HAL_GPIO_WritePin(GPIOA, R1_Pin, 1); HAL_GPIO_WritePin(GPIOA, R2_Pin, 1); HAL_GPIO_WritePin(GPIOA, L1_Pin, 1); HAL_GPIO_WritePin(GPIOA, L2_Pin, 1); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, 0); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 0); } Dly_us(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM1 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) { if (us_state == US_WAIT_ECHO) { // 仅处理等待回波状态 if (!isFirstCaptured) { icVal1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); isFirstCaptured = 1; __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING); } else { icVal2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); uint32_t diff = (icVal2 > icVal1) ? (icVal2 - icVal1) : (0xFFFF - icVal1 + icVal2); distance_cm = diff * 0.034f / 2; isFirstCaptured = 0; __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING); us_state = US_IDLE; // 测量完成,回到空闲状态 } } } } /* 精准延时函数 */ void delay_us(uint16_t us) { __HAL_TIM_SET_COUNTER(&htim4, 0); while (__HAL_TIM_GET_COUNTER(&htim4) < us); } /* 中值滤波函数 */ #define FILTER_SIZE 5 float median_filter(float new_val) { static float buffer[FILTER_SIZE] = {0}; static uint8_t index = 0; float temp[FILTER_SIZE]; buffer[index] = new_val; index = (index + 1) % FILTER_SIZE; memcpy(temp, buffer, sizeof(temp)); // 冒泡排序 for(int i=0; i<FILTER_SIZE-1; i++){ for(int j=0; j<FILTER_SIZE-i-1; j++){ if(temp[j] > temp[j+1]){ float swap = temp[j]; temp[j] = temp[j+1]; temp[j+1] = swap; } } } return temp[FILTER_SIZE/2]; } /* 校准函数 */ float calibration(float raw_cm) { // 校准点配置(根据实测数据修改) const float calib_table[2][2] = {{15.0, 15.3}, {50.0, 49.7}}; if(raw_cm <= calib_table[0][0]) return raw_cm + (calib_table[0][1] - calib_table[0][0]); if(raw_cm >= calib_table[1][0]) return raw_cm + (calib_table[1][1] - calib_table[1][0]); float k = (calib_table[1][1]-calib_table[0][1]) / (calib_table[1][0]-calib_table[0][0]); return k * (raw_cm - calib_table[0][0]) + calib_table[0][1]; } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file tim.c * @brief This file provides code for the configuration * of the TIM instances. ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "tim.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ TIM_HandleTypeDef htim1; TIM_HandleTypeDef htim2; TIM_HandleTypeDef htim3; TIM_HandleTypeDef htim4; /* TIM1 init function */ void MX_TIM1_Init(void) { /* USER CODE BEGIN TIM1_Init 0 */ /* USER CODE END TIM1_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_IC_InitTypeDef sConfigIC = {0}; /* USER CODE BEGIN TIM1_Init 1 */ /* USER CODE END TIM1_Init 1 */ htim1.Instance = TIM1; htim1.Init.Prescaler = 39; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 65535; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_IC_Init(&htim1) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; sConfigIC.ICFilter = 0; if (HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM1_Init 2 */ /* USER CODE END TIM1_Init 2 */ } /* TIM2 init function */ void MX_TIM2_Init(void) { /* USER CODE BEGIN TIM2_Init 0 */ /* USER CODE END TIM2_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; /* USER CODE BEGIN TIM2_Init 1 */ /* USER CODE END TIM2_Init 1 */ htim2.Instance = TIM2; htim2.Init.Prescaler = 19; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 9; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 10; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM2_Init 2 */ /* USER CODE END TIM2_Init 2 */ HAL_TIM_MspPostInit(&htim2); } /* TIM3 init function */ void MX_TIM3_Init(void) { /* USER CODE BEGIN TIM3_Init 0 */ /* USER CODE END TIM3_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; /* USER CODE BEGIN TIM3_Init 1 */ /* USER CODE END TIM3_Init 1 */ htim3.Instance = TIM3; htim3.Init.Prescaler = 0; htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 499; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim3) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&htim3) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM3_Init 2 */ /* USER CODE END TIM3_Init 2 */ HAL_TIM_MspPostInit(&htim3); } /* TIM4 init function */ void MX_TIM4_Init(void) { /* USER CODE BEGIN TIM4_Init 0 */ /* USER CODE END TIM4_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; /* USER CODE BEGIN TIM4_Init 1 */ /* USER CODE END TIM4_Init 1 */ htim4.Instance = TIM4; htim4.Init.Prescaler = 19; htim4.Init.CounterMode = TIM_COUNTERMODE_UP; htim4.Init.Period = 65535; htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim4) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM4_Init 2 */ /* USER CODE END TIM4_Init 2 */ } void HAL_TIM_IC_MspInit(TIM_HandleTypeDef* tim_icHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(tim_icHandle->Instance==TIM1) { /* USER CODE BEGIN TIM1_MspInit 0 */ /* USER CODE END TIM1_MspInit 0 */ /* TIM1 clock enable */ __HAL_RCC_TIM1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM1 GPIO Configuration PA8 ------> TIM1_CH1 */ GPIO_InitStruct.Pin = ECHO_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(ECHO_GPIO_Port, &GPIO_InitStruct); /* TIM1 interrupt Init */ HAL_NVIC_SetPriority(TIM1_CC_IRQn, 3, 0); HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); /* USER CODE BEGIN TIM1_MspInit 1 */ /* USER CODE END TIM1_MspInit 1 */ } } void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance==TIM2) { /* USER CODE BEGIN TIM2_MspInit 0 */ /* USER CODE END TIM2_MspInit 0 */ /* TIM2 clock enable */ __HAL_RCC_TIM2_CLK_ENABLE(); /* TIM2 interrupt Init */ HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); /* USER CODE BEGIN TIM2_MspInit 1 */ /* USER CODE END TIM2_MspInit 1 */ } else if(tim_baseHandle->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspInit 0 */ /* USER CODE END TIM3_MspInit 0 */ /* TIM3 clock enable */ __HAL_RCC_TIM3_CLK_ENABLE(); /* USER CODE BEGIN TIM3_MspInit 1 */ /* USER CODE END TIM3_MspInit 1 */ } else if(tim_baseHandle->Instance==TIM4) { /* USER CODE BEGIN TIM4_MspInit 0 */ /* USER CODE END TIM4_MspInit 0 */ /* TIM4 clock enable */ __HAL_RCC_TIM4_CLK_ENABLE(); /* TIM4 interrupt Init */ HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM4_IRQn); /* USER CODE BEGIN TIM4_MspInit 1 */ /* USER CODE END TIM4_MspInit 1 */ } } void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(timHandle->Instance==TIM2) { /* USER CODE BEGIN TIM2_MspPostInit 0 */ /* USER CODE END TIM2_MspPostInit 0 */ __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM2 GPIO Configuration PA3 ------> TIM2_CH4 */ GPIO_InitStruct.Pin = TRIG_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(TRIG_GPIO_Port, &GPIO_InitStruct); /* USER CODE BEGIN TIM2_MspPostInit 1 */ /* USER CODE END TIM2_MspPostInit 1 */ } else if(timHandle->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspPostInit 0 */ /* USER CODE END TIM3_MspPostInit 0 */ __HAL_RCC_GPIOB_CLK_ENABLE(); /**TIM3 GPIO Configuration PB1 ------> TIM3_CH4 PB5 ------> TIM3_CH2 */ GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); __HAL_AFIO_REMAP_TIM3_PARTIAL(); /* USER CODE BEGIN TIM3_MspPostInit 1 */ /* USER CODE END TIM3_MspPostInit 1 */ } } void HAL_TIM_IC_MspDeInit(TIM_HandleTypeDef* tim_icHandle) { if(tim_icHandle->Instance==TIM1) { /* USER CODE BEGIN TIM1_MspDeInit 0 */ /* USER CODE END TIM1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM1_CLK_DISABLE(); /**TIM1 GPIO Configuration PA8 ------> TIM1_CH1 */ HAL_GPIO_DeInit(ECHO_GPIO_Port, ECHO_Pin); /* TIM1 interrupt Deinit */ HAL_NVIC_DisableIRQ(TIM1_CC_IRQn); /* USER CODE BEGIN TIM1_MspDeInit 1 */ /* USER CODE END TIM1_MspDeInit 1 */ } } void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance==TIM2) { /* USER CODE BEGIN TIM2_MspDeInit 0 */ /* USER CODE END TIM2_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM2_CLK_DISABLE(); /* TIM2 interrupt Deinit */ HAL_NVIC_DisableIRQ(TIM2_IRQn); /* USER CODE BEGIN TIM2_MspDeInit 1 */ /* USER CODE END TIM2_MspDeInit 1 */ } else if(tim_baseHandle->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspDeInit 0 */ /* USER CODE END TIM3_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM3_CLK_DISABLE(); /* USER CODE BEGIN TIM3_MspDeInit 1 */ /* USER CODE END TIM3_MspDeInit 1 */ } else if(tim_baseHandle->Instance==TIM4) { /* USER CODE BEGIN TIM4_MspDeInit 0 */ /* USER CODE END TIM4_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM4_CLK_DISABLE(); /* TIM4 interrupt Deinit */ HAL_NVIC_DisableIRQ(TIM4_IRQn); /* USER CODE BEGIN TIM4_MspDeInit 1 */ /* USER CODE END TIM4_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ 有什么问题吗

根据以上我问你的,你能帮我优化我的这段prompt吗: You are a powerful text-to-SQL model. Your job is to answer questions about a database. You are given a question and context regarding one or more tables. You must output the SQL query that answers the question. ### Input: ### Context: { "table_name": "iPortal.dbo.kpi_indicator", "table_description": "汽车KPI数据描述表,日期,班次,目标产量,实际产量等等数据", "fields": [ { "chinese_name": "工段", "field_name": "kpi", "description": "工段描述,比如Chassis_1,Chassis_2,Door_line等汽车生产线工段", "type": "varchar(30)", "example": "Chassis_3" }, { "chinese_name": "日期", "field_name": "date", "description": "日期", "type": "date", "example": "2025-03-18" }, { "chinese_name": "车间", "field_name": "shop", "description": "车间名称", "type": "varchar(30)", "example": "MRA2_AS" }, { "chinese_name": "班次", "field_name": "shift", "description": "班次信息,1表示为班次1,2表示为班次2", "type": "int", "example": "1" }, { "chinese_name": "实际产量", "field_name": "actual", "description": "实际产量的值", "type": "int", "example": "213" }, { "chinese_name": "计划产量/目标产量", "field_name": "plan", "description": "计划产量/目标产量的值", "type": "int", "example": "3" }, { "chinese_name": "有效生产时间", "field_name": "ebot_net", "description": "用来计算oee(不区分大小写)", "type": "float", "example": "464" }, { "chinese_name": "计划运行时间", "field_name": "business_operation_time", "description": "用来计算oee(不区分大小写)", "type": "float", "example": "690" } ], "common_queries": [ { "chinese": "查询某个时间段的某车间前三天的实际产量", "sql": "SELECT shop AS 车间,SUM(actual) AS 总产量 FROM iPortal.dbo.kpi_indicator WHERE shop = 'MRA2_AS' AND date between '2025-03-23' and '2025-03-25' GROUP BY shop" }, { "chinese": "xx天/xx时间段,某车间的OEE实际具体数值", "sql": "SELECT SUM(ebot_net) * 1.0 / NULLIF(SUM(business_operation_time), 0) AS OEE FROM ( SELECT ebot_net, business_operation_time, CASE WHEN kpi IN ('Chassis-3', 'Chassis4') THEN 'Chassis_3' ELSE kpi END AS converted_kpi FROM iPortal.dbo.kpi_indicator WHERE date BETWEEN '2025-03-01' AND '2025-03-10' and shop = 'MRA2_AS' ) AS filtered_data WHERE converted_kpi = 'Chassis_3'" }, { "chinese": "xx天/xx时间段,某车间的某个kpi区域OEE实际具体数值", "sql": "SELECT CASE WHEN SUM(business_operation_time) = 0 THEN 0 ELSE CAST(SUM(ebot_net) AS FLOAT) / SUM(business_operation_time) END AS OEE FROM iPortal.dbo.kpi_indicator WHERE kpi = 'Trim_1' and date BETWEEN '2025-03-01' AND '2025-03-10' and shop = 'MRA2_AS'" } ] } 请注意: 1.最后只给出sql语句, 2.其中如果用户问oee数值相关问题,一定不要直接用数据表中的oee字段! 请用ebot_net和business_operation_time这两个字段计算: a.如果用户问车间的实际oee,那么,用有效生产时间总和(ebot_net)除以计划运行时间总和(business_operation_time),结果以百分比表示。当总运行时间为零时返回空值,计算范围限定为合并后的Chassis_3类设备(由原始kpi值Chassis-3和Chassis4合并而成),时间范围以及车间以用户提问进行对应查询。 b.若果用户问的是某kpi区域,那么就用kpi为用户提问区域的有效生产时间总和(ebot_net)除以计划运行时间总和(business_operation_time) 3.当前的时间是 4.表名必须是iPortal.dbo.kpi_indicator ### Response:

大家在看

recommend-type

AAA2.5及汉化补丁

Advanced Aircraft Analysis V2.5.1.53 (3A) 在win7 64位上安装测试。有注册机和安装视频。支持winxp和win732位和64位系统。 Darcorp Advanced Aircraft Analysis V2.5.1.53 (AAA) 软件是一款面向于高级用户的飞机设计和仿真分析软件,目前广泛应用于数十个国家的各种机构,已然成为飞机设计、开发、稳定性分析以及飞行控制的工业标准软件。适用于 FAR23、FAR25、UAV无人驾驶飞机与 Military 规范,为全球飞机公司(如波音公司)、政府部门(如 FAA)与学校采用于飞机初步设计、分析、与 3-D 绘图的一套完整软件工具。 Advanced Aircraft Analysis (AAA) 是行业标准的飞机设计,稳定性和控制分析软件。 安装在超过45个国家,AAA所使用的主要航空工程大学,飞机制造商和世界各地的军事组织。 Advanced Aircraft Analysis(AAA)是行业标准的飞机设计 AAA提供了一个功能强大的框架,以支持飞机初步设计迭代和非独特的过程。 AAA计划允许学生和初步设计工程师从早期的大小通过开环和闭环动态稳定性和灵敏度分析的重量,而该机的配置工作在监管和成本的限制。
recommend-type

人脸检测 人脸关键点检测 口罩检测.zip

RetinaFace 实现的同时人脸检测 关键点 口罩检测 1. linux用户打开rcnn/cython/setup.py 121行注释(windows跳过) 2. 进入cython目录 执行python setup.py build_ext --inplace 3. 运行python test.py 注意如果缺少mxnet等类库 自行使用pip安装
recommend-type

commons-collections4-4.1-bin.zip

commonS操作源码及jar包,没有外部依赖,jar包比较全
recommend-type

CENTUM TP 安装授权及windows设置.rar

CENTUM VP系统软件的安装,以及安装前的必要工作。 CENTUM VP 系统软件的构成: CENTUM VP software(系统组态、操作监视功能、其他可选软件包)控制总线驱 动电子文档。 CENTUM VP 系统软件的安装步骤 安装Windows。(如果PC已经安装可以不做) 启动 Windows 对Windows 进行必要设置以便CENTUM VP的运行: 添加网络适配器 安装Ethernet 适配器(已经存在不必安装)。 安装控制总线驱动(已经存在不必安装)。 添加打印机 安装Service Pack。 安装USB操作键盘驱动 使用USB接口操作键盘时安装 安装CENTUM VP 软件。 Windows构成指定。(包括运行CENTUM VP必须的网络、用户名、其他必要信息 等的设置)。 在CENTUM VP的功能已经具备,如果仅仅是用于工程组态,不需要制定“CENTUM” 用户“自动登录HIS”。 以管理员身份对以下内容进行必要设置。 l 计算机名(站名) 计算机名是Windows 网络用于识别每一台计算机的标志。 一个站名是CENTUM VP 系统中,根据控制总线地址确定的唯一名称。 应确保计算机名和站名的一致性。 计算机名(站名)的设定例: HIS0164 (HISddss:“dd”域号;“ss”站号。) l IP 地址 IP 地址是Vnet 或Vnet Open。用于识别每台PC的确定地址。在各网络中每台PC 的地址是唯一的。 例:172.16.1.64(Vnet);192.168.129.193(Vnet Open) Vnet 地址:172.16.dd.ss “dd”域号:01~16 “ss”站号:01~64 Vnet Open 地址:192.168.128+ dd.129+ ss 子网掩码 255.255.0.0 设置Administrator 密码 为PC机管理者设定密码。 l CENTUM VP 帐户和密码 操作监视功能帐户:CENTUM(系统固定)。 该帐户是在系统安装时自动生成的,账户名不能更改。
recommend-type

Cluster Load Balance Algorithm Simulation Based on Repast

Cluster Load Balance Algorithm Simulation Based on Repast

最新推荐

recommend-type

mavlink协议,c++语言版本,用于px4飞控通信

mavlink协议,c++语言版本,用于px4飞控通信
recommend-type

(完整word版)网上订餐系统软件测试总结报告.doc

(完整word版)网上订餐系统软件测试总结报告.doc
recommend-type

chromedriver-mac-x64-140.0.7295.0(Canary).zip

chromedriver-mac-x64-140.0.7295.0(Canary).zip
recommend-type

(完整版)基因工程药物干扰素的制备.ppt

(完整版)基因工程药物干扰素的制备.ppt
recommend-type

用户完成登录后自动跳转至主界面

资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 Delphi 7 中做一个「登录→主界面」的完整流程: 建立登录窗体 File → New → VCL Forms Application,拖两个 TEdit(用户名、密码)、一个 TButton(登录)、一个 TLabel(提示)。把 Edit2 的 PasswordChar 设为 *,Button.Caption 设为“登录”。 写验证代码 Button 的 OnClick 里: 多窗体管理 Project → Options → Forms,把 Form1 设为主窗体,Form2 设为可用窗体。登录成功后创建并显示 Form2,隐藏 Form1;主界面退出时调用 Application.Terminate 结束程序。 错误提示 验证失败直接用 ShowMessage,也可把 Label 换成红色文字提示。
recommend-type

Web2.0新特征图解解析

Web2.0是互联网发展的一个阶段,相对于早期的Web1.0时代,Web2.0具有以下显著特征和知识点: ### Web2.0的定义与特点 1. **用户参与内容生产**: - Web2.0的一个核心特征是用户不再是被动接收信息的消费者,而是成为了内容的生产者。这标志着“读写网络”的开始,用户可以在网络上发布信息、评论、博客、视频等内容。 2. **信息个性化定制**: - Web2.0时代,用户可以根据自己的喜好对信息进行个性化定制,例如通过RSS阅读器订阅感兴趣的新闻源,或者通过社交网络筛选自己感兴趣的话题和内容。 3. **网页技术的革新**: - 随着技术的发展,如Ajax、XML、JSON等技术的出现和应用,使得网页可以更加动态地与用户交互,无需重新加载整个页面即可更新数据,提高了用户体验。 4. **长尾效应**: - 在Web2.0时代,即使是小型或专业化的内容提供者也有机会通过互联网获得关注,这体现了长尾理论,即在网络环境下,非主流的小众产品也有机会与主流产品并存。 5. **社交网络的兴起**: - Web2.0推动了社交网络的发展,如Facebook、Twitter、微博等平台兴起,促进了信息的快速传播和人际交流方式的变革。 6. **开放性和互操作性**: - Web2.0时代倡导开放API(应用程序编程接口),允许不同的网络服务和应用间能够相互通信和共享数据,提高了网络的互操作性。 ### Web2.0的关键技术和应用 1. **博客(Blog)**: - 博客是Web2.0的代表之一,它支持用户以日记形式定期更新内容,并允许其他用户进行评论。 2. **维基(Wiki)**: - 维基是另一种形式的集体协作项目,如维基百科,任何用户都可以编辑网页内容,共同构建一个百科全书。 3. **社交网络服务(Social Networking Services)**: - 社交网络服务如Facebook、Twitter、LinkedIn等,促进了个人和组织之间的社交关系构建和信息分享。 4. **内容聚合器(RSS feeds)**: - RSS技术让用户可以通过阅读器软件快速浏览多个网站更新的内容摘要。 5. **标签(Tags)**: - 用户可以为自己的内容添加标签,便于其他用户搜索和组织信息。 6. **视频分享(Video Sharing)**: - 视频分享网站如YouTube,用户可以上传、分享和评论视频内容。 ### Web2.0与网络营销 1. **内容营销**: - Web2.0为内容营销提供了良好的平台,企业可以通过撰写博客文章、发布视频等内容吸引和维护用户。 2. **社交媒体营销**: - 社交网络的广泛使用,使得企业可以通过社交媒体进行品牌传播、产品推广和客户服务。 3. **口碑营销**: - 用户生成内容、评论和分享在Web2.0时代更易扩散,为口碑营销提供了土壤。 4. **搜索引擎优化(SEO)**: - 随着内容的多样化和个性化,SEO策略也必须适应Web2.0特点,注重社交信号和用户体验。 ### 总结 Web2.0是对互联网发展的一次深刻变革,它不仅仅是一个技术变革,更是人们使用互联网的习惯和方式的变革。Web2.0的时代特征与Web1.0相比,更加注重用户体验、社交互动和信息的个性化定制。这些变化为网络营销提供了新的思路和平台,也对企业的市场策略提出了新的要求。通过理解Web2.0的特点和应用,企业可以更好地适应互联网的发展趋势,实现与用户的深度互动和品牌的有效传播。
recommend-type

【C++编程新手必看】:一步步带你制作出风靡全球的“别踩白块儿”游戏

# 摘要 本文全面介绍C++编程在游戏开发中的应用,涵盖了从基础概念到具体实现的多个方面。首先,文章提供了游戏开发环境的搭建指南,包括编译器配置和开发工具的选择。随后,重点介绍了游戏主循环和基本框架的构建,强调了事件处理和渲染技术。在游戏逻辑和交互设计方面,本文阐述了界面布局、事件响应和游戏状态管理的核心实现。为了提升游戏体验,本文还探讨了添加音效和背景音乐以及开发高级游戏特性的方法。最后,文章介绍了性能优化和跨平台发布的过程,包括游戏的打包和针对不同平台的发布策略。本文旨在为C++游戏开发者提供一个实用的开发指南,帮助他们从零开始构建出性能优化、跨平台兼容的游戏。 # 关键字 C++编程;
recommend-type

使用scikit-learn训练模型来预测鸢尾花种类

<think>我们使用scikit-learn库来训练一个分类模型预测鸢尾花种类。鸢尾花数据集是scikit-learn内置的经典数据集,包含三种鸢尾花的四个特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度)和对应的类别标签。步骤:1.导入必要的库和数据集2.数据探索(可选,但建议了解数据)3.数据预处理(如划分训练集和测试集、标准化等)4.选择模型(例如KNN、随机森林等)5.训练模型6.模型评估7.使用模型进行预测下面以KNN(K近邻)算法为例,展示完整流程。</think>### 使用 scikit-learn 训练鸢尾花分类模型 以下是基于 scikit-learn 训练鸢尾花分类模型的
recommend-type

WWF工作流设计器C#源码解析及演示

### WWF工作流设计器控件C#源码知识点 #### 1. WWF(Windows Workflow Foundation)概述 WWF是微软公司推出的一个工作流框架,作为.NET Framework的一部分。它提供了一套丰富的API,用于设计、执行和管理工作流。工作流可以用于各种应用程序,包括Web应用、服务和桌面应用,使得开发者能够将复杂的业务逻辑以工作流的形式表现出来,简化业务流程自动化和管理。 #### 2. 工作流设计器控件(Workflow Designer Control) 工作流设计器控件是WWF中的一个组件,主要用于提供可视化设计工作流的能力。它允许用户通过拖放的方式在界面上添加、配置和连接工作流活动,从而构建出复杂的工作流应用。控件的使用大大降低了工作流设计的难度,并使得设计工作流变得直观和用户友好。 #### 3. C#源码分析 在提供的文件描述中提到了两个工程项目,它们均使用C#编写。下面分别对这两个工程进行介绍: - **WorkflowDesignerControl** - 该工程是工作流设计器控件的核心实现。它封装了设计工作流所需的用户界面和逻辑代码。开发者可以在自己的应用程序中嵌入这个控件,为最终用户提供一个设计工作流的界面。 - 重点分析:控件如何加载和显示不同的工作流活动、控件如何响应用户的交互、控件状态的保存和加载机制等。 - **WorkflowDesignerExample** - 这个工程是演示如何使用WorkflowDesignerControl的示例项目。它不仅展示了如何在用户界面中嵌入工作流设计器控件,还展示了如何处理用户的交互事件,比如如何在设计完工作流后进行保存、加载或执行等。 - 重点分析:实例程序如何响应工作流设计师的用户操作、示例程序中可能包含的事件处理逻辑、以及工作流的实例化和运行等。 #### 4. 使用Visual Studio 2008编译 文件描述中提到使用Visual Studio 2008进行编译通过。Visual Studio 2008是微软在2008年发布的集成开发环境,它支持.NET Framework 3.5,而WWF正是作为.NET 3.5的一部分。开发者需要使用Visual Studio 2008(或更新版本)来加载和编译这些代码,确保所有必要的项目引用、依赖和.NET 3.5的特性均得到支持。 #### 5. 关键技术点 - **工作流活动(Workflow Activities)**:WWF中的工作流由一系列的活动组成,每个活动代表了一个可以执行的工作单元。在工作流设计器控件中,需要能够显示和操作这些活动。 - **活动编辑(Activity Editing)**:能够编辑活动的属性是工作流设计器控件的重要功能,这对于构建复杂的工作流逻辑至关重要。 - **状态管理(State Management)**:工作流设计过程中可能涉及保存和加载状态,例如保存当前的工作流设计、加载已保存的工作流设计等。 - **事件处理(Event Handling)**:处理用户交互事件,例如拖放活动到设计面板、双击活动编辑属性等。 #### 6. 文件名称列表解释 - **WorkflowDesignerControl.sln**:解决方案文件,包含了WorkflowDesignerControl和WorkflowDesignerExample两个项目。 - **WorkflowDesignerControl.suo**:Visual Studio解决方案用户选项文件,该文件包含了开发者特有的个性化设置,比如窗口布局、断点位置等。 - **Thumbs.db**:缩略图缓存文件,由Windows自动生成,用于存储文件夹中的图片缩略图,与WWF工作流设计器控件功能无关。 - **WorkflowDesignerExample**:可能是一个文件夹,包含了示例工程相关的所有文件,或者是示例工程的可执行文件。 - **EULA.txt**:最终用户许可协议文本文件,通常说明了软件的版权和使用许可条件。 综上所述,该文件集包含了WWF工作流设计器控件的完整C#源码以及相应的Visual Studio项目文件,开发者可以利用这些资源深入理解WWF工作流设计器控件的工作机制,并将其应用于实际的项目开发中,实现工作流的设计和管理功能。
recommend-type

CAD数据在ANSA中:完美修复几何数据的策略与方法

# 摘要 CAD数据的准确性和几何完整性对于产品设计和工程分析至关重要。本文首先强调了CAD数据和几何修复的重要性,随后介绍了ANSA软件在处理CAD数据中的角色。通过详细的分析,本文探讨了几何数据的常见问题,以及有效的手动和自动修复技术。文中还提供了几何修复在实际应用中的案例分析,并讨论了行业未来对几何修复技术的需求和新兴技术趋势。文章旨在为CAD数据几何修复提供全面的理论知识、诊断方法和修复策略,并