Skip to content

Add 60deg setting for hall sensors #455

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from

Conversation

Moddingear
Copy link

I have a 60deg hall sensor motor, it didn't work. This fixes that.

@runger1101001 runger1101001 changed the base branch from master to dev March 6, 2025 23:57
@runger1101001
Copy link
Member

Thank you for contributing this! I'm about to do a release, so I will merge this to the dev branch immediately afterwards so people can test it out. Then it would be part of the following release.

@runger1101001 runger1101001 added the enhancement New feature or request label Mar 7, 2025
@Moddingear
Copy link
Author

Don't merge this just yet, i've got an idea for an algorithm that can find the correct electrical sectors regardless of the connections and the electrical setup.

@Moddingear
Copy link
Author

Ok now it's mergeable.

By default it will act like a 120deg sensor until it sees that it's not, in which case it will switch the polarity of one line.

After two rotations, if it's a 120 deg config, it will stop detecting.

Here's a python file simulating the algorithm as well:

import random
import matplotlib.pyplot as plt

sine_six_step = [0,0,0,1,1,1]

def rotate(l, n):
	return l[n:] + l[:n]

def gen_hall():
	hall_120 = not bool(random.randint(0,3)) and False
	print(f"{hall_120=}")
	sectors = []
	#create hall sensor readings, either 120 deg out of phase, or 60 deg
	for i in range(3):
		sectors.append(rotate(sine_six_step, i*2 if hall_120 else i))
	#shuffle hall connections
	random.shuffle(sectors)
	states = []
	truth = []
	#random starting point, move randomly
	read_pos = random.randint(0,5)
	for i in range(30):
		shift = random.randint(-1,1)
		read_pos = read_pos + shift
		#print(f"{i=} {shift=} {read_pos=}")
		state = 0
		for j in range(3):
			state += sectors[j][read_pos%6] << j
		states.append(state)
		truth.append(read_pos*60)
	return (states, truth)

def plot_stacked_arrays(array_of_arrays, labels=None):
	num_arrays = len(array_of_arrays)
	pos = [i*60 for i in range(len(array_of_arrays[0]))]
	# Create subplots
	fig, axs = plt.subplots(num_arrays, 1, figsize=(8, 2 * num_arrays), sharex=True)
	
	for i, data in enumerate(array_of_arrays):
		axs[i].step(pos, data, where='post', label=labels[i])
		axs[i].set_ylabel(labels[i])
		axs[i].grid(True)
		axs[i].legend()
	
	axs[-1].set_xlabel('Angle')  # Label x-axis only for the last subplot
	plt.tight_layout()
	plt.show()

def get_num_discovered_sectors(ELECTRIC_SECTORS):
	discovered_sectors = 0
	for sector in ELECTRIC_SECTORS:
		if sector != -1:
			discovered_sectors +=1
	return discovered_sectors

def recompose_sectors(ELECTRIC_SECTORS):
	print(f"{ELECTRIC_SECTORS=}")
	names = ["120deg hall", "60deg hall A", "60deg hall B", "60deg hall C"]
	for i in range(4):
		if ELECTRIC_SECTORS[i] == -1 and ELECTRIC_SECTORS[7-i] == -1:
			print(names[i])
			phases = [0]*3
			if i == 0:
				roll = 1
				phases[0] = 0+roll
				phases[1] = 2+roll
				phases[2] = 4+roll
			else:
				#When i==1, hall A is in the middle, phase[0] = 1
				roll = 3
				phases[(i+2)%3] = 1+roll #middle hall
				phases[i%3] = 2+roll #
				phases[(i+1)%3] = 0+roll #
			print(f"{phases=}")
			for j in range(6):
				state = 0
				for k in range(3):
					state += 1<<k if (phases[k]+j)%6 < 3 else 0
				print(f"{j=} {state=}")
				ELECTRIC_SECTORS[state] = j
			break
	else:
		print("Wtf is that hall?!")
	print(f"Recomposed {ELECTRIC_SECTORS=}")

def extract_angle(states, ELECTRIC_SECTORS):
	sector_prev = -1
	direction = 1
	rotations = 0
	discovered_sectors = get_num_discovered_sectors(ELECTRIC_SECTORS)
	angles = []
	
	for state in states:
		new_electric_sector = ELECTRIC_SECTORS[state]
		#calibration phase, build the sector map
		if new_electric_sector == -1 and discovered_sectors <6:
			ELECTRIC_SECTORS[state] = (sector_prev + direction) % 6
			new_electric_sector = ELECTRIC_SECTORS[state]
			discovered_sectors +=1
			print(f"Set sector {state} to {new_electric_sector} ({discovered_sectors}/6)")
			if discovered_sectors == 6:
				recompose_sectors(ELECTRIC_SECTORS)
				print(f"Before {new_electric_sector}, after {ELECTRIC_SECTORS[state]}")
		#repeat of previous, regular sector to angle code
		if new_electric_sector == sector_prev:
			angles.append(angles[-1])
			continue
		electric_sector_diff = new_electric_sector-sector_prev
		if electric_sector_diff > 3:
			direction = -1
			rotations += direction
		elif electric_sector_diff < -3:
			direction = 1
			rotations += direction
		else:
			direction = 1 if (new_electric_sector > sector_prev) else -1
		sector_prev = new_electric_sector
		angles.append((rotations*6+new_electric_sector)*60)
	return angles

def extract_angle2(states):
	ELECTRIC_SECTORS = [-1,  0,  4,  5,  2,  1,  3 , -1]
	state1, state2 = (-1,-1)
	sector_prev = -1
	direction = 1
	rotations = 0
	flipbit = 0
	angles = []
	for state in states:
		state = state ^ flipbit
		if state == state1:
			angles.append(angles[-1] if len(angles) > 0 else 0)
			continue
		if (state1 == 0 or state1 == 7) and state2 != -1:
			if state != state2:
				flipbit = (7 - state ^ state2) % 8
				print(f"{state=} {state1=} {state2=} {bin(flipbit)=}")
				state = state ^ flipbit
		state2, state1 = (state1, state)

		new_electric_sector = ELECTRIC_SECTORS[state]
		electric_sector_diff = new_electric_sector-sector_prev
		if electric_sector_diff > 3:
			direction = -1
			rotations += direction
		elif electric_sector_diff < -3:
			direction = 1
			rotations += direction
		else:
			direction = 1 if (new_electric_sector > sector_prev) else -1
		sector_prev = new_electric_sector
		angles.append((rotations*6+new_electric_sector)*60)
	return angles

states, truth = gen_hall()

ELECTRIC_SECTORS = [-1]*8

angles = extract_angle2(states)

plot_stacked_arrays([truth, states, angles], ["Truth", "States", "Angle"])```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants