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
|
||||||
`TEST_RESONANCES AXIS=<axis> OUTPUT=<resonances,raw_data>
|
`TEST_RESONANCES AXIS=<axis> OUTPUT=<resonances,raw_data>
|
||||||
[NAME=<name>] [FREQ_START=<min_freq>] [FREQ_END=<max_freq>]
|
[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
|
test in all configured probe points for the requested "axis" and
|
||||||
measures the acceleration using the accelerometer chips configured for
|
measures the acceleration using the accelerometer chips configured for
|
||||||
the respective axis. "axis" can either be X or Y, or specify an
|
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
|
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
|
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`
|
`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
|
and `AXIS=-dx,-dy` is equivalent. `adxl345_chip_name` can be one or
|
||||||
(default), disables input shaping for the resonance testing, because
|
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
|
it is not valid to run the resonance testing with the input shaper
|
||||||
enabled. `OUTPUT` parameter is a comma-separated list of which outputs
|
enabled. `OUTPUT` parameter is a comma-separated list of which outputs
|
||||||
will be written. If `raw_data` is requested, then the raw
|
will be written. If `raw_data` is requested, then the raw
|
||||||
accelerometer data is written into a file or a series of files
|
accelerometer data is written into a file or a series of files
|
||||||
`/tmp/raw_data_<axis>_[<point>_]<name>.csv` with (`<point>_` part of
|
`/tmp/raw_data_<axis>_[<chip_name>_][<point>_]<name>.csv` with
|
||||||
the name generated only if more than 1 probe point is configured). If
|
(`<point>_` part of the name generated only if more than 1 probe point
|
||||||
`resonances` is specified, the frequency response is calculated
|
is configured or POINT is specified). If `resonances` is specified, the
|
||||||
(across all probe points) and written into
|
frequency response is calculated (across all probe points) and written into
|
||||||
`/tmp/resonances_<axis>_<name>.csv` file. If unset, OUTPUT defaults to
|
`/tmp/resonances_<axis>_<name>.csv` file. If unset, OUTPUT defaults to
|
||||||
`resonances`, and NAME defaults to the current time in
|
`resonances`, and NAME defaults to the current time in
|
||||||
"YYYYMMDD_HHMMSS" format.
|
"YYYYMMDD_HHMMSS" format.
|
||||||
|
|
|
@ -147,15 +147,21 @@ class ResonanceTester:
|
||||||
(chip_axis, self.printer.lookup_object(chip_name))
|
(chip_axis, self.printer.lookup_object(chip_name))
|
||||||
for chip_axis, chip_name in self.accel_chip_names]
|
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')
|
toolhead = self.printer.lookup_object('toolhead')
|
||||||
calibration_data = {axis: None for axis in axes}
|
calibration_data = {axis: None for axis in axes}
|
||||||
|
|
||||||
self.test.prepare_test(gcmd)
|
self.test.prepare_test(gcmd)
|
||||||
|
|
||||||
|
if test_point is not None:
|
||||||
|
test_points = [test_point]
|
||||||
|
else:
|
||||||
test_points = self.test.get_start_test_points()
|
test_points = self.test.get_start_test_points()
|
||||||
|
|
||||||
for point in test_points:
|
for point in test_points:
|
||||||
toolhead.manual_move(point, self.move_speed)
|
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(
|
gcmd.respond_info(
|
||||||
"Probing point (%.3f, %.3f, %.3f)" % tuple(point))
|
"Probing point (%.3f, %.3f, %.3f)" % tuple(point))
|
||||||
for axis in axes:
|
for axis in axes:
|
||||||
|
@ -165,29 +171,36 @@ class ResonanceTester:
|
||||||
gcmd.respond_info("Testing axis %s" % axis.get_name())
|
gcmd.respond_info("Testing axis %s" % axis.get_name())
|
||||||
|
|
||||||
raw_values = []
|
raw_values = []
|
||||||
|
if accel_chips is None:
|
||||||
for chip_axis, chip in self.accel_chips:
|
for chip_axis, chip in self.accel_chips:
|
||||||
if axis.matches(chip_axis):
|
if axis.matches(chip_axis):
|
||||||
aclient = chip.start_internal_client()
|
aclient = chip.start_internal_client()
|
||||||
raw_values.append((chip_axis, aclient))
|
raw_values.append((chip_axis, aclient, chip.name))
|
||||||
|
else:
|
||||||
|
for chip in accel_chips:
|
||||||
|
aclient = chip.start_internal_client()
|
||||||
|
raw_values.append((axis, aclient, chip.name))
|
||||||
|
|
||||||
# Generate moves
|
# Generate moves
|
||||||
self.test.run_test(axis, gcmd)
|
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()
|
aclient.finish_measurements()
|
||||||
if raw_name_suffix is not None:
|
if raw_name_suffix is not None:
|
||||||
raw_name = self.get_filename(
|
raw_name = self.get_filename(
|
||||||
'raw_data', raw_name_suffix, axis,
|
'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)
|
aclient.write_to_file(raw_name)
|
||||||
gcmd.respond_info(
|
gcmd.respond_info(
|
||||||
"Writing raw accelerometer data to "
|
"Writing raw accelerometer data to "
|
||||||
"%s file" % (raw_name,))
|
"%s file" % (raw_name,))
|
||||||
if helper is None:
|
if helper is None:
|
||||||
continue
|
continue
|
||||||
for chip_axis, aclient in raw_values:
|
for chip_axis, aclient, chip_name in raw_values:
|
||||||
if not aclient.has_valid_samples():
|
if not aclient.has_valid_samples():
|
||||||
raise gcmd.error(
|
raise gcmd.error(
|
||||||
"%s-axis accelerometer measured no data" % (
|
"accelerometer '%s' measured no data" % (
|
||||||
chip_axis,))
|
chip_name,))
|
||||||
new_data = helper.process_accelerometer_data(aclient)
|
new_data = helper.process_accelerometer_data(aclient)
|
||||||
if calibration_data[axis] is None:
|
if calibration_data[axis] is None:
|
||||||
calibration_data[axis] = new_data
|
calibration_data[axis] = new_data
|
||||||
|
@ -198,6 +211,28 @@ class ResonanceTester:
|
||||||
def cmd_TEST_RESONANCES(self, gcmd):
|
def cmd_TEST_RESONANCES(self, gcmd):
|
||||||
# Parse parameters
|
# Parse parameters
|
||||||
axis = _parse_axis(gcmd, gcmd.get("AXIS").lower())
|
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(',')
|
outputs = gcmd.get("OUTPUT", "resonances").lower().split(',')
|
||||||
for output in outputs:
|
for output in outputs:
|
||||||
|
@ -221,10 +256,13 @@ class ResonanceTester:
|
||||||
|
|
||||||
data = self._run_test(
|
data = self._run_test(
|
||||||
gcmd, [axis], helper,
|
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:
|
if csv_output:
|
||||||
csv_name = self.save_calibration_data('resonances', name_suffix,
|
csv_name = self.save_calibration_data('resonances', name_suffix,
|
||||||
helper, axis, data)
|
helper, axis, data,
|
||||||
|
point=test_point)
|
||||||
gcmd.respond_info(
|
gcmd.respond_info(
|
||||||
"Resonances data written to %s file" % (csv_name,))
|
"Resonances data written to %s file" % (csv_name,))
|
||||||
cmd_SHAPER_CALIBRATE_help = (
|
cmd_SHAPER_CALIBRATE_help = (
|
||||||
|
@ -287,7 +325,8 @@ class ResonanceTester:
|
||||||
for chip_axis, aclient in raw_values:
|
for chip_axis, aclient in raw_values:
|
||||||
if not aclient.has_valid_samples():
|
if not aclient.has_valid_samples():
|
||||||
raise gcmd.error(
|
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)
|
data = helper.process_accelerometer_data(aclient)
|
||||||
vx = data.psd_x.mean()
|
vx = data.psd_x.mean()
|
||||||
vy = data.psd_y.mean()
|
vy = data.psd_y.mean()
|
||||||
|
@ -299,18 +338,22 @@ class ResonanceTester:
|
||||||
def is_valid_name_suffix(self, name_suffix):
|
def is_valid_name_suffix(self, name_suffix):
|
||||||
return name_suffix.replace('-', '').replace('_', '').isalnum()
|
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
|
name = base
|
||||||
if axis:
|
if axis:
|
||||||
name += '_' + axis.get_name()
|
name += '_' + axis.get_name()
|
||||||
|
if chip_name:
|
||||||
|
name += '_' + chip_name.replace(" ", "_")
|
||||||
if point:
|
if point:
|
||||||
name += "_%.3f_%.3f_%.3f" % (point[0], point[1], point[2])
|
name += "_%.3f_%.3f_%.3f" % (point[0], point[1], point[2])
|
||||||
name += '_' + name_suffix
|
name += '_' + name_suffix
|
||||||
return os.path.join("/tmp", name + ".csv")
|
return os.path.join("/tmp", name + ".csv")
|
||||||
|
|
||||||
def save_calibration_data(self, base_name, name_suffix, shaper_calibrate,
|
def save_calibration_data(self, base_name, name_suffix, shaper_calibrate,
|
||||||
axis, calibration_data, all_shapers=None):
|
axis, calibration_data,
|
||||||
output = self.get_filename(base_name, name_suffix, axis)
|
all_shapers=None, point=None):
|
||||||
|
output = self.get_filename(base_name, name_suffix, axis, point)
|
||||||
shaper_calibrate.save_calibration_data(output, calibration_data,
|
shaper_calibrate.save_calibration_data(output, calibration_data,
|
||||||
all_shapers)
|
all_shapers)
|
||||||
return output
|
return output
|
||||||
|
|
Loading…
Reference in New Issue