网站建设搜索优化app推广新闻营销/互联网全网营销
这里写目录标题
- 前言
- 一、赛题分析
- 1、车型选择
- 2、巡线
- 1、OpenMv循迹
- 2、灰度循迹
- 3、装载药品
- 4、识别数字
- 5、LED指示
- 6、双车通信
- 7、转向方案
- 1、开环转向
- 2、位置环速度环闭环串级转向
- 3、MPU6050转向
- 二、调试经验分享
- 1、循迹
- 2、识别数字
- 3、转向
- 4、双车通信
- 5、逻辑处理
- 6、心态问题
- 总结
- 开源链接
前言
自己是今年准备电赛的同学一名,电赛结束了,想把自己之前刷过的题目,通过这篇文章,来分享一波做这道题的思路和调试方法
自己在做之前的电赛题目时,也苦苦没有思路,不知道该怎么去下手,面对题目的要求和限制,应该如何去分析和实现
由于我们主要是准备小车相关的,大部分时间都用来刷电赛期间出现的小车题目了
其中包括21年F题——智能送药小车、22年C题——小车跟随系统、22年B题——自动泊车系统等
可是今年电赛题目并没有小车,小车和无人机一起
可以看出电赛题目更贴近于综合,对个人能力的要求更高了
好了,废话不多说,我会在这段时间,将学习到的知识和做电赛题目的代码一步一步写出文章分享和教学,希望以后的同学可以参考学习,而不是盲目无从下手
一、赛题分析
赛题地图如下
1、车型选择
在做这道题目的时候,采用过好几种车型,并且采用过不同的方案,其中一种是
- 四轮小车,前轮为舵机转向,后两轮为驱动轮
- 三轮小车,前轮为万向轮或牛眼轮,后两轮为驱动轮
在实践的过程中,因为题目要求是转向90°,这种情况下三轮小车前轮为从动轮的更占优势,转向更为方便,而舵机前轮后轮驱动的车型转向就无法像三轮一般丝滑,略显笨重,但是也可以实现
2、巡线
巡线有两种方案
- OpenMv巡线
- 灰度循迹
这两种循迹方案都是差不多的,都是检测当前小车行进的位置的偏差的误差值来改变小车的行进方向
就是接收误差,将误差带入PID进行计算,得出巡线补偿,使小车始终保持在期望中心
1、OpenMv循迹
这部分我就不多写了,OpenMv有很多种方法,来巡线,这部分是队友负责,我大概也知道一些,比如二值化、色块追踪、模拟灰度传感器等
32这边始终接收到的数据就是一个偏差Err,根据这个Err来计算PID,调节PID参数,到达期巡线望值
最后这个计算出来的值一般也是串起来的,循线环输出带入速度环的输入,两轮不同的方向,一边+,一边-,调节PID参数即可丝滑循迹
float location_pid_realize(_pid *pid, float actual_val)
{/* 计算偏差 这里的偏差是指 巡线偏差 设定的巡线期望值 和 MV传回的巡线实际值 得偏差 */pid->err = pid->target_val - actual_val;pid->integral += pid->err; // 误差累积// if (pid->err >= 1000) // 积分限幅// {// pid->err = 0;// }// if (huidu.output >= 550)// huidu.output = 550;// if (huidu.output <= -600)// huidu.output = -600;/*PID算法实现*/pid->actual_val = pid->Kp * pid->err + pid->Ki * pid->integral + pid->Kd * (pid->err - pid->err_last);/*误差传递*/pid->err_last = pid->err;/*返回当前实际值*/return pid->actual_val;
}/*** @brief 巡线pid输出函数 后轮差速* @param actual_val:实际值* @note 无* @retval 通过PID计算后的输出*/
float OpenMV_location_pid_control(void)
{float Expect_Pwm = 0.0; // 当前控制值Pid_location = OpenMv_data1 * 10; // 获取巡线模块当前误差 后轮差速// Pid_location = 0;Expect_Pwm = location_pid_realize(&OpenMv_pid_track, Pid_location); // 进行 PID 计算// #if defined(PID_ASSISTANT_EN)// set_computer_value(SEND_FACT_CMD, CURVES_CH1, &actual_speed, 1); // 给通道 1 发送实际值// #endifreturn Expect_Pwm;
}
2、灰度循迹
这部分我使用的是五路灰度循迹,也是根据灰度管检测当前时刻的巡线变化来得出巡线偏差,带入PID进行计算,这和OpenMv巡线类似,我给出如何获得误差,大家就可以把误差带入PID进行计算了
最后这个计算出来的值一般也是串起来的,循线环输出带入速度环的输入,两轮不同的方向,一边+,一边-,调节PID参数即可丝滑循迹
/** @Author: _oufen* @Date: 2023-04-15 09:06:56* @LastEditTime: 2023-07-27 19:50:46* @Description: 五路灰度传感器*//* Includes -------------------------------------------------------------------------------------------------------------*/
#include "tracking.h"/* Define -----------------------------------------------------------------------------------------------------------------*/
PID_Track pid_track;
/* Functions -----------------------------------------------------------------------------------------------------------------*/
/*** @brief 五路灰度GPIO初始化* @param None* @retval None* 分别使用到了 PB0/PB1/PB8/PB9/PA4*/
void Tracking_Init(void)
{// GPIO初始化 上拉输入MY_GPIO_Init(GPIOB, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9, GPIO_Mode_IPD);MY_GPIO_Init(GPIOA, GPIO_Pin_4, GPIO_Mode_IPD);
}/*** @brief 五路灰度GPIO初始化* @param None* @retval None* 分别使用到了 PB0/PB1/PB8/PB9/PA4* 计划使用中间三路进行巡线 最左端和最右端进行识别十字路口和丁字路口* 这里行驶的距离和巡线要有巡线补偿* 低电平有效输出 感应黑色输出高电平*/
void Tracking_Control(void)
{
}void PID_xun_init(void) // 五路灰度循迹pid初始化
{pid_track.Kp = 35.0;pid_track.Ki = 0.0;pid_track.Kd = 0.0;pid_track.err = 0.0;pid_track.err_last = 0.0;pid_track.integral = 0.0;pid_track.output = 0.0;
}/*** @brief 循迹模块对应所有初始化* @param None* @retval None*/
void Tracking_All_Init(void)
{Tracking_Init(); // 循迹GPIO初始化PID_xun_init(); // 循迹PID参数初始化
}float PID_output(void)
{if ((L2 == 1) && (L1 == 0) && (M == 0) && (R1 == 0) && (R2 == 0)) // 10000{pid_track.err = -3;}else if ((L2 == 1) && (L1 == 1) && (M == 0) && (R1 == 0) && (R2 == 0)) // 11000{pid_track.err = -2;}else if ((L2 == 0) && (L1 == 1) && (M == 0) && (R1 == 0) && (R2 == 0)) // 01000{pid_track.err = -1.5;}else if ((L2 == 0) && (L1 == 1) && (M == 1) && (R1 == 0) && (R2 == 0)) // 01100{pid_track.err = -1;}else if ((L2 == 1) && (L1 == 1) && (M == 1) && (R1 == 0) && (R2 == 0)) // 11100{pid_track.err = -4;}else if ((L2 == 0) && (L1 == 0) && (M == 1) && (R1 == 0) && (R2 == 0)) // 00100{pid_track.err = 0;}else if ((L2 == 0) && (L1 == 0) && (M == 1) && (R1 == 1) && (R2 == 0)) // 00110{pid_track.err = 1;}else if ((L2 == 0) && (L1 == 0) && (M == 0) && (R1 == 1) && (R2 == 0)) // 00010{pid_track.err = 1.5;}else if ((L2 == 0) && (L1 == 0) && (M == 0) && (R1 == 1) && (R2 == 1)) // 00011{pid_track.err = 2;}else if ((L2 == 0) && (L1 == 0) && (M == 0) && (R1 == 0) && (R2 == 1)) // 00001{pid_track.err = 3;}else if ((L2 == 0) && (L1 == 0) && (M == 1) && (R1 == 1) && (R2 == 1)) // 00111{pid_track.err = 4;}// 十字路口else if ((L2 == 0) && (L1 == 0) && (M == 1) && (R1 == 0) && (R2 == 1)) // 00101{pid_track.err = 4;}elsepid_track.err = 0;pid_track.integral += pid_track.err;pid_track.output = pid_track.Kp * pid_track.err + pid_track.Ki * pid_track.integral + pid_track.Kd * (pid_track.err - pid_track.err_last);pid_track.err_last = pid_track.err;return pid_track.output;
}/*****************************************************END OF FILE*********************************************************/
3、装载药品
是否装载药品采用红外对管来实现
这部分我也不多说了,就是检测红外的高低电平,分别对应药品的状态
4、识别数字
识别数字,我们采用的是OpenMv4和OpenMv4Plus,病房前识别数字采用模板匹配,小车行进时采用神经网络匹配数字,效果很好
但是由于我不是负责这方面的,所以,只知道一个大概思路
5、LED指示
这个也没什么好说的,到达相应的状态时,点亮和熄灭LED就行了
6、双车通信
这里我们采用的方案有两种
- 蓝牙通信模块,HC-05
- Zigbee通信模块
其实,配置好了之后,这两种使用都是一样的,不同的方面就是Zigbee相较于蓝牙配置好配置一些,更方便一些
就一般的通信来说,蓝牙足够了
关于这方面的通信模块,一般肯定不会只发一个数据,这个时候就需要定义数据包协议,以保证发方和收方接收的数据的准确性
我自己定义的数据包协议和OpenMv协议相同
数据包为 b3 b3 data1 data2 data3 5b
其中b3 b3为帧头,5b为帧尾
下方是相关代码
/** @Author: _oufen* @Date: 2023-07-06 15:05:38* @LastEditTime: 2023-07-07 16:55:46* @Description:*/
#include "usart3.h"int Bluetooth_Receive_Buff[6]; // 蓝牙接收数据
int16_t data1; // 三个有效数据位 第一个为 模式选择
int16_t data2; // 第二个为 停车标志
int16_t data3; // 第三个为 主车走的圈数/*** @brief 串口3初始化* @param 无* @retval 无*/
void uart3_init(u32 bound)
{// GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能USART3,GPIOB时钟// USART3_TX GPIOB2 RX PA2GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // PA2GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIOB2// USART3_RX GPIOB3 TX PA3GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; // PB11GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIOB3// USART3 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能NVIC_Init(&NVIC_InitStructure); // 根据指定的参数初始化VIC寄存器// USART 初始化设置USART_InitStructure.USART_BaudRate = bound; // 串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一个停止位USART_InitStructure.USART_Parity = USART_Parity_No; // 无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收发模式USART_Init(USART3, &USART_InitStructure); // 初始化串口2USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); // 开启串口接受中断USART_Cmd(USART3, ENABLE); // 使能串口2
}/*** @brief 串口3发送数据包* @param 无* @retval 无*/
void u3_sendData(u8 *str)
{u8 i = 0;for (i = 0; i < 2; i++) // b3 b3{USART_SendData(USART3, 0xb3);while (USART_GetFlagStatus(USART3, USART_FLAG_TC) != SET);}for (i = 0; i < 3; i++) // 发送三位有效位{USART_SendData(USART3, str[i]);while (USART_GetFlagStatus(USART3, USART_FLAG_TC) != SET);}USART_SendData(USART3, 0x5b); // 0x5bwhile (USART_GetFlagStatus(USART3, USART_FLAG_TC) != SET);
}void Bluetooth_Data(void) // 处理蓝牙接收的数据
{data1 = Bluetooth_Receive_Buff[2];data2 = Bluetooth_Receive_Buff[3];data3 = Bluetooth_Receive_Buff[4];
}/*** @brief 串口3接收数据包 解析接收数据包 解析数据包 b3 b3 data1 data2 data3 5b* @param 无* @retval 无*/
void Bluetooth_Receive_Data(int16_t data)
{int i = 0;static u8 state = 0; // 初始化状态值if (state == 0 && data == 0xb3) // 第一个帧头 0xb3{state = 1;Bluetooth_Receive_Buff[0] = data;}else if (state == 1 && data == 0xb3) // 第二个帧头 0xb3{state = 2;Bluetooth_Receive_Buff[1] = data;}else if (state == 2) // 第一个有效数据{state = 3;Bluetooth_Receive_Buff[2] = data;}else if (state == 3) // 第二个有效数据{state = 4;Bluetooth_Receive_Buff[3] = data;}else if (state == 4) // 第三个有效数据{state = 5;Bluetooth_Receive_Buff[4] = data;}else if (state == 5) // 接收帧尾{if (data == 0x5b) // 是帧尾 直接回到初始状态{state = 0;Bluetooth_Receive_Buff[5] = data;Bluetooth_Data(); // 处理数据}else if (data != 0x5b) // 不是帧尾 所有数据置0{state = 0;for (i = 0; i < 6; i++){Bluetooth_Receive_Buff[i] = 0;}}}else{state = 0;for (i = 0; i < 6; i++){Bluetooth_Receive_Buff[i] = 0;}}
}/*** @brief 串口3接收中断* @param 无* @retval 无*/
void USART3_IRQHandler(void) // 串口2中断服务程序
{uint8_t ReceiveData;if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) // 接收中断(接收到的数据必须是0x0d 0x0a结尾){USART_ClearITPendingBit(USART3, USART_IT_RXNE); // 清除中断标志ReceiveData = USART_ReceiveData(USART3); // 接收的数据Bluetooth_Receive_Data(ReceiveData);Bluetooth_Data();// USART_SendData(USART3, ReceiveData);// 测试收发数据// if (ReceiveData == 58) // 当接收到0x3A后 接收数据灯亮 这个是基于最小系统板的测试程序// {// MY_GPIO_Init(GPIOC, GPIO_Pin_13, GPIO_Mode_Out_PP);// }}
}/********************************* 测试蓝牙接收数据 ****************************************************/// 在主函数中显示 但是要先引入usart3头文件 注意要在主函数中初始化 连线连接无错误// 在上位机中以定义协议格式发送 b3 b3 01 02 03 5b// 接收数据在OLED上显示 如发送数据和接收数据相同 则表示接收协议无错误// 下一步就是接收蓝牙主机的数据// // 显示串口3接收数据 这是蓝牙从机 接收数据
// OLED_ShowNum(3, 8, data1, 2); // 有效数据1
// OLED_ShowNum(3, 11, data2, 2); // 有效数据2
// OLED_ShowNum(3, 14, data3, 2); // 有效数据3/*********************************** 结束 *************************************************************/
7、转向方案
转向方案可有很多种了嘞
在经过实际测试后,我总结出来了主要的三种转向方案
- 开环转向
- 位置环速度环串级转向
- MPU6050转向
1、开环转向
就是电机IO,分别给0、1,然后给一个PWM,记录此时两轮的脉冲数相加的绝对值,当超过设定的脉冲时就停止
这时设定的脉冲,就可以是90°的脉冲和180度的脉冲,这需要自己一步一步的测试
我经过测试发现可行,并且还挺稳定的
下面给出相关代码
/*** @brief 转向 开环转向* @param 脉冲值;方向(左1 右2) pwm* @retval 无*/
void Car_turn(int pluse, int mode, int pwm)
{while (1){if (mode == 1) // 向左{Load_Motor_PWM(-pwm, pwm);}else if (mode == 2) // 向右{Load_Motor_PWM(pwm, -pwm);}if (pathLenth > pluse) // 达到预设角度{break;}}Load_Motor_PWM(0, 0); // 立马定住Motor_Left_DIR(STOP);Motor_Right_DIR(STOP);
}void TIM6_IRQHandler(void) // 10ms
{if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET){LED_RED = !LED_RED; // 测试程序是否卡死TIM_ClearITPendingBit(TIM6, TIM_IT_Update);a = -Read_Encoder(2);b = Read_Encoder(3);pathLenth += MyABS(a) + MyABS(b); // 累积脉冲数// rpm 330脉冲// speed1 = ((float)a * 60000.0) / 13200;// speed2 = ((float)b * 60000.0) / 13200;}
}
可以看出当小车当前脉冲到达自己设置的脉冲时,小车就停止,这个时候小车差速,即可到达期望角度
// Car_turn(2000, 1, 1000); // 开环转弯 左转90
// Car_turn(2000, 2, 1000); // 开环转弯 右转90
// Car_turn(4000, 1, 1000); // 掉头180
2、位置环速度环闭环串级转向
位置环为外环,速度环为内环,位置环的输出即是速度环的输入
这个时候小车旋转的角度就是以小车两轮为直径的圆的四分之一的距离,这个距离如何计算呢
小车转一圈的脉冲我们知道,假定1040个脉冲
那么当前行进的脉冲数/小车转一圈的脉冲数,我们就是不是就知道了小车转了几圈,然后把这个×小车转一圈的周长,就知道了小车行进的距离
把小车行进距离转换为脉冲带入位置环,得到输出后赋值给速度环即可,使小车转90°的距离恒定,掉头的距离也恒定,转向就完成了
这部分代码有些多,我在文末会贴出代码,大家可以自行查看
3、MPU6050转向
通过yaw角的反馈,来改变小车的旋转方向,yaw角为90°时即转向90°,yaw角为180°时即掉头
这个也是串起来的PID,角度环的输出是速度环的输入
调节好PID参数后即可丝滑转向
/*** @brief 角度环pid输出函数* @param actual_val:实际值 6050yaw* @note 无* @retval 通过PID计算后的输出*/
float Angle_pid_realize(_pid *pid, float actual_val)
{/* 计算偏差 这里的偏差是指 巡线偏差 设定的巡线期望值 和 MV传回的巡线实际值 得偏差 */pid->err = pid->target_val - actual_val;if (pid->err > 180) // 防止小车转到180度时一直旋转的问题pid->err = pid->err - 360;if (pid->err < -180)pid->err = pid->err + 360;pid->integral += pid->err; // 误差累积// if (pid->err >= 1000) // 积分限幅// {// pid->err = 0;// }// if (huidu.output >= 550)// huidu.output = 550;// if (huidu.output <= -600)// huidu.output = -600;/*PID算法实现*/pid->actual_val = pid->Kp * pid->err + pid->Ki * pid->integral + pid->Kd * (pid->err - pid->err_last);/*误差传递*/pid->err_last = pid->err;/*返回当前实际值*/return pid->actual_val;
}/*** @brief 角度环pid输出函数* @param actual_val:无* @note 无* @retval 通过PID计算后的输出*/
float Angle_pid_control(void)
{float Expect_Pwm = 0.0; // 当前控制值// pid_speed1.actual_val = ((float)Param.UnitTime_Motor1Pluse * 1000.0 * 60.0) / (RESOULTION_TOTAL_RATIO * REDUCTION_RATIO * PID_PERIOD);// Pid_speed2 = ((float)Param.UnitTime_Motor2Pluse * 60000.0) / 17680;Pid_Actual_angle = KLM(yaw); // 实际值 为yaw 滤波后的数据Expect_Pwm = Angle_pid_realize(&pid_angle, Pid_Actual_angle); // 进行 PID 计算// #if defined(PID_ASSISTANT_EN)// set_computer_value(SEND_FACT_CMD, CURVES_CH1, &actual_speed, 1); // 给通道 1 发送实际值// #endifreturn Expect_Pwm;
}
二、调试经验分享
大家在实际做题的时候肯定会出现非常多的问题,不要慌,慢慢来,分析造成这种问题的原因是什么,从现象出发,再回到代码
等调出想要的代码的实际效果时,那一刻就会感觉之前的努力都值了
关于这道题,主要调试的有以下几部分
1、循迹
这个循迹,只要偏差值没错,补偿值两轮,一正一负,后面就是调节PID的问题了
2、识别数字
这个也是关键,如何准确识别数字,然后小车根据MV发过来的数据进行运动
识别数字的准确率也要有相应的保证,小车一切行进的基础都是在准确识别到数字的基础上的
3、转向
在调试的时候,多次发现小车不能完全转向90度,造成小车循迹出线,压黑线等
这个时候,要检查一下小车的硬件结构是否合理,程序是不是哪个地方写错了等
4、双车通信
通信部分,我建议的是,首先在上位机上模拟OpenMv或者蓝牙主机,发送定义的数据包协议,将接收到的数据在OLED上进行显示,如果接收到正确的数据,即可证明通信无问题,再去排除其他问题
5、逻辑处理
其实,在掌握了以上知识点后,我觉得逻辑还是很重要的,由自己亲身经历过,就是你知道如何实现单个功能,但是融合起来后就完全不行了,在比赛过程中是很浪费时间的,会造成时间的大量浪费,再加上身体的高强度运作和心态,就悲剧了
千万要在平时加强对程序逻辑的判断和处理,作者本人亲身经历,不要学我
比如这道题目,我首先是在OpenMv识别数字后,放上药品才可以小车行进去指定的病房送药,一二号病房没有太大难度,写死即可,后面的病房要根据OpenMv二次判断,来进行更正进病房,并要求返回药房。
这个逻辑就很重要,识别到Mv就返回一个标志位,左边为0x3A,右边即为0x3B等。发挥部分,从车等待主车卸载药品后取药,这个时候是主车卸载完药品后才给从车发行进标志,从车才可以动,防止撞车等
6、心态问题
不要被一种方案限制住了,比赛吗,有无限可能的,发挥不同的思路和方法,只要能实现就是好方法
我已经给大家以身试法过了,这次参加的电赛,由于没有车,只能做E题,赛前玩了玩二维云台追踪小球,大部分心思还是压在了车上,而这道题目比赛完后,再次复盘回想起这道题,是自己的思维局限把自己限定死了,导致越调越不行,前两天,想着闭环跑,可惜没有实现,后面自己稀里糊涂的实现了闭环,但是速度不可控,还是会超出黑线,误差很大,导致每分,自己也很急,就这样,第一次电赛也是最后一次就结束了
总归来说还是心态和实力,想的太多,每次力争最优解
电赛还是很考验人的,虽说可能结果不会怎么样,但是我觉得在准备电赛得过程中还是很棒得,一起每天早起得队友,大家互相配合,完成题目得喜悦,一起解决问题得思考,还是很有意义的。
总结
希望大家吸取教训,大家有什么不懂得问题也可以在评论区留言,看到了得话就肯定会恢复给大家解答,希望自己得绵薄之力可以帮助大家
大家一定要不断的加强训练,对学习的东西进行一个总结和汇总,加强控制题目的训练,而不是仅仅做小车,小车是一个载体,其内部原理也是控制的精细程度
开源链接
我会在这两天将自己这个开源链接的代码进行一个讲解
我采用了不同的主控,不同的巡线方案、大家可以自行访问,进行下载
下方为gitee开源链接,请大家点一个star,谢谢
oufen / 2021年电赛F题-智能送药小车
相关文章:

分享21年电赛F题-智能送药小车-做题记录以及经验分享
这里写目录标题 前言一、赛题分析1、车型选择2、巡线1、OpenMv循迹2、灰度循迹 3、装载药品4、识别数字5、LED指示6、双车通信7、转向方案1、开环转向2、位置环速度环闭环串级转向3、MPU6050转向 二、调试经验分享1、循迹2、识别数字3、转向4、双车通信5、逻辑处理6、心态问题 …...

字符串统计-C语言/Java
描述 计算字符串中含有的不同字符的个数。字符在 ASCII 码范围内( 0~127 ,包括 0 和 127 ),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次。数据范围: 1≤n≤500 例如,对于字符串 ab…...

Styled-components,另一种css in js的方案
介绍 Styled-components是一种流行的CSS-in-JS库,它为React和React Native应用程序提供了一种优雅的方式来管理组件的样式。它的设计理念是将CSS样式与组件逻辑紧密绑定在一起,从而使样式在组件层级中作用更加清晰和可维护 使用 安装Styled-components…...

nginx部署以及反向代理多域名实现HTTPS访问
nginx部署以及反向代理多域名实现 1.nginx部署 1.1 编写nginx部署文件 docker-compose.yml version: 3 services: nginx:restart: always image: nginx:1.20container_name: nginx-mainports:- 80:80- 443:443volumes: # 基础配置- /opt/nginx_main/nginx-info/nginx.conf:/…...

24届近5年东华大学自动化考研院校分析
今天给大家带来的是东华大学控制考研分析 满满干货~还不快快点赞收藏 一、东华大学 学校简介 东华大学(Donghua University),地处上海市,是教育部直属全国重点大学,国家“双一流”、“211工程”建设高校…...

nacos伪集群启动成功,但是服务注册不上的问题
项目场景: nacos 伪集群启动成功,但是服务未注册上的问题: 问题描述 在学习nacos中,我买了一台阿里云服务器,在其上部署了nginx及三个nacos 端口分别是 8848 8868 8888 我按照正常的流程 解压nacos修改application.p…...

tidevice+appium在windows系统实施iOS自动化
之前使用iOS手机做UI自动化都是在Mac电脑上进行的,但是比较麻烦,后来看到由阿里开源的tidevice工具可以实现在windows上启动WDA,就准备试一下,记录一下过程。 tidevice的具体介绍可以参考一下这篇文章:tidevice 开源&…...

面试热题(LRU缓存)
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 …...

微信小程序开发【从0到1~入门篇】2023.08
一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下: 文件必须作用app.js是小程序逻辑app.json是小程序公告配置app.wxss否小程序公告样式表 3. 小程序项目结构 一个小程序页面由四个文件组成,分别是: 文…...

P1398 [NOI2013] 书法家
题目描述 输入 #1 3 13 1 1 -1 -1 1 -1 1 1 1 -1 1 1 1 1 -1 1 -1 1 -1 1 -1 1 -1 -1 1 -1 1 -1 -1 1 1 -1 1 1 1 -1 1 1 1 输出 #1 24 输入 #2 3 13 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1…...

【构建卷积神经网络】
构建卷积神经网络 卷积网络中的输入和层与传统神经网络有些区别,需重新设计,训练模块基本一致 全连接层:batch784,各个像素点之间都是没有联系的。 卷积层:batch12828,各个像素点之间是有联系的。 impor…...

SSH 认证原理
SSH协议登录服务器: $ ssh userhost 主要有两种登录方式:第一种为密码口令登录,第二种为公钥登录 密码口令登录 通过密码进行登录,主要流程为: 1、客户端连接上服务器之后,服务器把自己的公钥传给客户端…...

基于DETR (DEtection TRansformer)开发构建MSTAR雷达影像目标检测系统
关于DETR相关的实践在之前的文章中很详细地介绍过,感兴趣的话可以自行移步阅读即可: 《DETR (DEtection TRansformer)基于自建数据集开发构建目标检测模型超详细教程》 《书接上文——DETR评估可视化》 基于MSTAR雷达影像数据开发构建目标检测系统&am…...

Java分布式微服务1——注册中心(Eureka/Nacos)
文章目录 基础知识注册中心Eureka注册中心与Ribbon负载均衡1、Eureka注册中心2、Eureka的搭建3、Eureka服务注册4、复制服务实例5、拉取服务6、Ribbon负载均衡的流程及Eureka规则调整:7、Ribbon负载均衡饥饿加载 Nacos注册中心1、服务端Nacos安装与启动2、客户端Nac…...

(文章复现)建筑集成光储系统规划运行综合优化方法matlab代码
参考文献: [1]陈柯蒙,肖曦,田培根等.一种建筑集成光储系统规划运行综合优化方法[J].中国电机工程学报,2023,43(13):5001-5012. 1.基本原理 本文建立的双层耦合模型内、外层分别对应求解容量配置与能量调度问题。外层模型设置光伏与储能容量备选集并将容量配置组合…...

【Redis】——RDB快照
Redis 是内存数据库,但是它为数据的持久化提供了两个技术,一个是AOF日志,另一个是RDB快照: AOF 文件的内容是操作命令;RDB 文件的内容是二进制数据。 RDB 快照就是记录某一个瞬间的内存数据,记录的是实际…...

微服务监控技术skywalking的部署与使用(亲测无坑)
微服务监控技术skywalking的部署与使用 1. 前期准备2. skywalking安装部署2.1 Java Agent2.2 apache/skywalking-oap-server2.3 apache/skywalking-ui 3. 项目启动4.效果展示 1. 前期准备 注:本篇文章采用docker部署,采用8.2.0版本,版本一定…...

DLA 神经网络的极限训练方法:gradient checkpointing
gradient checkpointing 一般来说,训练的过程需要保存中间结果(不管是GPU还是CPU)。前向传播根据输入(bottom_data)计算输出(top_data),后向传播由top_diff计算bottom_diff(如果某个变量打开梯度进行训练的话ÿ…...

python excel 操作
excel文件内容如下: 一、xlrd 读Excel 操作 1、打开Excel文件读取数据 filexlrd.open_workbook(filename)#文件名以及路径,如果路径或者文件名有中文给前面加一个 r 2、常用函数 (1)获取一个sheet工作表 table file.sheets(…...

记一次Linux启动Mysql异常解决
文章目录 第一步: netstat -ntlp 查看端口情况2、启动Mysql3、查看MySQL日志 tail -100f /var/log/mysqld.log4、查看磁盘占用情况:df -h5、思路小结 第一步: netstat -ntlp 查看端口情况 并没有发现3306数据库端口 2、启动Mysql service …...

ATFX汇市:美联储年内或仍将加息依次,美指向下空间不大
环球汇市行情摘要—— 昨日,美元指数上涨0.08%,收盘在102.08点, 欧元贬值0.07%,收盘价1.1003点; 日元贬值0.51%,收盘价142.47点; 英镑升值0.28%,收盘价1.2784点; 瑞…...

【博客687】k8s informer的list-watch机制剖析
k8s informer的list-watch机制剖析 1、list-watch场景: client-go中的reflector模块首先会list apiserver获取某个资源的全量信息,然后根据list到的rv来watch资源的增量信息。希望使用client-go编写的控制器组件在与apiserver发生连接异常时,…...

用Python获取链家二手房房源数据,做可视化图分析数据
前言 数据采集的步骤是固定: 发送请求, 模拟浏览器对于url地址发送请求获取数据, 获取网页数据内容 --> 请求那个链接地址, 返回服务器响应数据解析数据, 提取我们需要的数据内容保存数据, 保存本地文件 所需模块 win R 输入cmd 输入安装命令 pip install 模块名 (如果你…...

Yield Guild Games:社区更新 — 2023 年第二季度
本文重点介绍了 Yield Guild Games (YGG) 2023 年第二季度社区更新中涵盖的关键主题,包括公会发展计划 (GAP) 第 3 季的总结、YGG 领导团队的新成员以及 YGG 的最新消息地区公会网络和广泛的游戏合作伙伴生态系统。 在 YGG 品牌焕然一新的基础上,第二季…...

Stable Diffusion - 运动服 (Gymwear Leggings) 风格服装与背景的 LoRA 配置
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/132179050 测试模型:DreamShaper 8 运动裤 (Gymwear Leggings) 是紧身的裤子,通常用于健身、瑜伽、跑步等运动。运动裤的…...

js-7:javascript原型、原型链及其特点
1、原型 JavaScript常被描述为一种基于原型的语言-每个对象拥有一个原型对象。 当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字…...

无涯教程-Perl - continue 语句函数
可以在 while 和 foreach 循环中使用continue语句。 continue - 语法 带有 while 循环的 continue 语句的语法如下- while(condition) {statement(s); } continue {statement(s); } 具有 foreach 循环的 continue 语句的语法如下- foreach $a (listA) {statement(s); } co…...

【贪心算法】leetcode刷题
贪心算法无固定套路。 核心思想:先找局部最优,再扩展到全局最优。 455.分发饼干 两种思路: 1、从大到小。局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。先遍历的胃口&a…...

PyMySQL库版本引起的python执行sql编码错误
前言 长话短说,之前在A主机(centos7.9)上运行的py脚本拿到B主机上(centos7.9)运行报错: UnicodeEncodeError: latin-1 codec cant encode characters in position 265-266: ordinal not in range(256)两个…...

第二章-算法
第二章-算法 数据结构和算法的关系 算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。 算法的特性 算法有五个基本特征:输入、输出、有穷性、确定性和可行性。 输入:算法具…...