69
.github/workflows/test.yml
vendored
Normal file
69
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
name: Smoke Tests
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
klippy_testing:
|
||||
name: Klippy Tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
klipper_repo:
|
||||
- klipper3d/klipper
|
||||
- DangerKlippers/danger-klipper
|
||||
steps:
|
||||
- name: Checkout shaketune
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: shaketune
|
||||
- name: Checkout Klipper
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: klipper
|
||||
repository: ${{ matrix.klipper_repo }}
|
||||
ref: master
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential
|
||||
- name: Build klipper dict
|
||||
run: |
|
||||
pushd klipper
|
||||
cp ../shaketune/ci/smoke-test/klipper-smoketest.kconfig .config
|
||||
make olddefconfig
|
||||
make out/compile_time_request.o
|
||||
popd
|
||||
- name: Setup klippy env
|
||||
run: |
|
||||
python3 -m venv --prompt klippy klippy-env
|
||||
./klippy-env/bin/python -m pip install -r klipper/scripts/klippy-requirements.txt
|
||||
./klippy-env/bin/python -m pip install -r shaketune/requirements.txt
|
||||
- name: Install shaketune
|
||||
run: |
|
||||
ln -s $PWD/shaketune/shaketune $PWD/klipper/klippy/extras/shaketune
|
||||
- name: Klipper import test
|
||||
run: |
|
||||
./klippy-env/bin/python klipper/klippy/klippy.py --import-test
|
||||
- name: Klipper integrated test
|
||||
run: |
|
||||
pushd klipper
|
||||
mkdir ../dicts
|
||||
cp ../klipper/out/klipper.dict ../dicts/linux_basic.dict
|
||||
../klippy-env/bin/python scripts/test_klippy.py -d ../dicts ../shaketune/ci/smoke-test/klippy-tests/simple.test
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
cache: 'pip'
|
||||
- name: install ruff
|
||||
run: |
|
||||
pip install ruff
|
||||
- name: run ruff tests
|
||||
run: |
|
||||
ruff check
|
||||
|
||||
|
||||
34
ci/smoke-test/klipper-smoketest.kconfig
Normal file
34
ci/smoke-test/klipper-smoketest.kconfig
Normal file
@@ -0,0 +1,34 @@
|
||||
CONFIG_LOW_LEVEL_OPTIONS=y
|
||||
# CONFIG_MACH_AVR is not set
|
||||
# CONFIG_MACH_ATSAM is not set
|
||||
# CONFIG_MACH_ATSAMD is not set
|
||||
# CONFIG_MACH_LPC176X is not set
|
||||
# CONFIG_MACH_STM32 is not set
|
||||
# CONFIG_MACH_HC32F460 is not set
|
||||
# CONFIG_MACH_RP2040 is not set
|
||||
# CONFIG_MACH_PRU is not set
|
||||
# CONFIG_MACH_AR100 is not set
|
||||
CONFIG_MACH_LINUX=y
|
||||
# CONFIG_MACH_SIMU is not set
|
||||
CONFIG_BOARD_DIRECTORY="linux"
|
||||
CONFIG_CLOCK_FREQ=50000000
|
||||
CONFIG_LINUX_SELECT=y
|
||||
CONFIG_USB_VENDOR_ID=0x1d50
|
||||
CONFIG_USB_DEVICE_ID=0x614e
|
||||
CONFIG_USB_SERIAL_NUMBER="12345"
|
||||
CONFIG_WANT_GPIO_BITBANGING=y
|
||||
CONFIG_WANT_DISPLAYS=y
|
||||
CONFIG_WANT_SENSORS=y
|
||||
CONFIG_WANT_LIS2DW=y
|
||||
CONFIG_WANT_LDC1612=y
|
||||
CONFIG_WANT_SOFTWARE_I2C=y
|
||||
CONFIG_WANT_SOFTWARE_SPI=y
|
||||
CONFIG_NEED_SENSOR_BULK=y
|
||||
CONFIG_CANBUS_FREQUENCY=1000000
|
||||
CONFIG_INITIAL_PINS=""
|
||||
CONFIG_HAVE_GPIO=y
|
||||
CONFIG_HAVE_GPIO_ADC=y
|
||||
CONFIG_HAVE_GPIO_SPI=y
|
||||
CONFIG_HAVE_GPIO_I2C=y
|
||||
CONFIG_HAVE_GPIO_HARD_PWM=y
|
||||
CONFIG_INLINE_STEPPER_HACK=y
|
||||
9
ci/smoke-test/klippy-tests/simple.cfg
Normal file
9
ci/smoke-test/klippy-tests/simple.cfg
Normal file
@@ -0,0 +1,9 @@
|
||||
[mcu]
|
||||
serial: /tmp/klipper_host_mcu
|
||||
|
||||
[printer]
|
||||
kinematics: none
|
||||
max_velocity: 300
|
||||
max_accel: 300
|
||||
|
||||
[shaketune]
|
||||
4
ci/smoke-test/klippy-tests/simple.test
Normal file
4
ci/smoke-test/klippy-tests/simple.test
Normal file
@@ -0,0 +1,4 @@
|
||||
DICTIONARY linux_basic.dict
|
||||
CONFIG simple.cfg
|
||||
|
||||
G4 P1000
|
||||
@@ -1,5 +1,5 @@
|
||||
[project]
|
||||
name = "Shake&Tune"
|
||||
name = "shake_n_tune"
|
||||
description = "Klipper streamlined input shaper workflow and calibration tools"
|
||||
readme = "README.md"
|
||||
requires-python = ">= 3.9"
|
||||
|
||||
@@ -13,10 +13,13 @@ import os
|
||||
import time
|
||||
from multiprocessing import Process, Queue
|
||||
|
||||
FILE_WRITE_TIMEOUT = 10 # seconds
|
||||
|
||||
|
||||
class Accelerometer:
|
||||
def __init__(self, klipper_accelerometer):
|
||||
def __init__(self, reactor, klipper_accelerometer):
|
||||
self._k_accelerometer = klipper_accelerometer
|
||||
self._reactor = reactor
|
||||
|
||||
self._bg_client = None
|
||||
self._write_queue = Queue()
|
||||
@@ -70,16 +73,35 @@ class Accelerometer:
|
||||
os.nice(20)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
with open(filename, 'w') as f:
|
||||
f.write('#time,accel_x,accel_y,accel_z\n')
|
||||
samples = bg_client.samples or bg_client.get_samples()
|
||||
for t, accel_x, accel_y, accel_z in samples:
|
||||
f.write(f'{t:.6f},{accel_x:.6f},{accel_y:.6f},{accel_z:.6f}\n')
|
||||
|
||||
self._write_queue.get()
|
||||
|
||||
def wait_for_file_writes(self):
|
||||
while not self._write_queue.empty():
|
||||
time.sleep(0.1)
|
||||
eventtime = self._reactor.monotonic()
|
||||
self._reactor.pause(eventtime + 0.1)
|
||||
|
||||
for proc in self._write_processes:
|
||||
proc.join()
|
||||
if proc is None:
|
||||
continue
|
||||
eventtime = self._reactor.monotonic()
|
||||
endtime = eventtime + FILE_WRITE_TIMEOUT
|
||||
complete = False
|
||||
while eventtime < endtime:
|
||||
eventtime = self._reactor.pause(eventtime + 0.05)
|
||||
if not proc.is_alive():
|
||||
complete = True
|
||||
break
|
||||
if not complete:
|
||||
raise TimeoutError(
|
||||
'Shake&Tune was not able to write the accelerometer data into the CSV file. '
|
||||
'This might be due to a slow SD card or a busy or full filesystem.'
|
||||
)
|
||||
|
||||
self._write_processes = []
|
||||
|
||||
@@ -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")!'
|
||||
)
|
||||
accelerometer = Accelerometer(k_accelerometer)
|
||||
accelerometer = Accelerometer(printer.get_reactor(), k_accelerometer)
|
||||
|
||||
toolhead_info = toolhead.get_status(systime)
|
||||
old_accel = toolhead_info['max_accel']
|
||||
@@ -46,7 +46,9 @@ def axes_map_calibration(gcmd, config, st_process: ShakeTuneProcess) -> None:
|
||||
# set the wanted acceleration values
|
||||
if 'minimum_cruise_ratio' in toolhead_info:
|
||||
old_mcr = toolhead_info['minimum_cruise_ratio'] # minimum_cruise_ratio found: Klipper >= v0.12.0-239
|
||||
gcode.run_script_from_command(f'SET_VELOCITY_LIMIT ACCEL={accel} MINIMUM_CRUISE_RATIO=0 SQUARE_CORNER_VELOCITY=5.0')
|
||||
gcode.run_script_from_command(
|
||||
f'SET_VELOCITY_LIMIT ACCEL={accel} MINIMUM_CRUISE_RATIO=0 SQUARE_CORNER_VELOCITY=5.0'
|
||||
)
|
||||
else: # minimum_cruise_ratio not found: Klipper < v0.12.0-239
|
||||
old_mcr = None
|
||||
gcode.run_script_from_command(f'SET_VELOCITY_LIMIT ACCEL={accel} SQUARE_CORNER_VELOCITY=5.0')
|
||||
@@ -94,7 +96,9 @@ def axes_map_calibration(gcmd, config, st_process: ShakeTuneProcess) -> None:
|
||||
|
||||
# Restore the previous acceleration values
|
||||
if old_mcr is not None: # minimum_cruise_ratio found: Klipper >= v0.12.0-239
|
||||
gcode.run_script_from_command(f'SET_VELOCITY_LIMIT ACCEL={old_accel} MINIMUM_CRUISE_RATIO={old_mcr} SQUARE_CORNER_VELOCITY={old_sqv}')
|
||||
gcode.run_script_from_command(
|
||||
f'SET_VELOCITY_LIMIT ACCEL={old_accel} MINIMUM_CRUISE_RATIO={old_mcr} SQUARE_CORNER_VELOCITY={old_sqv}'
|
||||
)
|
||||
else: # minimum_cruise_ratio not found: Klipper < v0.12.0-239
|
||||
gcode.run_script_from_command(f'SET_VELOCITY_LIMIT ACCEL={old_accel} SQUARE_CORNER_VELOCITY={old_sqv}')
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ 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.get_reactor(), printer.lookup_object(accel_chip))
|
||||
|
||||
# Then do the actual measurements
|
||||
accelerometer.start_measurement()
|
||||
|
||||
@@ -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.get_reactor(), printer.lookup_object(accel_chip))
|
||||
|
||||
# Move to the starting point
|
||||
test_points = res_tester.test.get_start_test_points()
|
||||
|
||||
@@ -64,7 +64,9 @@ def create_vibrations_profile(gcmd, config, st_process: ShakeTuneProcess) -> Non
|
||||
# set the wanted acceleration values
|
||||
if 'minimum_cruise_ratio' in toolhead_info: # minimum_cruise_ratio found: Klipper >= v0.12.0-239
|
||||
old_mcr = toolhead_info['minimum_cruise_ratio']
|
||||
gcode.run_script_from_command(f'SET_VELOCITY_LIMIT ACCEL={accel} MINIMUM_CRUISE_RATIO=0 SQUARE_CORNER_VELOCITY=5.0')
|
||||
gcode.run_script_from_command(
|
||||
f'SET_VELOCITY_LIMIT ACCEL={accel} MINIMUM_CRUISE_RATIO=0 SQUARE_CORNER_VELOCITY=5.0'
|
||||
)
|
||||
else: # minimum_cruise_ratio not found: Klipper < v0.12.0-239
|
||||
old_mcr = None
|
||||
gcode.run_script_from_command(f'SET_VELOCITY_LIMIT ACCEL={accel} SQUARE_CORNER_VELOCITY=5.0')
|
||||
@@ -95,7 +97,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(printer.get_reactor(), k_accelerometer)
|
||||
|
||||
# Sweep the speed range to record the vibrations at different speeds
|
||||
for curr_speed_sample in range(nb_speed_samples):
|
||||
@@ -139,7 +141,9 @@ def create_vibrations_profile(gcmd, config, st_process: ShakeTuneProcess) -> Non
|
||||
|
||||
# Restore the previous acceleration values
|
||||
if old_mcr is not None: # minimum_cruise_ratio found: Klipper >= v0.12.0-239
|
||||
gcode.run_script_from_command(f'SET_VELOCITY_LIMIT ACCEL={old_accel} MINIMUM_CRUISE_RATIO={old_mcr} SQUARE_CORNER_VELOCITY={old_sqv}')
|
||||
gcode.run_script_from_command(
|
||||
f'SET_VELOCITY_LIMIT ACCEL={old_accel} MINIMUM_CRUISE_RATIO={old_mcr} SQUARE_CORNER_VELOCITY={old_sqv}'
|
||||
)
|
||||
else: # minimum_cruise_ratio not found: Klipper < v0.12.0-239
|
||||
gcode.run_script_from_command(f'SET_VELOCITY_LIMIT ACCEL={old_accel} SQUARE_CORNER_VELOCITY={old_sqv}')
|
||||
toolhead.wait_moves()
|
||||
|
||||
@@ -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(printer.get_reactor(), k_accelerometer)
|
||||
|
||||
ConsoleOutput.print(f'Excitating {axis.upper()} axis at {freq}Hz for {duration} seconds')
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ from .helpers.console_output import ConsoleOutput
|
||||
from .shaketune_config import ShakeTuneConfig
|
||||
from .shaketune_process import ShakeTuneProcess
|
||||
|
||||
IN_DANGER = False
|
||||
|
||||
|
||||
class ShakeTune:
|
||||
def __init__(self, config) -> None:
|
||||
@@ -51,21 +53,31 @@ class ShakeTune:
|
||||
self._config = ShakeTuneConfig(result_folder_path, keep_n_results, keep_csv, dpi)
|
||||
ConsoleOutput.register_output_callback(gcode.respond_info)
|
||||
|
||||
commands = [
|
||||
# Register Shake&Tune's measurement commands
|
||||
measurement_commands = [
|
||||
(
|
||||
'EXCITATE_AXIS_AT_FREQ',
|
||||
self.cmd_EXCITATE_AXIS_AT_FREQ,
|
||||
'Maintain a specified excitation frequency for a period of time to diagnose and locate a source of vibration',
|
||||
(
|
||||
'Maintain a specified excitation frequency for a period '
|
||||
'of time to diagnose and locate a source of vibrations'
|
||||
),
|
||||
),
|
||||
(
|
||||
'AXES_MAP_CALIBRATION',
|
||||
self.cmd_AXES_MAP_CALIBRATION,
|
||||
'Perform a set of movements to measure the orientation of the accelerometer and help you set the best axes_map configuration for your printer',
|
||||
(
|
||||
'Perform a set of movements to measure the orientation of the accelerometer '
|
||||
'and help you set the best axes_map configuration for your printer'
|
||||
),
|
||||
),
|
||||
(
|
||||
'COMPARE_BELTS_RESPONSES',
|
||||
self.cmd_COMPARE_BELTS_RESPONSES,
|
||||
'Perform a custom half-axis test to analyze and compare the frequency profiles of individual belts on CoreXY printers',
|
||||
(
|
||||
'Perform a custom half-axis test to analyze and compare the '
|
||||
'frequency profiles of individual belts on CoreXY or CoreXZ printers'
|
||||
),
|
||||
),
|
||||
(
|
||||
'AXES_SHAPER_CALIBRATION',
|
||||
@@ -75,12 +87,14 @@ class ShakeTune:
|
||||
(
|
||||
'CREATE_VIBRATIONS_PROFILE',
|
||||
self.cmd_CREATE_VIBRATIONS_PROFILE,
|
||||
'Perform a set of movements to measure the orientation of the accelerometer and help you set the best axes_map configuration for your printer',
|
||||
(
|
||||
'Run a series of motions to find speed/angle ranges where the printer could be '
|
||||
'exposed to VFAs to optimize your slicer speed profiles and TMC driver parameters'
|
||||
),
|
||||
),
|
||||
]
|
||||
command_descriptions = {name: desc for name, _, desc in commands}
|
||||
|
||||
for name, command, description in commands:
|
||||
command_descriptions = {name: desc for name, _, desc in measurement_commands}
|
||||
for name, command, description in measurement_commands:
|
||||
gcode.register_command(f'_{name}' if show_macros else name, command, desc=description)
|
||||
|
||||
# Load the dummy macros with their description in order to show them in the web interfaces
|
||||
|
||||
Reference in New Issue
Block a user