电机应用-直流有刷电机

目录

直流有刷电机

工作原理

直流有刷减速电机的重要参数

电路原理与分析

驱动芯片分析

L298N驱动芯片

直流有刷减速电机控制实现

控制速度原理

硬件设计

L298N

野火直流有刷电机驱动板-MOS管搭建板

软件设计1:两个直流有刷减速电机按键控制

开发设计

定时器配置

测试环节

直流有刷减速电机驱动板电流电压采集

ADC配置

测试环节

直流有刷减速电机驱动板限电流、过电压、欠电压保护

ADC配置

测试环节


直流有刷电机

直流有刷电机具有结构简单、易于控制、成本低等特点。

基本的直流有刷电机在电源和电机间只需要两根电缆,可以节省配线和连接器所需的空间,并降低电缆和连接器的成本。

还可以使用MOSFET/IGBT开关对直流有刷电机进行控制,给电机提供足够好的性能,并且整个电机控制系统也会比较便宜。

直流有刷电机转速快、扭矩小,在某些应用中可能无法满足要求。直流有刷减速电机可以降低转速并提高力矩

工作原理

直流有刷电机在其电枢(转子)上绕有大量的线圈,所产生强大的磁场与外部磁场相互作用产生旋转运动。

电源通过电刷向线框供电,线框就有电流通过,在线框两侧放一对磁极NS形成磁场,磁力线由N到S。

线框有电流时,线框就会收到磁场的作用力,按照左手定则,红色线框受到力F1,蓝色线框受到力F2,F1和F2力的方向相反,使得线框会转动。

当线框转到90°时,换向器改变了线框电流的方向,产生的安培力方向不变,于是线框会连续旋转。

直流有刷减速电机的重要参数

空载转速:正常工作电压下电机不带任何负载的转速(单位为r/min,即转/分)。空载转速由于没有反向力矩,所以输出功率和堵转情况不一样,该参数只是提供一个电机在规定电压下最大转速的参考。

空载电流:正常工作电压下电机不带任何负载的工作电流(单位为mA)。电机越好,该值越小。

负载转速:正常工作电压下电机带负载的转速。

负载力矩:正常工作电压下电机带负载的力矩(单位为N·m,即牛·米)。

负载电流:电机拖动负载时实际检测到的定子电流数值。

堵转力矩:在电机受反向外力使其停止转动时的力矩。如果电机堵转现象经常出现,则会损坏电机或烧坏电机驱动芯片。所以选电机时,除了考虑转速还要考虑堵转。堵转时间一长,电机温度上升的很快,这个值也会下降的很厉害。

堵转电流:在电机受反向外力使其停止转动时的电流。此时电流非常大,稍微就可能会烧毁电机,在实际使用时应尽量避免。

减速比:没有减速齿轮组时转速和有减速齿轮组时转速之比。

功率:一般为额定功率(单位W,即瓦),即在额定电压下能够长期正常运转的最大功率,也是指电动机在制造厂所规定的额定情况下运行时其输出端的机械功率。

电路原理与分析

当拥有一个直流电机和一节电池,只要把电机的两根电源线和电池的电源线连接在一起时,电机就可以正常旋转。反接时电机就反向旋转。但实际单片机一般是用H桥电路来驱动电机。

如下图:H桥电机驱动电路包括4个三极管和一个电机。要想电机运转就必须导通对角线上的一对三极管,所以电流可能会从左到右或从右到左流过电机,从而控制电机转向。

当同一侧的Q1和Q2导通时,电流将从电源经过Q1和Q2,然后直接流到电源负极,这个回路中除了三极管外没有经过负载(电机),这时电流可能会达到最大值而造成烧毁三极管。当同一侧的Q3和Q4导通时也一样。于是可以改进电路原理图。

改进后的电路增加了4个与门和2个非门,以及Q1和Q3换成了NPN三极管。这样的组合可以实现一个信号控制两个同一侧的三极管,并且可以保证在同一侧的两个三极管不会同时导通,即在同一时刻只有一个三极管是导通的。

ENABLE脚接入高电平,IN1脚接入高电平,AND1_2脚是低电平,所以AND1_3脚是低电平,所以Q1截止。而AND2_1脚和AND2_2脚都是高电平,所以ADN2_3脚是高电平,所以Q2导通。然后IN2脚接入低电平,AND4_2脚是高电平,且AND4_1是高电平,所以AND4_3脚是高电平,所以Q3导通。而AND3_1脚是高电平,AND3_2脚是低电平,所以AND3_3脚是低电平,所以Q4截止。故电机逆时针转动。

ENABLE脚接入高电平,IN1脚接入低电平,AND1_2脚是高电平,所以AND1_3脚是高电平,所以Q1导通。而AND2_1脚是高电平,AND2_2脚是低电平,所以ADN2_3脚是低电平,所以Q2截止。然后IN2脚接入高电平,AND4_2脚是低电平,AND4_1是高电平,所以AND4_3脚是低电平,所以Q3截止。而AND3_1脚是高电平,AND3_2脚是高电平,所以AND3_3脚是高电平,所以Q4导通。故电机顺时针转动。

当ENABLE脚接入高电平,IN1和IN2都接入同一电平(高电平或低电平)都只会同时导通上面或下面的两个三极管,不会出现同一侧的三极管同时导通的情况。此时电机停止,当然,ENABLE脚接入低电平时不管IN1、IN2怎样电平,都停止电机。

驱动芯片分析

通常在驱动电机时会选择集成H桥的IC,因为H桥使用分立元件搭建比较麻烦,增加了硬件设计难度。

当我们选择集成IC时,需要考虑集成IC是否能满足电机的驱动电压要求,是否能承受电机工作时的电流等情况。

如果集成IC无法满足功率要求时还是需要自己使用MOS管、三极管等元件搭建H桥电路,这样的分立元件搭建的H桥一般驱动能力也会比集成IC要高。

L298N驱动芯片

L298N是ST公司的产品,内部包含4通道逻辑驱动电路,是一种二相和四相电机的专门驱动芯片,即内含两个H桥的高电压大电流双桥式驱动器,接收标准的TTL逻辑电平信号,可驱动4.5V~46V、2A以下的电机,电流峰值输出可达3A。

原理和刚刚的电路原理分析一致。

直流有刷减速电机控制实现

控制速度原理

PWM通过一定的频率来改变通电和断电的时间,从而控制电路输出功率,在电机的控制周期中,通电时间决定了它的转速。

占空比 = 通电时间 / (通电时间+断电时间),即高电平占整个周期的百分比。

假如T1为高电平时间,T2为低电平时间,T为周期,D为占空比,则D = T1 / T。设电机速度为V,最大速度为Vmax,则V = Vmax * D。当D的大小改变时,速度V也会改变,所以只要改变占空比就能达到控制电机的速度。

硬件设计

主控有刷电机接口如上图,有刷电机接口和无刷电机接口都使用同一个接口。本实验只用到了TIM1_CH1和TIM1_CH2,即PA8和PA9来输出PWM信号控制电机,需注意主控板需要和电机驱动板共地。

L298N

驱动板可以支持12~46V的宽电压供电,并且带输入电压转5V的电压芯片,所以驱动板只需一个电源输入,具体需要多大电压需要根据电机来选择。

ENABLEA和ENABLEB都是使能输入脚,ENABLEA用于控制A桥,ENABLEB用于控制B桥,可以接到单片机的引脚进行电平控制,也可以直接使用跳帽接入5V。

INPUT1和INPUT2是A桥的控制信号,INPUT3和INPUT4是B桥的控制信号,可以接PWM控制电机。

OUTPUT1和OUTPUT2是A桥的输出信号,OUTPUT3和OUTPUT4是B桥的输出信号。

两路电机接口的8个二极管用于防止电机的反电动势损坏L298N。

当E点反电动势为正,超过电源+0.7V时,上端二极管导通,因此输出线就被限位在电源电压+0.7V上,不会超过这个数值。

当E点反电动势为负,低于电源-0.7V时,下端二极管导通,因此输出线就被限位在电源电压-0.7V上,不会低于这个数值。

野火直流有刷电机驱动板-MOS管搭建板

野火直流有刷电机驱动板是使用MOS管搭建的大功率H桥电机驱动板。驱动板可支持12V~70V的宽电压输入,10A过电流保护电路(超过10A可自动禁用电机控制信号),最高功率支持700W。实际使用输入电压需要根据电机进行选择,同时还具有电流采样电路、编码器接口和电源电压检测电路等。

野火使用MOS管搭建的直流有刷电机驱动板做到了信号完全隔离,其它驱动板基本都只是使用光耦隔离了控制信号,并没有对ADC采样电路进行隔离。野火不仅使用光耦对控制信号进行了隔离,还使用AMC1200SDUBR隔离运放对ADC采样电路进行了隔离。

PWM控制信号使用TLP2362高速光耦进行了隔离,SD控制信号使用EL357N光耦进行了隔离。如下图。

下图是使用MOS管搭建的H桥电路,使用两个EG2104驱动四个MOS管。

EG2104S主要功能有逻辑信号输入处理、死区时间控制、电平转换功能、悬浮自举电源结构和上下桥图腾柱式输出。逻辑信号输入端高电平阈值为2.5V以上,低电平阈值为1.0V以下,要求逻辑信号的输出电流小,可以使MCU输出逻辑信号直接连接到EG2104S的输入通道上。EG2104S芯片有一个SHUTDOWN引脚,逻辑输入控制信号低电平有效,强行控制下功率管LO、上功率管HO输出低电平,这样可以直接使用这个引脚做软件控制电机的旋转和停止,还可以实现硬件的限流和保护。

EG2104S内部集成了死区时间控制电路,死区时间波形如下图,其中死区时间DT的典型值为640ns。EG2104S采用自举悬浮驱动电源结构大大简化了驱动电源设计,只用一路电源电压VCC即可完成高端N沟道MOS管和低端N沟道MOS管两个功率开关器件的驱动,给实际应用带来了极大的方便。EG2104S自举电路结构也如下图。RG2104S可以使用外接一个自举二极管和一个自举电容自动完成自举升压功能,假如在下管开通、上管关断期间VC自举电容已充到足够的电压(Vc=VCC),当HO输出高电平时上管开通、下管关断时,VC自举电容上的电压将等效一个电压源作为内部驱动器VB和VS的电源,完成高端N沟道MOS管的驱动。

软件设计1:两个直流有刷减速电机按键控制

以STM32F4为例。

开发设计

按键1:电机1速度加(总10个级别)。

按键2:电机1速度减(总10个级别)。

按键3:电机2速度加(总10个级别)。

按键4:电机2速度减(总10个级别)。

按键5:电机1、电机2同向且都转化方向。

两电机开始状态为停止。

定时器配置

TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim8;void MX_TIM1_Init(void)
{TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};htim1.Instance 					= TIM1;htim1.Init.Prescaler 			= 1;htim1.Init.CounterMode 			= TIM_COUNTERMODE_UP;htim1.Init.Period 				= 5599;htim1.Init.ClockDivision 		= TIM_CLOCKDIVISION_DIV1;htim1.Init.RepetitionCounter 	= 0;htim1.Init.AutoReloadPreload 	= TIM_AUTORELOAD_PRELOAD_ENABLE;if (HAL_TIM_Base_Init(&htim1) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_PWM_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();}sConfigOC.OCMode 		= TIM_OCMODE_PWM1;sConfigOC.Pulse 		= 0;sConfigOC.OCPolarity 	= TIM_OCPOLARITY_HIGH;sConfigOC.OCNPolarity 	= TIM_OCNPOLARITY_HIGH;sConfigOC.OCFastMode 	= TIM_OCFAST_DISABLE;sConfigOC.OCIdleState 	= TIM_OCIDLESTATE_SET;sConfigOC.OCNIdleState 	= TIM_OCNIDLESTATE_RESET;if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)	// 配置PWM通道{Error_Handler();}if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)	// 配置PWM通道{Error_Handler();}sBreakDeadTimeConfig.OffStateRunMode 	= TIM_OSSR_DISABLE;sBreakDeadTimeConfig.OffStateIDLEMode 	= TIM_OSSI_DISABLE;sBreakDeadTimeConfig.LockLevel 			= TIM_LOCKLEVEL_OFF;sBreakDeadTimeConfig.DeadTime 			= 0;sBreakDeadTimeConfig.BreakState 		= TIM_BREAK_DISABLE;sBreakDeadTimeConfig.BreakPolarity 		= TIM_BREAKPOLARITY_HIGH;sBreakDeadTimeConfig.AutomaticOutput 	= TIM_AUTOMATICOUTPUT_DISABLE;if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK){Error_Handler();}HAL_TIM_MspPostInit(&htim1);/*开始输出PWM*/HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
}void MX_TIM8_Init(void)
{TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};htim8.Instance 					= TIM8;htim8.Init.Prescaler 			= 1;htim8.Init.CounterMode 			= TIM_COUNTERMODE_UP;htim8.Init.Period 				= 5599;htim8.Init.ClockDivision 		= TIM_CLOCKDIVISION_DIV1;htim8.Init.RepetitionCounter 	= 0;htim8.Init.AutoReloadPreload 	= TIM_AUTORELOAD_PRELOAD_ENABLE;if (HAL_TIM_Base_Init(&htim8) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK){Error_Handler();}if (HAL_TIM_PWM_Init(&htim8) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger 	= TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode 		= TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK){Error_Handler();}sConfigOC.OCMode 		= TIM_OCMODE_PWM1;sConfigOC.Pulse 		= 0;sConfigOC.OCPolarity 	= TIM_OCPOLARITY_HIGH;sConfigOC.OCNPolarity 	= TIM_OCNPOLARITY_HIGH;sConfigOC.OCFastMode 	= TIM_OCFAST_DISABLE;sConfigOC.OCIdleState 	= TIM_OCIDLESTATE_SET;sConfigOC.OCNIdleState 	= TIM_OCNIDLESTATE_RESET;if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)	// 配置PWM通道{Error_Handler();}if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)	// 配置PWM通道{Error_Handler();}sBreakDeadTimeConfig.OffStateRunMode 	= TIM_OSSR_DISABLE;sBreakDeadTimeConfig.OffStateIDLEMode 	= TIM_OSSI_DISABLE;sBreakDeadTimeConfig.LockLevel 			= TIM_LOCKLEVEL_OFF;sBreakDeadTimeConfig.DeadTime 			= 0;sBreakDeadTimeConfig.BreakState 		= TIM_BREAK_DISABLE;sBreakDeadTimeConfig.BreakPolarity 		= TIM_BREAKPOLARITY_HIGH;sBreakDeadTimeConfig.AutomaticOutput 	= TIM_AUTOMATICOUTPUT_DISABLE;if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK){Error_Handler();}HAL_TIM_MspPostInit(&htim8);/*开始输出PWM*/HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_2);
}void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *tim_baseHandle)
{if (tim_baseHandle->Instance == TIM1){__HAL_RCC_TIM1_CLK_ENABLE();}else if (tim_baseHandle->Instance == TIM8){__HAL_RCC_TIM8_CLK_ENABLE();}
}void HAL_TIM_MspPostInit(TIM_HandleTypeDef *timHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if (timHandle->Instance == TIM1){__HAL_RCC_GPIOE_CLK_ENABLE();/**TIM1 GPIO ConfigurationPE9     ------> TIM1_CH1PE11     ------> TIM1_CH2*/GPIO_InitStruct.Pin 		= GPIO_PIN_9 | GPIO_PIN_11;GPIO_InitStruct.Mode 		= GPIO_MODE_AF_PP;GPIO_InitStruct.Pull 		= GPIO_NOPULL;GPIO_InitStruct.Speed 		= GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate 	= GPIO_AF1_TIM1;HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);}else if (timHandle->Instance == TIM8){__HAL_RCC_GPIOC_CLK_ENABLE();/**TIM8 GPIO ConfigurationPC6     ------> TIM8_CH1PC7     ------> TIM8_CH2*/GPIO_InitStruct.Pin 		= GPIO_PIN_6 | GPIO_PIN_7;GPIO_InitStruct.Mode 		= GPIO_MODE_AF_PP;GPIO_InitStruct.Pull 		= GPIO_NOPULL;GPIO_InitStruct.Speed 		= GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate 	= GPIO_AF3_TIM8;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);}
}void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *tim_baseHandle)
{if (tim_baseHandle->Instance == TIM1){__HAL_RCC_TIM1_CLK_DISABLE();}else if (tim_baseHandle->Instance == TIM8){__HAL_RCC_TIM8_CLK_DISABLE();}
}

测试环节
/*** @brief  设置TIM通道的占空比* @param  channel		通道	(1,2)* @param  compare		占空比*	@note 	无* @retval 无*/
void TIM_SetPWM_pulse(TIM_HandleTypeDef *TIM_TimeStructure, uint32_t channel, int compare)
{switch (channel){case TIM_CHANNEL_1:__HAL_TIM_SET_COMPARE(TIM_TimeStructure, TIM_CHANNEL_1, compare);break;case TIM_CHANNEL_2:__HAL_TIM_SET_COMPARE(TIM_TimeStructure, TIM_CHANNEL_2, compare);break;}
}void motor_init(void)
{GPIO_InitTypeDef GPIO_InitStruct;__GPIOG_CLK_ENABLE();__GPIOE_CLK_ENABLE();// ENA--PG12GPIO_InitStruct.Pin 	= GPIO_PIN_12;GPIO_InitStruct.Mode 	= GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Speed 	= GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);// ENB--PE6GPIO_InitStruct.Pin = GPIO_PIN_6;HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}/*** @brief  设置电机速度* @param  motor: 电机选择(1、2)* @param  speed: 速度(占空比)* @retval 无*/
void set_motor_speed(uint8_t motor, uint16_t speed)
{if(motor == 1){dutyfactor = speed;if (direction == MOTOR_FWD){TIM_SetPWM_pulse(&htim1, TIM_CHANNEL_1, dutyfactor);	// 设置比较寄存器的值}	else	{	TIM_SetPWM_pulse(&htim1, TIM_CHANNEL_2, dutyfactor);	// 设置比较寄存器的值}}else{dutyfactor2 = speed;if (direction == MOTOR_FWD){TIM_SetPWM_pulse(&htim8, TIM_CHANNEL_1, dutyfactor);	// 设置比较寄存器的值}	else	{	TIM_SetPWM_pulse(&htim8, TIM_CHANNEL_2, dutyfactor);	// 设置比较寄存器的值}}
}/*** @brief  设置电机方向* @param  motor: 电机选择(1、2)* @param  motor: 方向选择(MOTOR_FWD、MOTOR_REV)* @retval 无*/
void set_motor_direction(uint8_t motor, motor_dir_t dir)
{if(motor == 1){direction = dir;if (direction == MOTOR_FWD){TIM_SetPWM_pulse(&htim1, TIM_CHANNEL_1, dutyfactor);	// 设置比较寄存器的值TIM_SetPWM_pulse(&htim1, TIM_CHANNEL_2, 0);				// 设置比较寄存器的值}else{TIM_SetPWM_pulse(&htim1, TIM_CHANNEL_1, 0);				// 设置比较寄存器的值TIM_SetPWM_pulse(&htim1, TIM_CHANNEL_2, dutyfactor);	// 设置比较寄存器的值}}else{direction2 = dir;if (direction2 == MOTOR_FWD){TIM_SetPWM_pulse(&htim8, TIM_CHANNEL_1, dutyfactor);	// 设置比较寄存器的值TIM_SetPWM_pulse(&htim8, TIM_CHANNEL_2, 0);			// 设置比较寄存器的值}else{TIM_SetPWM_pulse(&htim8, TIM_CHANNEL_1, 0);			// 设置比较寄存器的值TIM_SetPWM_pulse(&htim8, TIM_CHANNEL_2, dutyfactor);	// 设置比较寄存器的值}}
}/*** @brief  使能电机* @param  motor: 电机选择(1、2)* @retval 无*/
void set_motor_enable(uint8_t motor)
{if(motor == 1){HAL_GPIO_WritePin(ENA_GPIO_PORT, ENA_PIN, GPIO_PIN_SET);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);    // 使能 PWM 通道 1HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);    // 使能 PWM 通道 2}else{HAL_GPIO_WritePin(ENB_GPIO_PORT, ENB_PIN, GPIO_PIN_SET);HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);   // 使能 PWM 通道 1HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_2);   // 使能 PWM 通道 2}
}/*** @brief  禁用电机* @param  motor: 电机选择(1、2)* @retval 无*/
void set_motor_disable(uint8_t motor)
{if(motor == 1){HAL_GPIO_WritePin(ENA_GPIO_PORT, ENA_PIN, GPIO_PIN_RESET);HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);    // 禁用 PWM 通道 1HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);    // 禁用 PWM 通道 2}else{HAL_GPIO_WritePin(ENB_GPIO_PORT, ENB_PIN, GPIO_PIN_RESET);HAL_TIM_PWM_Stop(&htim8, TIM_CHANNEL_1);   // 禁用 PWM 通道 1HAL_TIM_PWM_Stop(&htim8, TIM_CHANNEL_2);   // 禁用 PWM 通道 2}
}void test(void)
{__IO uint16_t ChannelPulse = 0;__IO uint16_t ChannelPulse2 = 0;uint8_t i = 0;初始化motor_init();set_motor_enable(1);				// 使能电机1set_motor_enable(2);				// 使能电机2set_motor_speed(1, ChannelPulse);	// 电机1开始状态为停止set_motor_speed(2, ChannelPulse2);	// 电机2开始状态为停止while (1){/* 扫描KEY1 */if (Key_Scan(KEY1_GPIO_PORT, KEY1_PIN) == KEY_ON){/* 加大占空比,即加快电机1的速度 */ChannelPulse += 5600 / 10;if (ChannelPulse > 5600){ChannelPulse = 5600;}set_motor_speed(1, ChannelPulse);}/* 扫描KEY2 */if (Key_Scan(KEY2_GPIO_PORT, KEY2_PIN) == KEY_ON){if (ChannelPulse < 5600 / 10){ChannelPulse = 0;}else{/* 减小占空比,即减满电机1的速度 */ChannelPulse -= 5600 / 10;}set_motor_speed(1, ChannelPulse);}/* 扫描KEY3 */if (Key_Scan(KEY3_GPIO_PORT, KEY3_PIN) == KEY_ON){/* 加大占空比,即加快电机2的速度 */ChannelPulse2 += 5600 / 10;if (ChannelPulse2 > 5600){ChannelPulse2 = 5600;}set_motor_speed(2, ChannelPulse2);}/* 扫描KEY4 */if (Key_Scan(KEY4_GPIO_PORT, KEY4_PIN) == KEY_ON){if (ChannelPulse2 < 5600 / 10){ChannelPulse2 = 0;}else{/* 减小占空比,即减满电机1的速度 */ChannelPulse2 -= 5600 / 10;}set_motor_speed(2, ChannelPulse2);}/* 扫描KEY5 */if (Key_Scan(KEY5_GPIO_PORT, KEY5_PIN) == KEY_ON){/* 转换方向(两电机同向) */set_motor_direction(1, (++i % 2) ? MOTOR_FWD : MOTOR_REV);set_motor_direction(2, (i % 2) ? MOTOR_FWD : MOTOR_REV);}}
}

直流有刷减速电机驱动板电流电压采集

ADC配置

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;void MX_ADC1_Init(void)
{ADC_ChannelConfTypeDef sConfig = {0};/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)*/hadc1.Instance 						= ADC1;hadc1.Init.ClockPrescaler 			= ADC_CLOCK_SYNC_PCLK_DIV4;hadc1.Init.Resolution 				= ADC_RESOLUTION_12B;hadc1.Init.ScanConvMode 			= ENABLE;hadc1.Init.ContinuousConvMode 		= ENABLE;hadc1.Init.DiscontinuousConvMode 	= DISABLE;hadc1.Init.ExternalTrigConvEdge 	= ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.ExternalTrigConv 		= ADC_SOFTWARE_START;hadc1.Init.DataAlign 				= ADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion 			= 2;hadc1.Init.DMAContinuousRequests 	= ENABLE;hadc1.Init.EOCSelection 			= ADC_EOC_SINGLE_CONV;if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.*/sConfig.Channel 		= ADC_CHANNEL_9;sConfig.Rank 			= 1;sConfig.SamplingTime 	= ADC_SAMPLETIME_3CYCLES;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.*/sConfig.Channel 		= ADC_CHANNEL_8;sConfig.Rank 			= 2;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}
}void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if (adcHandle->Instance == ADC1){__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/**ADC1 GPIO ConfigurationPB0     ------> ADC1_IN8PB1     ------> ADC1_IN9*/GPIO_InitStruct.Pin 	= GPIO_PIN_0 | GPIO_PIN_1;GPIO_InitStruct.Mode 	= GPIO_MODE_ANALOG;GPIO_InitStruct.Pull 	= GPIO_NOPULL;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* ADC1 DMA Init *//* ADC1 Init */hdma_adc1.Instance 					= DMA2_Stream0;hdma_adc1.Init.Channel 				= DMA_CHANNEL_0;hdma_adc1.Init.Direction 			= DMA_PERIPH_TO_MEMORY;hdma_adc1.Init.PeriphInc 			= DMA_PINC_DISABLE;hdma_adc1.Init.MemInc 				= DMA_MINC_ENABLE;hdma_adc1.Init.PeriphDataAlignment 	= DMA_PDATAALIGN_HALFWORD;hdma_adc1.Init.MemDataAlignment 	= DMA_MDATAALIGN_HALFWORD;hdma_adc1.Init.Mode 				= DMA_CIRCULAR;hdma_adc1.Init.Priority 			= DMA_PRIORITY_HIGH;hdma_adc1.Init.FIFOMode 			= DMA_FIFOMODE_DISABLE;if (HAL_DMA_Init(&hdma_adc1) != HAL_OK){Error_Handler();}__HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);}
}void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
{if (adcHandle->Instance == ADC1){__HAL_RCC_ADC1_CLK_DISABLE();/**ADC1 GPIO ConfigurationPB0     ------> ADC1_IN8PB1     ------> ADC1_IN9*/HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0 | GPIO_PIN_1);/* ADC1 DMA DeInit */HAL_DMA_DeInit(adcHandle->DMA_Handle);}
}void MX_DMA_Init(void)
{/* DMA controller clock enable */__HAL_RCC_DMA2_CLK_ENABLE();/* DMA interrupt init *//* DMA2_Stream0_IRQn interrupt configuration */HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}

测试环节

#define ADC_NUM_MAX		2048     		// ADC 转换结果缓冲区最大值
#define VREF            3.3f     		// 参考电压,理论上是3.3,可通过实际测量得3.258static uint16_t adc_buff[ADC_NUM_MAX];	// 电压采集缓冲区
static uint16_t vbus_adc_mean = 0;    	// 电源电压 ACD 采样结果平均值
static uint32_t adc_mean_sum = 0;     	// 平均值累加
static uint32_t adc_mean_count = 0;   	// 累加计数/*** @brief  常规转换在非阻塞模式下完成回调* @param  hadc: ADC  句柄.* @retval 无*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{uint32_t adc_mean = 0;// 停止 ADC 采样,处理完一次数据在继续采样HAL_ADC_Stop_DMA(hadc);       /* 累加ADC通道9的采样值 */for (uint32_t count = 0; count < ADC_NUM_MAX; count += 2){adc_mean += (uint32_t)adc_buff[count];}adc_mean_sum += adc_mean / (ADC_NUM_MAX / 2);   // 累加电流平均后累加adc_mean_count++;								// 累加计数adc_mean = 0;/* 累加ADC通道8的采样值 */for (uint32_t count = 1; count < ADC_NUM_MAX; count += 2){adc_mean += (uint32_t)adc_buff[count];}vbus_adc_mean = adc_mean / (ADC_NUM_MAX / 2);   				// 保存平均值HAL_ADC_Start_DMA(hadc, (uint32_t *)&adc_buff, ADC_NUM_MAX);   	// 开始 ADC 采样
}	/*** @brief  获取电流值* @param  无* @retval 转换得到的电流值*/
int32_t get_curr_val(void)
{static uint8_t flag = 0;static uint32_t adc_offset = 0;    	// 偏置电压int16_t curr_adc_mean = 0;         	// 电流 ADC 采样结果平均值curr_adc_mean = adc_mean_sum / adc_mean_count;    // 保存平均值adc_mean_count = 0;adc_mean_sum = 0;if (flag < 17){adc_offset = curr_adc_mean;    	// 多次记录偏置电压,待系统稳定偏置电压才为有效值flag += 1;}if (curr_adc_mean >= adc_offset){curr_adc_mean -= adc_offset;  	// 减去偏置电压}else{curr_adc_mean = 0;}// 获取电压值float vdc = ((float)vbus_adc_mean / 4096.0f * VREF);// 得到电流值,电压放大8倍,0.02是采样电阻,单位mA。电流采样电路得知的return ( (float)vdc / 8.0f / 0.02f * 1000.0f )          
}/*** @brief  获取电源电压值* @param  无* @retval 转换得到的电流值*/
float get_vbus_val(void)
{// 获取电压值float vdc = ((float)vbus_adc_mean / 4096.0f * VREF);		// 电压最大值(测量电压是电源电压的1/37),电流、电压采样电路得知的return ( ((float)vdc - 1.24f) * 37.0f );      				
}void test(void)
{uint8_t flag = 0;初始化HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&adc_buff, ADC_NUM_MAX);while(1){if (HAL_GetTick() % 50 == 0 && flag == 0)  // 每50毫秒读取一次电流、电压{flag = 1;int32_t current = get_curr_val();printf("电源电压:%.2fV,电流:%dmA\r\n", get_vbus_val(), current);}else if (HAL_GetTick() % 50 != 0 && flag == 1){flag = 0;}}	
}

直流有刷减速电机驱动板限电流、过电压、欠电压保护

ADC配置

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;/* ADC1 init function */
void MX_ADC1_Init(void)
{ADC_AnalogWDGConfTypeDef AnalogWDGConfig = {0};ADC_ChannelConfTypeDef sConfig = {0};/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)*/hadc1.Instance 						= ADC1;hadc1.Init.ClockPrescaler 			= ADC_CLOCK_SYNC_PCLK_DIV4;hadc1.Init.Resolution 				= ADC_RESOLUTION_12B;hadc1.Init.ScanConvMode 			= ENABLE;hadc1.Init.ContinuousConvMode 		= ENABLE;hadc1.Init.DiscontinuousConvMode 	= DISABLE;hadc1.Init.ExternalTrigConvEdge 	= ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.ExternalTrigConv 		= ADC_SOFTWARE_START;hadc1.Init.DataAlign 				= ADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion 			= 2;hadc1.Init.DMAContinuousRequests 	= ENABLE;hadc1.Init.EOCSelection 			= ADC_EOC_SINGLE_CONV;if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();}/** Configure the analog watchdog*/AnalogWDGConfig.WatchdogMode 	= ADC_ANALOGWATCHDOG_SINGLE_REG;AnalogWDGConfig.HighThreshold 	= (15 / 37 + 1.24) / 3.3 * 4096;AnalogWDGConfig.LowThreshold 	= (10 / 37 + 1.24) / 3.3 * 4096;AnalogWDGConfig.Channel 		= ADC_CHANNEL_8;AnalogWDGConfig.ITMode 			= ENABLE;if (HAL_ADC_AnalogWDGConfig(&hadc1, &AnalogWDGConfig) != HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.*/sConfig.Channel 		= ADC_CHANNEL_9;sConfig.Rank 			= 1;sConfig.SamplingTime 	= ADC_SAMPLETIME_3CYCLES;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.*/sConfig.Channel 		= ADC_CHANNEL_8;sConfig.Rank 			= 2;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}
}void MX_DMA_Init(void)
{__HAL_RCC_DMA2_CLK_ENABLE();HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if (adcHandle->Instance == ADC1){/* ADC1 clock enable */__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/**ADC1 GPIO ConfigurationPB0     ------> ADC1_IN8PB1     ------> ADC1_IN9*/GPIO_InitStruct.Pin 	= GPIO_PIN_0 | GPIO_PIN_1;GPIO_InitStruct.Mode 	= GPIO_MODE_ANALOG;GPIO_InitStruct.Pull 	= GPIO_NOPULL;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* ADC1 DMA Init *//* ADC1 Init */hdma_adc1.Instance 					= DMA2_Stream0;hdma_adc1.Init.Channel 				= DMA_CHANNEL_0;hdma_adc1.Init.Direction 			= DMA_PERIPH_TO_MEMORY;hdma_adc1.Init.PeriphInc 			= DMA_PINC_DISABLE;hdma_adc1.Init.MemInc 				= DMA_MINC_ENABLE;hdma_adc1.Init.PeriphDataAlignment 	= DMA_PDATAALIGN_HALFWORD;hdma_adc1.Init.MemDataAlignment 	= DMA_MDATAALIGN_HALFWORD;hdma_adc1.Init.Mode 				= DMA_CIRCULAR;hdma_adc1.Init.Priority 			= DMA_PRIORITY_HIGH;hdma_adc1.Init.FIFOMode 			= DMA_FIFOMODE_DISABLE;if (HAL_DMA_Init(&hdma_adc1) != HAL_OK){Error_Handler();}__HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);/* ADC1 interrupt Init */HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);HAL_NVIC_EnableIRQ(ADC_IRQn);}
}void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
{if (adcHandle->Instance == ADC1){__HAL_RCC_ADC1_CLK_DISABLE();/**ADC1 GPIO ConfigurationPB0     ------> ADC1_IN8PB1     ------> ADC1_IN9*/HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0 | GPIO_PIN_1);/* ADC1 DMA DeInit */HAL_DMA_DeInit(adcHandle->DMA_Handle);/* ADC1 interrupt Deinit */HAL_NVIC_DisableIRQ(ADC_IRQn);}
}

测试环节

#define VREF         	3.3f    // 参考电压,理论上是3.3,可通过实际测量得3.258
#define ADC_NUM_MAX  	2048    // ADC 转换结果缓冲区最大值
#define VBUS_MAX        15     	// 电压最大值
#define VBUS_MIN        10     	// 电压最小值uint16_t adc_buff[ADC_NUM_MAX];
uint16_t vbus_adc_mean = 0;    	// 电源电压 ACD 采样结果平均值
uint32_t adc_mean_sum = 0;      // 平均值累加
uint32_t adc_mean_count = 0;    // 累加计数
uint16_t flag_num = 0;/*** @brief  常规转换在非阻塞模式下完成回调* @param  hadc: ADC  句柄.* @retval 无*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{uint32_t adc_mean = 0;// 停止 ADC 采样,处理完一次数据在继续采样HAL_ADC_Stop_DMA(hadc);       // 电流数据第一次滤波for (uint32_t count = 0; count < ADC_NUM_MAX; count += 2){adc_mean += (uint32_t)adc_buff[count];}adc_mean_sum += adc_mean / (ADC_NUM_MAX / 2);    // 累加电压adc_mean_count++;adc_mean = 0;// 电压数据第一次滤波for (uint32_t count = 1; count < ADC_NUM_MAX; count += 2){adc_mean += (uint32_t)adc_buff[count];}vbus_adc_mean = adc_mean / (ADC_NUM_MAX / 2);    // 保存平均值HAL_ADC_Start_DMA(hadc, (uint32_t *)&adc_buff, ADC_NUM_MAX); // 开始 ADC 采样
}/*** @brief  在非阻塞模式模拟看门狗回调* @param  hadc: ADC  句柄.* @retval 无*/
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef *hadc)
{float temp_adc;flag_num++;     // 电源电压超过阈值电压temp_adc = get_vbus_val();if (temp_adc > VBUS_MIN && temp_adc < VBUS_MAX){flag_num = 0;}if (flag_num > 2048){set_motor_disable();	// 停止电机flag_num = 0;printf("电源电压超过限制!请检查原因,复位开发板在试!\r\n");while (1);}
}/*** @brief  获取电流值(应定时调用)* @param  无* @retval 转换得到的电流值*/
int32_t get_curr_val(void)
{static uint8_t flag = 0;static uint32_t adc_offset = 0;    // 偏置电压int16_t curr_adc_mean = 0;         // 电流 ACD 采样结果平均值// 电流数据第二次滤波curr_adc_mean = adc_mean_sum / adc_mean_count;    // 保存平均值adc_mean_count = 0;adc_mean_sum = 0;if (flag < 17){adc_offset = curr_adc_mean;    // 多次记录偏置电压,待系统稳定偏置电压才为有效值flag += 1;}if (curr_adc_mean >= adc_offset){curr_adc_mean -= adc_offset;  // 减去偏置电压}else{curr_adc_mean = 0;}// 获取电压值float vdc = ((float)vbus_adc_mean / 4096.0f * VREF);// 得到电流值,电压放大8倍,0.02是采样电阻,单位mA。电流采样电路得知的return ( (float)vdc / 8.0f / 0.02f * 1000.0f )     
}/*** @brief  获取电源电压值* @param  无* @retval 转换得到的电流值*/
float get_vbus_val(void)
{// 获取电压值float vdc = ((float)vbus_adc_mean / 4096.0f * VREF);		// 电压最大值(测量电压是电源电压的1/37),电流、电压采样电路得知的return ( ((float)vdc - 1.24f) * 37.0f ); 
}#define CURR_MAX    500    // 最大电流(单位mA)void test(void)
{uint8_t curr_max_count = 0;uint8_t flag = 0;uint8_t dir = 0;初始化HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&adc_buff, ADC_NUM_MAX);while(1){if (HAL_GetTick() % 50 == 0 && flag == 0)  // 每50毫秒读取一次电流、电压{flag = 1;int32_t current = get_curr_val();printf("电源电压:%.2fV,电流:%dmA\r\n", get_vbus_val(), current);if (current > CURR_MAX)    		// 判断是不是超过限定的值{if (curr_max_count++ > 5)   // 连续5次超过{set_motor_disable();	// 电机停止curr_max_count = 0;printf("电流超过限制!请检查原因,复位开发板在试!\r\n");while (1);}}}else if (HAL_GetTick() % 50 != 0 && flag == 1){flag = 0;}	}	
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/136325.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gpt网站资源分享

gpt网站 gpt网站 下面是一个扫码跳转的图片&#xff1a; 里面有3.5和4模型&#xff0c;目前有免费体验&#xff0c;大家可以试试

C++ 之多态(一)

什么是虚函数 在类的定义中&#xff0c;前面有 virtual 关键字的成员函数称为虚函数&#xff1b;virtual 关键字只用在类定义里的函数声明中&#xff0c;写函数体时不用。 class Base {virtual int Fun() ; // 虚函数 };int Base::Fun() // virtual 字段不用在函数体时定义 …

【MySQL】一文学会所有MySQL基础知识以及基本面试题

文章目录 前言 目录 文章目录 前言 一、主流数据库以及如何登陆数据库 二、常用命令使用 三、SQL分类 3.1 存储引擎 四、创建数据库如何设置编码等问题 4.1操纵数据库 4.2操纵表 五、数据类型 六、表的约束 七、基本查询 八、函数 九、复合查询 十、表的内连和外连 十一、索引…

Luatos Air700 改变BL0942串口波特率

LuatOs 改变模块串口波特率思路参照 luatos 改变AIR530串口波特率 BL0942默认串口波特率可以通过SCLK_BPS引脚接3.3V电源设置到9600bps 但如果调整到38400bps需要修改0x19寄存器 bl0942 v1.06版的特殊寄存器说明&#xff0c;注意早期版本特殊寄存器说明存在错误 完整代码 mai…

多路转接(上)——select

目录 一、select接口 1.认识select系统调用 2.对各个参数的认识 二、编写select服务器 1.两个工具类 2.网络套接字封装 3.服务器类编写 4.源文件编写 5.运行 一、select接口 1.认识select系统调用 int select(int nfds, fd_set readfds, fd_set writefds, fd_set ex…

在linux安装单机版hadoop-3.3.6

一、下载hadoop https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/core/hadoop-3.3.6/ 二、配置环境变量 1、配置java环境变量 2、配置hadoop环境变量 export HADOOP_HOME/usr/local/bigdata/hadoop-3.3.6 export HBASE_HOME/usr/local/bigdata/hbase-2.5.6 export JA…

Python进行数据可视化,探索和发现数据中的模式和趋势。

文章目录 前言第一步&#xff1a;导入必要的库第二步&#xff1a;加载数据第三步&#xff1a;创建基本图表第四步&#xff1a;添加更多细节第五步&#xff1a;使用Seaborn库创建更复杂的图表关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Pyth…

Vue 将响应式数据转为普通对象

toRaw&#xff1a;将一个 reactive 生成的响应式数据转为普通对象。 toRaw 适用于&#xff1a;获取响应式数据对应的普通对象&#xff0c;对这个普通对象所有的操作&#xff0c;都不会引起页面的更新。 markRaw&#xff1a;标记一个对象&#xff0c;使其永远不会再成为响应式…

设置区块链节点输出等级为警告级,并把日志存储阈值位100MB并验证;

题目 获取指定区块链节点输出等级为警告级&#xff0c;并设置日志存储阈值位100MB并验证&#xff1b; 操作步骤 1.切换目录 cd nodes/127.0.0.1/node0 2.打开配置文件并修改 vim config.ini warn&#xff1a;警告

初识微服务技术栈

认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构&#xff0c;这些架构之间有怎样的差别呢&#xff1f; 导学&#xff1a; 了解微服务的优缺点&#xff1b;了解微服务架构的演变过程&am…

智能井盖传感器功能,万宾科技产品介绍

在国家治理方面&#xff0c;对社会的治理是一个重要的领域&#xff0c;一定要在推进社会治理现代化过程中提高市政府的管理和工作能力&#xff0c;推动社会拥有稳定有序的发展。在管理过程中对全市井盖进行统一化管理&#xff0c;可能是市政府比较头疼的难题&#xff0c;如果想…

Mybatis(一)

1. Mybatis简介 MyBatis下载地址 1.1 MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff0c;iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到Github…

Flink(三)【运行时架构】

前言 今天学习 Flink 的一些原理性的东西&#xff0c;比较偏概念&#xff0c;但是十分重要。有人觉得上来框框敲代码才能学到东西&#xff0c;那是狗屁不通的道理&#xff08;虽然我以前也这么认为&#xff09;。个人认为&#xff0c;学习 JavaEE那些框架&#xff0c;你上来就敲…

毅速丨为什么不锈钢材料在金属3D打印中应用广泛

不锈钢材料作为一种常见材料&#xff0c;在金属3D打印中应用广泛&#xff0c;可以说是目前使用率最高的材料&#xff0c;为什么不锈钢大受欢迎&#xff0c;主要由几点原因。 第一、工艺适合性 金属3D打印的工艺&#xff0c;如直接金属激光烧结&#xff08;DMLS&#xff09;或选…

人工智能模型转ONNX 连接摄像头使用ONNX格式的模型进行推理

部署之后模型的运算基本上能快5倍。本地部署之后&#xff0c;联网都不需要&#xff0c;数据和隐私不像在网上那样容易泄露了。 模型部署的通用流程 各大厂商都有自己的推理工具。 训练的归训练&#xff0c;部署的归部署&#xff0c;人工智能也分训练端和部署端&#xff0c;每一…

云端生成式 AI – 基于 Amazon EKS 的 Stable Diffusion 图像生成方案

Stable Diffusion 是当下生成式 AI 领域最受欢迎的开源多模态语言-图像模型&#xff0c;由于其易用的接口和良好的使用体验&#xff0c;受到了开源社区和广大设计行业从业者的追捧。Stable Diffusion 模型版本正在快速迭代&#xff0c;并带动了各行各业的生产力变革。目前市场上…

java制作游戏,如何使用libgdx,入门级别教学

第一步&#xff0c;进入libgdx的官网。点击get started 进入这个页面&#xff0c;点击setup a project 进入这个页面直接点击&#xff0c;Generate a project. 点击下载&#xff0c;下载创建工具 它会让你下载一个jar包&#xff0c;有java环境的人可以双击直接打开。 把android…

C语言面试

数据类型&#xff08;基本内置类型&#xff09; char //字符数据类型 short //短整型 int //整型 long //长整型 long long //更长的整型 float //单精度浮点数 double //双精度浮点数 类型的基本归类 整形家族&#xff1a; …

机器人阻抗与导纳控制的区别

机器人自身的非线性动力学&#xff08;由柔软性引起的&#xff09;导致控制精度下降&#xff0c;因此难以描述准确的动力学。 导纳控制和阻抗控制都是基于位置与力关系的模式&#xff0c;被认为具有鲁棒性和安全性。然而&#xff0c;当机器人与刚体接触时&#xff0c;导纳控制常…