Skip to content

Commit

Permalink
offload the finish measurement and get sample when Klipper is ready
Browse files Browse the repository at this point in the history
  • Loading branch information
Frix-x committed Sep 15, 2024
1 parent fe78456 commit fa16d96
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 15 deletions.
5 changes: 4 additions & 1 deletion shaketune/commands/axes_map_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def axes_map_calibration(gcmd, config, st_process: ShakeTuneProcess) -> None:
raise gcmd.error(
f'The parameter axes_map is already set in your {accel_chip} configuration! Please remove it (or set it to "x,y,z") to be able to use this macro!'
)
accelerometer = Accelerometer(k_accelerometer)
accelerometer = Accelerometer(k_accelerometer, printer.get_reactor())

toolhead_info = toolhead.get_status(systime)
old_accel = toolhead_info['max_accel']
Expand Down Expand Up @@ -77,18 +77,21 @@ def axes_map_calibration(gcmd, config, st_process: ShakeTuneProcess) -> None:
toolhead.move([mid_x + SEGMENT_LENGTH / 2, mid_y - SEGMENT_LENGTH / 2, z_height, E], speed)
toolhead.dwell(0.5)
accelerometer.stop_recording()
accelerometer.wait_for_samples()
toolhead.dwell(0.5)
accelerometer.start_recording(measurements_manager, name='axesmap_Y', append_time=True)
toolhead.dwell(0.5)
toolhead.move([mid_x + SEGMENT_LENGTH / 2, mid_y + SEGMENT_LENGTH / 2, z_height, E], speed)
toolhead.dwell(0.5)
accelerometer.stop_recording()
accelerometer.wait_for_samples()
toolhead.dwell(0.5)
accelerometer.start_recording(measurements_manager, name='axesmap_Z', append_time=True)
toolhead.dwell(0.5)
toolhead.move([mid_x + SEGMENT_LENGTH / 2, mid_y + SEGMENT_LENGTH / 2, z_height + SEGMENT_LENGTH, E], speed)
toolhead.dwell(0.5)
accelerometer.stop_recording()
accelerometer.wait_for_samples()
toolhead.dwell(0.5)

# Re-enable the input shaper if it was active
Expand Down
3 changes: 2 additions & 1 deletion shaketune/commands/axes_shaper_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,14 @@ def axes_shaper_calibration(gcmd, config, st_process: ShakeTuneProcess) -> None:
accel_chip = Accelerometer.find_axis_accelerometer(printer, config['axis'])
if accel_chip is None:
raise gcmd.error('No suitable accelerometer found for measurement!')
accelerometer = Accelerometer(printer.lookup_object(accel_chip))
accelerometer = Accelerometer(printer.lookup_object(accel_chip), printer.get_reactor())

# Then do the actual measurements
ConsoleOutput.print(f'Measuring {config["label"]}...')
accelerometer.start_recording(measurements_manager, name=config['label'], append_time=True)
vibrate_axis(toolhead, gcode, config['direction'], min_freq, max_freq, hz_per_sec, accel_per_hz)
accelerometer.stop_recording()
accelerometer.wait_for_samples()
toolhead.dwell(0.5)
toolhead.wait_moves()

Expand Down
3 changes: 2 additions & 1 deletion shaketune/commands/compare_belts_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def compare_belts_responses(gcmd, config, st_process: ShakeTuneProcess) -> None:
raise gcmd.error(
'No suitable accelerometer found for measurement! Multi-accelerometer configurations are not supported for this macro.'
)
accelerometer = Accelerometer(printer.lookup_object(accel_chip))
accelerometer = Accelerometer(printer.lookup_object(accel_chip), printer.get_reactor())

# Move to the starting point
test_points = res_tester.test.get_start_test_points()
Expand Down Expand Up @@ -111,6 +111,7 @@ def compare_belts_responses(gcmd, config, st_process: ShakeTuneProcess) -> None:
accelerometer.start_recording(measurements_manager, name=config['label'], append_time=True)
vibrate_axis(toolhead, gcode, config['direction'], min_freq, max_freq, hz_per_sec, accel_per_hz)
accelerometer.stop_recording()
accelerometer.wait_for_samples()
toolhead.dwell(0.5)
toolhead.wait_moves()

Expand Down
3 changes: 2 additions & 1 deletion shaketune/commands/create_vibrations_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def create_vibrations_profile(gcmd, config, st_process: ShakeTuneProcess) -> Non
if k_accelerometer is None:
raise gcmd.error(f'Accelerometer [{current_accel_chip}] not found!')
ConsoleOutput.print(f'Accelerometer chip used for this angle: [{current_accel_chip}]')
accelerometer = Accelerometer(k_accelerometer)
accelerometer = Accelerometer(k_accelerometer, printer.get_reactor())

# Sweep the speed range to record the vibrations at different speeds
for curr_speed_sample in range(nb_speed_samples):
Expand Down Expand Up @@ -135,6 +135,7 @@ def create_vibrations_profile(gcmd, config, st_process: ShakeTuneProcess) -> Non
toolhead.move([mid_x + dX, mid_y + dY, z_height, E], curr_speed)
toolhead.move([mid_x - dX, mid_y - dY, z_height, E], curr_speed)
accelerometer.stop_recording()
accelerometer.wait_for_samples()

toolhead.dwell(0.3)
toolhead.wait_moves()
Expand Down
3 changes: 2 additions & 1 deletion shaketune/commands/excitate_axis_at_freq.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def excitate_axis_at_freq(gcmd, config, st_process: ShakeTuneProcess) -> None:
k_accelerometer = printer.lookup_object(accel_chip, None)
if k_accelerometer is None:
raise gcmd.error(f'Accelerometer chip [{accel_chip}] was not found!')
accelerometer = Accelerometer(k_accelerometer)
accelerometer = Accelerometer(k_accelerometer, printer.get_reactor())
measurements_manager = MeasurementsManager()

ConsoleOutput.print(f'Excitating {axis.upper()} axis at {freq}Hz for {duration} seconds')
Expand Down Expand Up @@ -101,6 +101,7 @@ def excitate_axis_at_freq(gcmd, config, st_process: ShakeTuneProcess) -> None:
# If the user wanted to create a graph, we stop the recording and generate it
if create_graph:
accelerometer.stop_recording()
accelerometer.wait_for_samples()
toolhead.dwell(0.5)

creator = st_process.get_graph_creator()
Expand Down
49 changes: 39 additions & 10 deletions shaketune/helpers/accelerometer.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,18 +140,21 @@ def wait_for_file_writes(self, k_reactor, timeout: int = 20):

if not complete:
raise TimeoutError(
'Shake&Tune was unable to write the accelerometer data into the archive file. '
'Shake&Tune was unable to write the accelerometer data into the .STDATA file. '
'This might be due to a slow SD card or a busy or full filesystem.'
)

self._write_process = None


class Accelerometer:
def __init__(self, klipper_accelerometer):
def __init__(self, klipper_accelerometer, k_reactor):
self._k_accelerometer = klipper_accelerometer
self._k_reactor = k_reactor
self._bg_client = None
self._measurements_manager: MeasurementsManager = None
self._samples_ready = False
self._sample_error = None

@staticmethod
def find_axis_accelerometer(printer, axis: str = 'xy'):
Expand Down Expand Up @@ -186,13 +189,39 @@ def stop_recording(self) -> MeasurementsManager:
ConsoleOutput.print('Warning: no recording to stop!')
return None

bg_client = self._bg_client
self._bg_client = None
bg_client.finish_measurements()
# Register a callback in Klipper's reactor to finish the measurements and get the
# samples when Klipper is ready to process them (and without blocking its main thread)
self._k_reactor.register_callback(self._finish_and_get_samples)

return self._measurements_manager

def _finish_and_get_samples(self, bg_client):
try:
self._bg_client.finish_measurements()
samples = self._bg_client.samples or self._bg_client.get_samples()
self._measurements_manager.append_samples_to_last_measurement(samples)
self._samples_ready = True
except Exception as e:
ConsoleOutput.print(f'Error during accelerometer data retrieval: {e}')
self._sample_error = e
finally:
self._bg_client = None

def wait_for_samples(self, timeout: int = 20):
eventtime = self._k_reactor.monotonic()
endtime = eventtime + timeout

while eventtime < endtime:
eventtime = self._k_reactor.pause(eventtime + 0.05)
if self._samples_ready:
break
if self._sample_error:
raise self._sample_error

samples = bg_client.samples or bg_client.get_samples()
self._measurements_manager.append_samples_to_last_measurement(samples)
m_manager = self._measurements_manager
self._measurements_manager = None
if not self._samples_ready:
raise TimeoutError(
'Shake&Tune was unable to retrieve accelerometer data in time. '
'This might be due to slow hardware or a busy system.'
)

return m_manager
self._samples_ready = False

0 comments on commit fa16d96

Please sign in to comment.