mirror of https://github.com/Desuuuu/klipper.git
adxl345: Support recording data from multiple ADXL345's in one run, and more. (#5224)
Add PROBE and CHIP to TEST_RESONANCES Since it's possible to specify more than one chip in TEST_RESONANCES the CHIP parameter has been renamed to CHIPS Signed-off-by: Mikkel Schmidt <mikkel.schmidt@gmail.com>
This commit is contained in:
parent
c7e0372c5d
commit
af38d708cb
|
@ -896,23 +896,28 @@ all enabled accelerometer chips.
|
|||
#### TEST_RESONANCES
|
||||
`TEST_RESONANCES AXIS=<axis> OUTPUT=<resonances,raw_data>
|
||||
[NAME=<name>] [FREQ_START=<min_freq>] [FREQ_END=<max_freq>]
|
||||
[HZ_PER_SEC=<hz_per_sec>] [INPUT_SHAPING=[<0:1>]]`: Runs the resonance
|
||||
[HZ_PER_SEC=<hz_per_sec>] [CHIPS=<adxl345_chip_name>]
|
||||
[POINT=x,y,z] [INPUT_SHAPING=[<0:1>]]`: Runs the resonance
|
||||
test in all configured probe points for the requested "axis" and
|
||||
measures the acceleration using the accelerometer chips configured for
|
||||
the respective axis. "axis" can either be X or Y, or specify an
|
||||
arbitrary direction as `AXIS=dx,dy`, where dx and dy are floating
|
||||
point numbers defining a direction vector (e.g. `AXIS=X`, `AXIS=Y`, or
|
||||
`AXIS=1,-1` to define a diagonal direction). Note that `AXIS=dx,dy`
|
||||
and `AXIS=-dx,-dy` is equivalent. If `INPUT_SHAPING=0` or not set
|
||||
(default), disables input shaping for the resonance testing, because
|
||||
and `AXIS=-dx,-dy` is equivalent. `adxl345_chip_name` can be one or
|
||||
more configured adxl345 chip,delimited with comma, for example
|
||||
`CHIPS="adxl345, adxl345 rpi"`. Note that `adxl345` can be omitted from
|
||||
named adxl345 chips. If POINT is specified it will override the point(s)
|
||||
configured in `[resonance_tester]`. If `INPUT_SHAPING=0` or not set(default),
|
||||
disables input shaping for the resonance testing, because
|
||||
it is not valid to run the resonance testing with the input shaper
|
||||
enabled. `OUTPUT` parameter is a comma-separated list of which outputs
|
||||
will be written. If `raw_data` is requested, then the raw
|
||||
accelerometer data is written into a file or a series of files
|
||||
`/tmp/raw_data_<axis>_[<point>_]<name>.csv` with (`<point>_` part of
|
||||
the name generated only if more than 1 probe point is configured). If
|
||||
`resonances` is specified, the frequency response is calculated
|
||||
(across all probe points) and written into
|
||||
`/tmp/raw_data_<axis>_[<chip_name>_][<point>_]<name>.csv` with
|
||||
(`<point>_` part of the name generated only if more than 1 probe point
|
||||
is configured or POINT is specified). If `resonances` is specified, the
|
||||
frequency response is calculated (across all probe points) and written into
|
||||
`/tmp/resonances_<axis>_<name>.csv` file. If unset, OUTPUT defaults to
|
||||
`resonances`, and NAME defaults to the current time in
|
||||
"YYYYMMDD_HHMMSS" format.
|
||||
|
|
|
@ -147,15 +147,21 @@ class ResonanceTester:
|
|||
(chip_axis, self.printer.lookup_object(chip_name))
|
||||
for chip_axis, chip_name in self.accel_chip_names]
|
||||
|
||||
def _run_test(self, gcmd, axes, helper, raw_name_suffix=None):
|
||||
def _run_test(self, gcmd, axes, helper, raw_name_suffix=None,
|
||||
accel_chips=None, test_point=None):
|
||||
toolhead = self.printer.lookup_object('toolhead')
|
||||
calibration_data = {axis: None for axis in axes}
|
||||
|
||||
self.test.prepare_test(gcmd)
|
||||
test_points = self.test.get_start_test_points()
|
||||
|
||||
if test_point is not None:
|
||||
test_points = [test_point]
|
||||
else:
|
||||
test_points = self.test.get_start_test_points()
|
||||
|
||||
for point in test_points:
|
||||
toolhead.manual_move(point, self.move_speed)
|
||||
if len(test_points) > 1:
|
||||
if len(test_points) > 1 or test_point is not None:
|
||||
gcmd.respond_info(
|
||||
"Probing point (%.3f, %.3f, %.3f)" % tuple(point))
|
||||
for axis in axes:
|
||||
|
@ -165,29 +171,36 @@ class ResonanceTester:
|
|||
gcmd.respond_info("Testing axis %s" % axis.get_name())
|
||||
|
||||
raw_values = []
|
||||
for chip_axis, chip in self.accel_chips:
|
||||
if axis.matches(chip_axis):
|
||||
if accel_chips is None:
|
||||
for chip_axis, chip in self.accel_chips:
|
||||
if axis.matches(chip_axis):
|
||||
aclient = chip.start_internal_client()
|
||||
raw_values.append((chip_axis, aclient, chip.name))
|
||||
else:
|
||||
for chip in accel_chips:
|
||||
aclient = chip.start_internal_client()
|
||||
raw_values.append((chip_axis, aclient))
|
||||
raw_values.append((axis, aclient, chip.name))
|
||||
|
||||
# Generate moves
|
||||
self.test.run_test(axis, gcmd)
|
||||
for chip_axis, aclient in raw_values:
|
||||
for chip_axis, aclient, chip_name in raw_values:
|
||||
aclient.finish_measurements()
|
||||
if raw_name_suffix is not None:
|
||||
raw_name = self.get_filename(
|
||||
'raw_data', raw_name_suffix, axis,
|
||||
point if len(test_points) > 1 else None)
|
||||
point if len(test_points) > 1 else None,
|
||||
chip_name if accel_chips is not None else None,)
|
||||
aclient.write_to_file(raw_name)
|
||||
gcmd.respond_info(
|
||||
"Writing raw accelerometer data to "
|
||||
"%s file" % (raw_name,))
|
||||
if helper is None:
|
||||
continue
|
||||
for chip_axis, aclient in raw_values:
|
||||
for chip_axis, aclient, chip_name in raw_values:
|
||||
if not aclient.has_valid_samples():
|
||||
raise gcmd.error(
|
||||
"%s-axis accelerometer measured no data" % (
|
||||
chip_axis,))
|
||||
"accelerometer '%s' measured no data" % (
|
||||
chip_name,))
|
||||
new_data = helper.process_accelerometer_data(aclient)
|
||||
if calibration_data[axis] is None:
|
||||
calibration_data[axis] = new_data
|
||||
|
@ -198,6 +211,28 @@ class ResonanceTester:
|
|||
def cmd_TEST_RESONANCES(self, gcmd):
|
||||
# Parse parameters
|
||||
axis = _parse_axis(gcmd, gcmd.get("AXIS").lower())
|
||||
accel_chips = gcmd.get("CHIPS", None)
|
||||
test_point = gcmd.get("POINT", None)
|
||||
|
||||
if test_point:
|
||||
test_coords = test_point.split(',')
|
||||
if len(test_coords) != 3:
|
||||
raise gcmd.error("Invalid POINT parameter, must be 'x,y,z'")
|
||||
try:
|
||||
test_point = [float(p.strip()) for p in test_coords]
|
||||
except ValueError:
|
||||
raise gcmd.error("Invalid POINT parameter, must be 'x,y,z'"
|
||||
" where x, y and z are valid floating point numbers")
|
||||
|
||||
if accel_chips:
|
||||
parsed_chips = []
|
||||
for chip_name in accel_chips.split(','):
|
||||
if "adxl345" in chip_name:
|
||||
chip_lookup_name = chip_name.strip()
|
||||
else:
|
||||
chip_lookup_name = "adxl345 " + chip_name.strip();
|
||||
chip = self.printer.lookup_object(chip_lookup_name)
|
||||
parsed_chips.append(chip)
|
||||
|
||||
outputs = gcmd.get("OUTPUT", "resonances").lower().split(',')
|
||||
for output in outputs:
|
||||
|
@ -221,10 +256,13 @@ class ResonanceTester:
|
|||
|
||||
data = self._run_test(
|
||||
gcmd, [axis], helper,
|
||||
raw_name_suffix=name_suffix if raw_output else None)[axis]
|
||||
raw_name_suffix=name_suffix if raw_output else None,
|
||||
accel_chips=parsed_chips if accel_chips else None,
|
||||
test_point=test_point)[axis]
|
||||
if csv_output:
|
||||
csv_name = self.save_calibration_data('resonances', name_suffix,
|
||||
helper, axis, data)
|
||||
helper, axis, data,
|
||||
point=test_point)
|
||||
gcmd.respond_info(
|
||||
"Resonances data written to %s file" % (csv_name,))
|
||||
cmd_SHAPER_CALIBRATE_help = (
|
||||
|
@ -287,7 +325,8 @@ class ResonanceTester:
|
|||
for chip_axis, aclient in raw_values:
|
||||
if not aclient.has_valid_samples():
|
||||
raise gcmd.error(
|
||||
"%s-axis accelerometer measured no data" % (chip_axis,))
|
||||
"%s-axis accelerometer measured no data" % (
|
||||
chip_axis,))
|
||||
data = helper.process_accelerometer_data(aclient)
|
||||
vx = data.psd_x.mean()
|
||||
vy = data.psd_y.mean()
|
||||
|
@ -299,18 +338,22 @@ class ResonanceTester:
|
|||
def is_valid_name_suffix(self, name_suffix):
|
||||
return name_suffix.replace('-', '').replace('_', '').isalnum()
|
||||
|
||||
def get_filename(self, base, name_suffix, axis=None, point=None):
|
||||
def get_filename(self, base, name_suffix, axis=None,
|
||||
point=None, chip_name=None):
|
||||
name = base
|
||||
if axis:
|
||||
name += '_' + axis.get_name()
|
||||
if chip_name:
|
||||
name += '_' + chip_name.replace(" ", "_")
|
||||
if point:
|
||||
name += "_%.3f_%.3f_%.3f" % (point[0], point[1], point[2])
|
||||
name += '_' + name_suffix
|
||||
return os.path.join("/tmp", name + ".csv")
|
||||
|
||||
def save_calibration_data(self, base_name, name_suffix, shaper_calibrate,
|
||||
axis, calibration_data, all_shapers=None):
|
||||
output = self.get_filename(base_name, name_suffix, axis)
|
||||
axis, calibration_data,
|
||||
all_shapers=None, point=None):
|
||||
output = self.get_filename(base_name, name_suffix, axis, point)
|
||||
shaper_calibrate.save_calibration_data(output, calibration_data,
|
||||
all_shapers)
|
||||
return output
|
||||
|
|
Loading…
Reference in New Issue