开源BLHELI-S 代码详细解读(二)

【Quad FPV】BLDC:BLHeli_S从硬件PCB设计到Keil编译、下载 前言 大学接触到多旋翼无人机以来,飞行水平未见提高,倒是一直在关注遥控设计和机体设计方面。本文记录关于BLHeli电调设计开发过程中的一些坑。 参考文档: timegate 墨鸢,moyuan2000@163.com《无感无刷直流电机之电调设计全攻略 》 逗倪豌儿,联系方式现已失效,《编译 BLHeli_S 的正确方式》 BLHeli固件开源地址:https://github.com/bitdump/BLHeli.git BLHeli上位机:https://github.com/blheli-config 阅读详情
AI摘要

本文主要解析无刷电调电机运行阶段的代码。从启动阶段开始,涉及变量清零、ADC转换、温度与电压检查、功率限制等操作。运行阶段在run1 - run6不断重复,中间进行判断和分支处理,包括换相操作、计算换相时间等。启动阶段完成24次换相后进入初始运行阶段,持续12次换相周期后进入正常运转阶段。

我们继续,

上篇跳到init_start, 现在就到了运行阶段了。 先翻译一下开头的一些相关的注释:

电机控制:

1. 无刷电机控制每360度电角度有6个状态(对应下面的run1-run6六步换相法两两导通,一个悬空用来做反向电动势检查)

2.  一个 0度的前进时机,会在一个换相后,30度的时候过零(zero cross), 
然后再过30度到达下一个时机

3. BLHELI 这里每个前进时机名义是15度

4. 电机的PWM 总是互补的

从过零(zero cross)开始的电机的序列:

; - Timer wait: Wt_Comm            15deg    ; Time to wait from zero cross to actual commutation

                                                                ;从过零后到真正换相的等待时间
; - Timer wait: Wt_Advance        15deg    ; Time to wait for timing advance. Nominal commutation point is after this

                                                                 ;等待前进时机的时间,换相会在这个之后。  
; - Timer wait: Wt_Zc_Scan        7.5deg    ; Time to wait before looking for zero cross

                                                                    ;在寻找过零(zero cross)之前的等待时间
; - Scan for zero cross            22.5deg    ; Nominal, with some motor variations

                                                                 ;名义上的,带一些电机的变数。

电机启动:

在正常根据bemf(反电动势)信号换相流程之前,有startup启动阶段和初始化运行阶段两个阶段。 

       

开启读代码,首先把所有的moset关掉,把Adc_Conversion_Cnt ,Flags0,Flags1,Demag_Detected_Metric(Metric used to gauge demag event frequency)这几个变量清零。

init_start:
	clr	IE_EA
	call switch_power_off
	clr	A
	setb	IE_EA
	clr	A
	mov	Adc_Conversion_Cnt, A
	mov	Flags0, A				; Clear flags0
	mov	Flags1, A				; Clear flags1
	mov	Demag_Detected_Metric, A	; Clear demag metric

等1ms, 然后开始adc转换,通过不停的判断ADC的中断标志是否设置(ADC0CN0_ADINT)
直至读取到温度,然后检查温度,供电电压, 限制输出功率的函数,调用前会设置power, Adc_Conversion_Cnt=8, 这个会在check_temp_voltage_and_limit_power判断,要是小8会进行电压的检查,要是大于等于8,就只有做温度的检查, efm8bb2自带一个温度探测。但是目前看代码,电压没有检查,只是要是Adc_Conversion_Cnt < 8 ,调用一次Pwm_Limit会增加16, 直到 Pwm_Limit == 255.

温度这里读平均值来,会和Temp_Prot_Limit(就是blsuite界面的温度保护设置)比较,要是大于这个温度就对Pwm_Limit进行限制,一旦超了,Pwm_Limit就限制到 192,再看看有超了多个TEMP_LIMIT_STEP/2,  最多会把 Pwm_Limit限制成0. TEMP_LIMIT_STEP在blheli-s基本都是10度,个别是5度。

    如果温度高于临界值,电机功率限制在75%。 - 如果温度高于阈值加上50摄氏度,电机功率限制在50%。 - 如果温度高于阈值加上100摄氏度,电机功率限制在25%。 - 如果温度高于阈值+150℃,则电机功率限制为0%。

;**** **** **** **** ****
	; Motor start beginning
	;**** **** **** **** **** 
	mov	Adc_Conversion_Cnt, #8				; Make sure a temp reading is done
	call wait1ms
	call start_adc_conversion
read_initial_temp:
	jnb	ADC0CN0_ADINT, read_initial_temp
	Read_Adc_Result						; Read initial temperature
	mov	A, Temp2
	jnz	($+3)							; Is reading below 256?

	mov	Temp1, A							; Yes - set average temperature value to zero

	mov	Current_Average_Temp, Temp1			; Set initial average temperature
	call check_temp_voltage_and_limit_power
	mov	Adc_Conversion_Cnt, #8				; Make sure a temp reading is done
	call wait1ms
	call start_adc_conversion
read_initial_temp:
	jnb	ADC0CN0_ADINT, read_initial_temp
	Read_Adc_Result						; Read initial temperature
	mov	A, Temp2
	jnz	($+3)							; Is reading below 256?

	mov	Temp1, A							; Yes - set average temperature value to zero

	mov	Current_Average_Temp, Temp1			; Set initial average temperature
	call check_temp_voltage_and_limit_power
	mov	Adc_Conversion_Cnt, #8				; Make sure a temp reading is done next time

然后设置启动pwm, set_startup_pwm, 这里等于设置界面的值的50倍

	; Set up start operating conditions
	clr	IE_EA				; Disable interrupts
	call set_startup_pwm
	mov	Pwm_Limit, Pwm_Limit_Beg
	mov	Pwm_Limit_By_Rpm, Pwm_Limit_Beg
	setb	IE_EA

开始启动序列,

这里要是48mhz的cpu,这里会设置时钟为48Mhz(    Set_MCU_Clk_48MHz).

然后先是判断是不是双向。设置       Flags1.STARTUP_PHASE , 把Startup_Cnt清零。然后开启换相操作(commutation), 先是5和6(comm5comm6), 再是comm6comm1. 跟着初始化timing(这里就是调置一下Comm_Period4x_L/H为一个指定的值, 它是最近四次换相,timer3的计数), timing是时机的意思,然后跟关计算下一次换相的时机(timing), 第一次是一个虚拟的时机,这个时间由于是无感的电机,也不知道当前的位置,应该是计算不出来的。        


	; Begin startup sequence
IF MCU_48MHZ >= 1
	Set_MCU_Clk_48MHz
ENDIF
	jnb	Flags3.PGM_BIDIR, init_start_bidir_done	; Check if bidirectional operation

	clr	Flags3.PGM_DIR_REV			; Set spinning direction. Default fwd
	jnb	Flags2.RCP_DIR_REV, ($+5)	; Check force direction
	setb	Flags3.PGM_DIR_REV			; Set spinning direction

init_start_bidir_done:
	setb	Flags1.STARTUP_PHASE		; Set startup phase flag
	mov	Startup_Cnt, #0			; Reset counter
	call comm5comm6				; Initialize commutation
	call comm6comm1				
	call initialize_timing			; Initialize timing
	call	calc_next_comm_timing		; Set virtual commutation point
	call initialize_timing			; Initialize timing
	call	calc_next_comm_timing		
	call	initialize_timing			; Initialize timing

计算下次换相时间calc_next_comm_timing这个很重要,迟些要详细看,先还是走主流程

下面来到run1, 这里是B-p 打开,然后C n-pwm打开,然后去检测A的比较器,应该就是检测A的反向电动势, A的电压是会从低到高。 

先是等待A的compare输出为高

然后等待zero cross过零信号

操作换相comm1comm2

计算下次换相时间


;**** **** **** **** **** **** **** **** **** **** **** **** ****
;
; Run entry point
;
;**** **** **** **** **** **** **** **** **** **** **** **** ****

; Run 1 = B(p-on) + C(n-pwm) - comparator A evaluated
; Out_cA changes from low to high
run1:
	call wait_for_comp_out_high	; Wait for high
;		setup_comm_wait		; Setup wait time from zero cross to commutation
;		evaluate_comparator_integrity	; Check whether comparator reading has been normal
	call wait_for_comm			; Wait from zero cross to commutation
	call comm1comm2			; Commutate
	call calc_next_comm_timing	; Calculate next timing and wait advance timing wait
;		wait_advance_timing		; Wait advance timing and start zero cross wait
;		calc_new_wait_times
;		wait_before_zc_scan		; Wait zero cross wait and start zero cross timeout

跟着是run2, 和run1基本上是一样的,A p打开, C是n-pwm控制,然后评估B的比较器. 这时B的电动势是会从高到低。 多了一个set_pwm_limit_high_rpm和set_pwm_limit_low_rpm的判断,这个是判断Flags.HIGH_RPM这个是上一次计算换相timing(时机)的时候设置的。操作换相comm2comm3


; Run 2 = A(p-on) + C(n-pwm) - comparator B evaluated
; Out_cB changes from high to low
run2:
	call wait_for_comp_out_low
;		setup_comm_wait
;		evaluate_comparator_integrity
	jb	Flags1.HIGH_RPM, ($+6)	; Skip if high rpm
	lcall set_pwm_limit_low_rpm
	jnb	Flags1.HIGH_RPM, ($+6)	; Do if high rpm
	lcall set_pwm_limit_high_rpm
	call wait_for_comm
	call comm2comm3
	call calc_next_comm_timing
;		wait_advance_timing
;		calc_new_wait_times
;		wait_before_zc_scan

跟着是run3, 也是差不多了, 这里打开A p,B是n-pwm, 然后评估C的电压。C会从low变成high。操作互相comm3comm4

; Run 3 = A(p-on) + B(n-pwm) - comparator C evaluated
; Out_cC changes from low to high
run3:
	call wait_for_comp_out_high
;	 	setup_comm_wait	
;	 	evaluate_comparator_integrity	
	jnb	Flags1.GOV_ACTIVE, ($+6)
	lcall calc_governor_int_error
	call wait_for_comm
	call comm3comm4
	call calc_next_comm_timing
;	 	wait_advance_timing
;	 	calc_new_wait_times
;	 	wait_before_zc_scan	

跟着是run4, 打开C p, B是n-pwm, 评估A的电压,A会从高变到低,等到之后,操作换相comm4comm5

; Run 4 = C(p-on) + B(n-pwm) - comparator A evaluated
; Out_cA changes from high to low
run4:
	call wait_for_comp_out_low
;		setup_comm_wait
;		evaluate_comparator_integrity
	call wait_for_comm
	call comm4comm5
	call calc_next_comm_timing
;		wait_advance_timing
;		calc_new_wait_times
;		wait_before_zc_scan

跟着是run5, 打开C p, A是n-pwm, 评估B的电压,B会从low变到high,等到之后,操作换相comm5comm6

; Run 5 = C(p-on) + A(n-pwm) - comparator B evaluated
; Out_cB changes from low to high
run5:
	call wait_for_comp_out_high
;		setup_comm_wait
;		evaluate_comparator_integrity
	call wait_for_comm
	call comm5comm6
	call calc_next_comm_timing
;		wait_advance_timing
;		calc_new_wait_times
;		wait_before_zc_scan

跟着run6, 打开B p, A是n-pwm, 评估C的电压,C会从high变到low,等到之后,操作换相comm6comm1. run60这里会先打开温度的adc, 然后互相之后,计算下次换相操作时机前调用check_temp_voltage_and_limit_power,检查温度,然后限制功率。


; Run 6 = B(p-on) + A(n-pwm) - comparator C evaluated
; Out_cC changes from high to low
run6:
	call start_adc_conversion
	call wait_for_comp_out_low
;		setup_comm_wait
;		evaluate_comparator_integrity
	call wait_for_comm
	call comm6comm1
	call check_temp_voltage_and_limit_power
	call calc_next_comm_timing
;		wait_advance_timing
;		calc_new_wait_times
;		wait_before_zc_scan

检查是不是在启动阶段(Flags1.STARTUP_PHASE),不是的话跳到正常的各种检查(normal_run_checks),  否则Pwm_Limit=Pwm_Limit_Beg

      然后检查启动的计数(Startup_Cnt, 它开始是0,在上面的每个run的检测电压时wait_for_comp_out_low或wait_for_comp_out_high, 会有机会增加1)。 

       要是这个计数大于等于24, 那么会清空启动阶段标志(Flags1.STARTUP_PHASE),然后设置初始化运行阶段标志(Flags1.INITIAL_RUN_PHASE),把初始化运行旋转计算(Initial_Run_Rot_Cntd)设置为12,设置Pwm_Limit=Pwm_Limit_Beg, Pwm_Limit_By_Rpm=Pwm_Limit_Beg, 跟着跳到(normal_run_checks). 

      要是启动的计数(Startup_Cnt)还是小于24的话,那么检查油门输入(New_Rcp),要是油门是大于零的,那么跳回run1, 要是油门零,跳到run_to_wait_for_power_on

	; Check if it is direct startup
	jnb	Flags1.STARTUP_PHASE, normal_run_checks

	; Set spoolup power variables
	mov	Pwm_Limit, Pwm_Limit_Beg		; Set initial max power
	; Check startup counter
	mov	Temp2, #24				; Set nominal startup parameters
	mov	Temp3, #12
	clr	C
	mov	A, Startup_Cnt				; Load counter
	subb	A, Temp2					; Is counter above requirement?
	jc	direct_start_check_rcp		; No - proceed

	clr	Flags1.STARTUP_PHASE		; Clear startup phase flag
	setb	Flags1.INITIAL_RUN_PHASE		; Set initial run phase flag
	mov	Initial_Run_Rot_Cntd, Temp3	; Set initial run rotation count
	mov	Pwm_Limit, Pwm_Limit_Beg
	mov	Pwm_Limit_By_Rpm, Pwm_Limit_Beg
	jmp	normal_run_checks

direct_start_check_rcp:
	clr	C
	mov	A, New_Rcp				; Load new pulse value
	subb	A, #1					; Check if pulse is below stop value
	jc	($+5)

	ljmp	run1						; Continue to run 

	jmp	run_to_wait_for_power_on

我们接着代码的布局看normal_run_checks,这里就是启动阶段结束后就会来到了,先是检查 不是运行的初始阶段(INITIAL_RUN_PHASE), 要是没设置Flags1.INITIAL_RUN_PHASE,跳到initial_run_phase_done.  否则检查要是换向的刹车阶段跳到DIR_CHANGE_BRAKE也跳到initial_run_phase_done。上面两个条件不成立,那么就递减一下Initial_Run_Rot_Cntd(初始化是12),检查它是不是0.

           要是0的话,就结束这个运行初始化阶段, 把状态设置成电机已启动阶段(Flags1.MOTOR_STARTED),跳回run1. 

           不是0的话,跳到initial_run_check_startup_rot,要是双向跳到initial_run_continue_run,否则检查油门是不是大于零; 油门不是0的话,跳回run1, 要是零就跳到 run_to_wait_for_power_on。


normal_run_checks:
	; Check if it is initial run phase
	jnb	Flags1.INITIAL_RUN_PHASE, initial_run_phase_done	; If not initial run phase - branch
	jb	Flags1.DIR_CHANGE_BRAKE, initial_run_phase_done	; If a direction change - branch

	; Decrement startup rotaton count
	mov	A, Initial_Run_Rot_Cntd
	dec	A
	; Check number of initial rotations
	jnz 	initial_run_check_startup_rot	; Branch if counter is not zero

	clr	Flags1.INITIAL_RUN_PHASE		; Clear initial run phase flag
	setb	Flags1.MOTOR_STARTED		; Set motor started
	jmp run1						; Continue with normal run

initial_run_check_startup_rot:
	mov	Initial_Run_Rot_Cntd, A		; Not zero - store counter

	jb	Flags3.PGM_BIDIR, initial_run_continue_run	; Check if bidirectional operation

	clr	C
	mov	A, New_Rcp				; Load new pulse value
	subb	A, #1					; Check if pulse is below stop value
	jc	($+5)

initial_run_continue_run:
	ljmp	run1						; Continue to run 

	jmp	run_to_wait_for_power_on

我们按代码的布局来读一下initial_run_phase_done这个位置,这个位置其实就是电机已启动阶段来的,即正常运行时。 先是把Stall_Cnt清零(这个Stall_Cnt会在run_to_wait_for_power_on_fail时增加1),如果PGM_BIDIR设置了,就跳去run6_check_timeout    , 判断Rcp_Stop_Cnt是不是大于预设值(Temp1),要是的话跳去run_to_wait_for_power_on。

             Rcp_Stop_Cnt会有Timer2(每32ms)的中断里检查到油门时自增。要是配置了Pgm_Brake_On_Stop那么,这个Temp1是3(100ms), 否则是250(8秒).   Rcp_Stop_Cnt要是比Temp1大的话,那么认为是没有油门了,跳到run_wait_for_power_on.

initial_run_phase_done:
	; Reset stall count
	mov	Stall_Cnt, #0
	; Exit run loop after a given time
	jb	Flags3.PGM_BIDIR, run6_check_timeout	; Check if bidirectional operation

	mov	Temp1, #250
	mov	Temp2, #Pgm_Brake_On_Stop
	mov	A, @Temp2
	jz	($+4)

	mov	Temp1, #3					; About 100ms before stopping when brake is set

	clr	C
	mov	A, Rcp_Stop_Cnt			; Load stop RC pulse counter low byte value
	subb	A, Temp1					; Is number of stop RC pulses above limit?
	jnc	run_to_wait_for_power_on		; Yes, go back to wait for poweron

没有跳走,就检查 Rcp_Timeout_Cnt是不是超时,它是倒计时的,上一篇有说,初始是10的,每超时一次减1。要是这里看到是零,那么就认为这个也没有油门了,跳到run_to_wait_for_power_on。

run6_check_timeout:
	mov	A, Rcp_Timeout_Cntd			; Load RC pulse timeout counter value
	jz	run_to_wait_for_power_on		; If it is zero - go back to wait for poweron

没跳走,就继续往下走,不是双向的话,就是跳到run6_check_speed, 要是双向倒转PGM_DIR_REV,跳run6_check_dir_rev,不行再看看是不是RCP_DIR_REV,是的话,跳到run6_check_dir_change,说是保证转向匹配力的方向。都不满足就跳到run6_check_speed.

在run6_check_dir_change里,会跳回到run4, 这样顺序变了,就会改变方向。

run6_check_dir:
	jnb	Flags3.PGM_BIDIR, run6_check_speed		; Check if bidirectional operation

	jb	Flags3.PGM_DIR_REV, run6_check_dir_rev		; Check if actual rotation direction
	jb	Flags2.RCP_DIR_REV, run6_check_dir_change	; Matches force direction
	jmp	run6_check_speed


run6_check_dir_rev:
	jnb	Flags2.RCP_DIR_REV, run6_check_dir_change
	jmp	run6_check_speed

run6_check_dir_change:
	jb	Flags1.DIR_CHANGE_BRAKE, run6_check_speed

	setb	Flags1.DIR_CHANGE_BRAKE		; Set brake flag
	mov	Pwm_Limit, Pwm_Limit_Beg		; Set max power while braking
	jmp	run4						; Go back to run 4, thereby changing force direction

来到run6_check_speed, temp1默认是240, 要有DIR_CHANGE_BRAKE, 修改一下Pwm_Limit为Pwm_Limit_Beg     , temp1改为32。 temp1这个是一个时间长短值,跟着temp1会和Comm_Period4x_H    比较大小,要是Comm_Period4x_H   比它小,跳回run1. 否则,看看要是

DIR_CHANGE_BRAKE没有设置的话,就跳到run_to_wait_for_power_on,不是的话,清除DIR_CHANGE_BRAKE的标志,清除PGM_DIR_REV标志,要是RCP_DIR_REV有设置,那么设置PGM_DIR_REV,然后把当前的阶段设置回INITIAL_RUN_PHASE。初始化Initial_Run_Rot_Cntd为18,设置Pwm_Limit = Pwm_Limit_Beg。然后跳加run1.


run6_check_speed:
	mov	Temp1, #0F0h				; Default minimum speed
	jnb	Flags1.DIR_CHANGE_BRAKE, run6_brake_done; Is it a direction change?

	mov	Pwm_Limit, Pwm_Limit_Beg 	; Set max power while braking
	mov	Temp1, #20h 				; Bidirectional braking termination speed

run6_brake_done:
	clr	C
	mov	A, Comm_Period4x_H			; Is Comm_Period4x more than 32ms (~1220 eRPM)?
	subb	A, Temp1
	jnc	($+5)					; Yes - stop or turn direction 
	ljmp	run1						; No - go back to run 1

	jnb	Flags1.DIR_CHANGE_BRAKE, run_to_wait_for_power_on	; If it is not a direction change - stop

	clr	Flags1.DIR_CHANGE_BRAKE		; Clear brake flag
	clr	Flags3.PGM_DIR_REV			; Set spinning direction. Default fwd
	jnb	Flags2.RCP_DIR_REV, ($+5)	; Check force direction
	setb	Flags3.PGM_DIR_REV			; Set spinning direction
	setb	Flags1.INITIAL_RUN_PHASE
	mov	Initial_Run_Rot_Cntd, #18
	mov	Pwm_Limit, Pwm_Limit_Beg		; Set initial max power
	jmp	run1						; Go back to run 1 

到这里主流程就结束了,运行其实就是在run1-run6这里不断重复,中间会做一些判断和分支处理。

以下是网上找到的流程图,可以参考:

启动阶段需完成24次换相,超过24次之后进入初始运行阶段,该阶段持续12次换相周期(每个周期6次换相),完成后进入正常运转阶段。

未完待续。。。。

我们下一篇继续详细读一下这个函数,还有计算换相时间,还有各个计时器,比较器相关的一些代码的阅读。 

什么是电调固件和电调通讯协议-BLheli电调与Dshot通讯学习笔记 DShot(Digital Shot,是数字协议)(相对于oneshot,oneshot125,oneshot42,multishot等模拟协议)。它最初是由Felix在KISS提出的,后来被Betaflight和BLHeli_S开发团队采用。是用来和刷有BLheli固件的电调通讯的协。BLHeli:最古老的两种开源电调固件之一,由于其广泛的功能和友好的用户界面而变得流行。... 阅读详情

相关推荐

(11)(2.2) BLHeli32 and BLHeli_S ESCs(一)

Ardupilot官网关于《Peripheral Hardware》的翻译 —《(2.2) BLHeli32 and BLHeli_S ESCs》。

无人机开发(开源Ardupilot) 2万+

开源BLHELI-S 代码详细解读(一)

Pgm_Beacon_Delay会和Power_On_Wait_Cnt_H相减,要是借位,就会开始beep f4, beep一次Power_On_Wait_Cnt_H会减1,就是Power_On_Wait_Cnt_L是255的时候beep一次了。如果有信号(Rcp_Timeout_Cntd不是零),同时New_Rcp(油门)不是零跳到 wait_for_power_on_nonzero, 再检查一次Rcp_Timeout_Cntd是不是零,要是不是零,那就跳到init_start。这个代码在inc里。

aerror的专栏 4229

从零到一:开源BLHeli_S电调DIY全流程实战解析

本文详细解析了开源BLHeli_S无刷电调的DIY全流程,从核心器件选型(EFM8BB21、FD6288)到硬件设计、固件烧录与参数配置,再到测试验证与性能优化。通过实战案例,帮助读者掌握无刷电调开发的关键技术,适用于无人机和航模爱好者提升DIY能力。

weixin_29191669的博客 644

esp-12f单片机无线控制无刷电机,解锁BLHeli_S电调电机保护,BLHeli_S电调建立Keil工程。

esp-12f单片机无线控制无刷电机,解锁BLHeli_S电调电机保护,BLHeli_S电调建立Keil工程。

m0_69233031的博客 4231

立创开源Blheli_s 8S60A电调:基于BLHeli_s固件的大功率无感方波驱动方案解析

本文详细解析了立创开源Blheli_s 8S60A电调方案,这是一款基于BLHeli_s固件的大功率无感方波驱动方案。文章深入介绍了其硬件规格,包括支持8S锂电池、峰值60A的强劲性能,并重点解析了其支持的Dshot等丰富控制协议。同时,提供了使用Arduino Nano作为编程器进行固件烧录的完整步骤指南,适用于大型无人机、模型船等大功率应用场景。

weixin_30021053的博客 385

STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统

STM32H7B0VBT6使用Free RTOS配置SD卡+Fatfs文件管理系统,记录配置过程

Jack的小窝 5942

BLHeli 固件开源项目教程

BLHeli 固件开源项目教程 项目地址:https://gitcode.com/gh_mirrors/bl/BLHeli 1. 项目介绍 BLHeli 是一个专为无刷电子速度控制器(ESC)固件开发的开源项目。它最初由 Assembly 编写,支持 Atmel 和 Silabs 的 8 位微控制器。后来发展出 BLHeli_S 和 BLHeli_32 两个版本,分别面向 8 位和 32 位处理器...

gitblog_01155的博客 1565

robomimic实验复现全流程:从数据集下载到训练视频生成

本文详细介绍了机器人模仿学习项目RoboMimic的完整实验复现流程。内容涵盖从使用Conda创建Python 3.8隔离环境、安装RoboSuite仿真器和MuJoCo物理引擎,到下载并探索数据集、配置与启动模型训练,最后进行模型评估和生成策略执行视频。该指南旨在帮助研究者和开发者高效搭建实战环境,规避常见问题,快速验证算法或应用于实际场景。

weixin_29089057的博客 518

开源BLHELI-S 代码详细解读(三)

如果不满足,则跳到run_to_wait_for_power_on_fail,这里上一篇有详细读了,是一些失败的检查,最坏会跳回init_no_signal。B. 否则就是在启动的阶段(STARTUP_PHASE),这里会将Startup_Zc_Timeout_Cntd减1(超时次数,wait_before_zc_scan会把它设置成2),要是它还不是0,就跳到comp_check_timeout_extend_timeout,再调用setup_zc_scan_timeout。

aerror的专栏 1677

使用Wireshark抓取用户在网站的登陆密码

(POST请求是浏览器向服务器提交数据的方式,我们的用户名和密码就是这样提交出去的),单击点开,发现我们的账号和密码,就被抓取到了,在。(注意哦,要去掉http和/,比如http://www.4399.com/,我们只需要记下4399.com即可)(这句话是筛选数据,就是只显示IP为我们要抓取网站的数据) ,点击右边的蓝色箭头。这就是Wireshark简单的抓取登录密码的教程,只适用于http协议的网站。”打开,是这个样子,上面的数据先不用管,我们先点击左上角红色的方块停止抓包。,然后回车,得到的IP为。

泡泡的博客 1万+

c语言播放背景音乐

相信很多童鞋都在为大学课设而伤透头脑,而背景音乐的使用无疑会成为其中的一个亮点(总比没有好吧(╯▽╰)),故接下来我将介绍一下如何用C播放音乐。我用的编译器是CodeBlocks16.01接下来新建一个C文件建立完后是这样滴然后添加其中mciSendString()函数是由&lt;mmsystem.h&gt;库提供的供播放音乐(MP3)的函数第一个参数是歌曲所在的绝对路径 打开音乐所在位置 复制这...

qq_41443987的博客 3万+

【亲测免费】 推荐开源项目:KEIL编译BLHeli_S正确方式指南

推荐开源项目:KEIL编译BLHeli_S正确方式指南 【下载地址】KEIL编译BLHeli_S正确方式指南 KEIL编译BLHeli_S正确方式指南本仓库提供了一个名为“KEIL编译BLHeli_S正确方式.pdf”的资源文件,该文件详细介绍了如何使用KEIL MDK编译著名的开源电调BLHeli_S工程 ...

gitblog_06688的博客 1076

STC51单片机串口多字节数据接收的优化策略

本文深入探讨了STC51单片机串口多字节数据接收的优化策略。针对数据丢包、粘包等常见痛点,核心思路是采用“缓冲队列+定时器超时”模式,将实时处理转变为“先收纳,后处理”。文章详细讲解了硬件初始化、中断服务程序优化(快速入队与激活超时裁判)以及主循环的非阻塞设计,并进阶介绍了环形缓冲区实现与错误处理,旨在构建稳定可靠的串口通信系统。

weixin_29264201的博客 374

BLHeli开源电调固件:从新手到专家的完整应用指南

BLHeli是一款专为无刷电机电调设计的开源固件,支持多种飞行器应用场景。作为航模爱好者和无人机开发者的首选方案,它提供了灵活的配置选项和稳定的性能表现。 ## 🚀 三大固件版本:选择适合你的技术路线 BLHeli生态包含三个主要版本,每个版本针对不同的硬件平台和应用需求: ### 1. 经典8位MCU版本(BLHeli) - **支持平台**:Atmel和Silabs 8位微控制器 -

gitblog_01174的博客 915

LoRa无线通信技术介绍(六)SX127X芯片收发程序讲解

接收LORA芯片SX127X的收发程序。

DT程序员的博客 1751

基于STM32单片机设计的智能水温控制系统

本项目研究并实现了一种基于STM32单片机的智能水温控制系统。系统以STM32F103RCT6作为主控制器,通过DS18B20温度传感器实时采集水温数据,利用PID控制算法精确调节5V直流防水型70W加热棒的功率输出,确保水温恒定在设定范围内。此外,采用OLED显示屏显示当前水温和预设上限阀值,并集成ESP8266-WiFi模块与自研Android手机APP进行远程通信和控制。用户可通过本地按键或手机APP设置温度阀值,实现实时监控与智能化管理。整个系统设计旨在提高水资源利用效率,提升生活及工业用水环境的舒

8790

BLHeli_S与BLHeli_32终极对比:无刷电调固件深度解析

在无人机和遥控模型领域,BLHeli固件已经成为无刷电调(ESC)的事实标准。作为开源固件的先驱,BLHeli项目经历了从8位到32位架构的演进,形成了BLHeli_S和BLHeli_32两大主流分支。本文将从技术架构、性能表现、适用场景到实战配置进行全面对比,帮助技术爱好者和进阶用户做出明智选择。 ## 架构演进:从8位精简到32位全能 BLHeli固件的演进反映了嵌入式系统发展的典型路径。

gitblog_00252的博客 374

YOLO26剪枝 lamp剪枝测试精度仅掉0.7个点,速度提高11.8fps!

针对没有如何去选择剪枝的内容LAMP是层自适应幅度调整剪枝,无需任何参数,通过算法内部自己计算每个层的重要程度进行剪枝。基于权重重要程度和该层权重大小关系,权重越大表明该层越重要的思想进行优化。这个跟我前面说的非结构化全局剪枝是一个解法(MP),也就是lamp是在我前面那个非结构化剪枝的基础上进行优化的。但是这个逐层进行非结构剪枝目前还没有一个清晰的概念,确定每个层要剪枝多少。LAMP得分是一个平方权重大小,由层中所有“幸存权重”的总和归一化。

m0_64661770的博客 673

开源BLHELI-S 代码详细解读(四)

如Set_Pwm_C, P1SKIP = 37h(00110111b), 即P1.3 P1.6和 P1.7会给外设使用, 根据优先度,PCA0的CEX0会使用P1.3(CpwmFET)输出 CEX1 会在P1.6(CcomFET)输出。这个 wait_before_zc_scan,其实比较简单,就是从把timer3的超时设置为Comm_Period4x_L和Comm_Period4x_H, 只有在STARTUP_PHASE和 SHL INITIAL_RUN_PHASE阶段才会设置。

aerror的专栏 1262

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

全面解析BLHeli开源电调固件:从8位到32位的无刷电机控制演进

BLHeli是一款广泛应用于无人机和航模领域的开源无刷电调固件,为多旋翼飞行器提供高效精准的电机控制解决方案。这款固件经历了从最初的8位Atmel平台到高性能32位ARM架构的完整演进,成为业界最受欢迎的电调控制软件之一。 ## 🔧 架构演进:三款固件的技术路线图 BLHeli项目包含了三个主要版本,每个版本都针对不同的硬件平台和应用场景进行了优化: **BLHeli(经典版)** - 基

gitblog_00164的博客 266

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Bluejay电调固件介绍和烧录Bluejay电调固件到BLHeli_S电调的方法

本篇文章介绍了Bluejay电调固件介绍和烧录Bluejay电调固件到BLHeli_S电调的方法。Bluejay是一种数字电调固件,用于控制多旋翼无人机中的无刷电机。该电调固件基于BLHeli_S电调固件revision 16.7版本进行改进的。Bluejay的目标是成为BLHeli_S的开源继任者,通过Busy Bee MCU对电调进行了一些改进。DShot是唯一受支持的电调协议。支持用户配置电调启动音乐。Bluejay固件可以烧录到与BLHeli_S兼容的电调。

在后厂村路努力科研搬砖的无人机控制方向练习生一名~ 8807

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

BLHeli电调固件终极指南:5个秘诀解锁无刷电机极致性能

BLHeli是一款开源的**无刷电调固件**,专为航模爱好者和无人机开发者设计。这个强大的固件项目支持多种硬件平台,包括Atmel和SiLabs微控制器,能够显著提升电调性能和响应速度。无论你是竞速飞手还是航拍爱好者,掌握**BLHeli电调调参**技巧都能让你的飞行器性能达到新高度!🚀 ## 项目概述与核心价值 BLHeli项目提供了三个主要版本:经典的BLHeli、改进的BLHeli_S

gitblog_00264的博客 434

深度解析:BLHeli无刷电调固件架构对比与性能优化指南

BLHeli作为开源无刷电调固件的领先解决方案,为无人机和RC模型提供了高性能的电机控制技术。本文将从技术架构、性能参数和应用场景三个维度,深入对比BLHeli、BLHeli_S和BLHeli_32三款固件的核心差异,帮助开发者选择最适合的无刷电调固件方案。 ## 技术背景与项目概述 BLHeli项目始于2011年,最初为Atmel和Silabs 8位MCU开发,采用汇编语言编写,支持直升机主

gitblog_00433的博客 615

BLHeli电调固件配置终极指南:3分钟快速入门教程

BLHeli是一款开源的无刷电调固件项目,为航模爱好者提供了强大的电机控制解决方案。无论你是新手还是经验丰富的飞手,掌握**BLHeli电调固件配置**技巧都能显著提升飞行器的性能和响应速度。这个项目包含了BLHeli、BLHeli_S和BLHeli_32三个主要版本,支持多种硬件平台,为你的飞行器提供专业级的电机控制能力。 ## 为什么选择BLHeli电调固件? BLHeli固件相比原厂固件

gitblog_00622的博客 642

开源BLHELI-S 的C语言版本

【代码】开源BLHELI-S 的C语言版本。

aerror的专栏 524

BLHeli_S vs BLHeli_32:多旋翼应用性能大比拼

BLHeli是一款广泛应用于无刷电调(ESC)的开源固件,为多旋翼飞行器提供高效的电机控制解决方案。本文将深入对比BLHeli_S和BLHeli_32这两款主流固件的性能特点、适用场景及核心功能,帮助你为多旋翼项目选择最合适的电调固件。 ## 🚀 核心架构与硬件支持 BLHeli_S和BLHeli_32在硬件架构上存在显著差异,这直接影响了它们的性能表现和适用范围: ### BLHeli_

gitblog_00735的博客 1097
上一篇: 开源BLHELI-S 代码详细解读(一)
下一篇: 开源BLHELI-S 代码详细解读(三)
aerror
博客等级 码龄23年 392粉丝 193原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值