RedBone/printer_data/config/scripts/plot_graphs.sh
2025-09-05 21:04:17 +01:00

220 lines
9.1 KiB
Bash

#!/usr/bin/env bash
###################################
###### GRAPH PLOTTING SCRIPT ######
###################################
# Written by Frix_x#0161 #
# @version: 1.6
# CHANGELOG:
# v1.6: - updated the handling of shaper graph files to be able to optionnaly account for added positions in the filenames and remove them
# - fixed a bug in the belt graph on slow SD card or Pi clones (Klipper was still writing in the file while we were already reading it)
# v1.5: fixed klipper unnexpected fail at the end of the execution, even if graphs were correctly generated (unicode decode error fixed)
# v1.4: added the ~/klipper dir parameter to the call of graph_vibrations.py for a better user handling (in case user is not "pi")
# v1.3: some documentation improvement regarding the line endings that needs to be LF for this file
# v1.2: added the movement name to be transfered to the Python script in vibration calibration (to print it on the result graphs)
# v1.1: multiple fixes and tweaks (mainly to avoid having empty files read by the python scripts after the mv command)
# v1.0: first version of the script based on a Zellneralex script
# Installation:
# 1. Copy this file somewhere in your config folder and edit the parameters below if needed
# Note: If using Windows to do the copy/paste, be careful with the line endings for this file: LF (or \n) is mandatory !!! No \r should be
# present in the file as it could lead to some errors like "\r : unknown command" when running the script. If you're not confident
# regarding your text editor behavior, the best way is to directly download the file on the pi by using for example wget:
# type 'wget -P ~/printer_data/config/scripts https://raw.githubusercontent.com/Frix-x/klippain/main/scripts/plot_graphs.sh'
# 2. Make it executable using SSH: type 'chmod +x ~/printer_data/config/scripts/plot_graphs.sh' (adjust the path if needed).
# 3. Be sure to have the gcode_shell_command.py Klipper extension installed (easiest way to install it is to use KIAUH in the Advanced section)
# 4. Create a gcode_shell_command to be able to start it from a macro (see my shell_commands.cfg file)
# Usage:
# This script was designed to be used with gcode_shell_commands. Use it to call it.
# Parameters availables:
# SHAPER - To generate input shaper diagrams after calling the Klipper TEST_RESONANCES AXIS=X/Y
# BELTS - To generate belts diagrams after calling the Klipper TEST_RESONANCES AXIS=1,(-)1 OUTPUT=raw_data
# VIBRATIONS - To generate vibration diagram after calling the custom (Frix_x#0161) VIBRATIONS_CALIBRATION macro
#################################################################################################################
RESULTS_FOLDER=/home/miguel/printer_data/config/shaper_results # Path to the folder where storing the results files
SCRIPTS_FOLDER=~/printer_data/config/scripts # Path to the folder where the graph_vibrations.py is located
KLIPPER_FOLDER=~/klipper # Path of the klipper main folder
STORE_RESULTS=3 # Number of results to keep (older files are automatically cleaned). 0 to keep them indefinitely
#################################################################################################################
#####################################################################
################ !!! DO NOT EDIT BELOW THIS LINE !!! ################
#####################################################################
export LC_ALL=C
function is_fopen() {
filepath=$(realpath "$1")
for pid in $(ls /proc | grep -E '^[0-9]+$'); do
if [ -d "/proc/$pid/fd" ]; then
for fd in /proc/$pid/fd/*; do
if [ -L "$fd" ] && [ "$(readlink -f "$fd")" == "$filepath" ]; then
return 0
fi
done
fi
done
return 1
}
function plot_shaper_graph {
local generator filename newfilename date axis
generator="${KLIPPER_FOLDER}/scripts/calibrate_shaper.py"
# For each file
while read filename; do
# Wait for the file handler to be released by Klipper
while is_fopen "${filename}"; do
sleep 3
done
# We remove the /tmp in front of the filename
newfilename="$(echo ${filename} | sed -e "s/\\/tmp\///")"
# We check if there is the position added by Klipper and remove it
if [[ ${newfilename} =~ ^resonances_[[:alpha:]]_([0-9]*\.)+[0-9]*_ ]]; then
newfilename="$(echo ${newfilename} | sed -E 's/(^resonances_[[:alpha:]])_(([0-9]*\.)+[0-9]*_)+/\1_/')"
fi
# We extract the date and axis name from the filename
date="$(basename "${newfilename}" | cut -d '.' -f1 | awk -F'_' '{print $3"_"$4}')"
axis="$(basename "${newfilename}" | cut -d '_' -f2)"
# Then we move the file to the result folder
mv "${filename}" "${isf}"/inputshaper/"${newfilename}"
sync && sleep 2
# Finally we compute the shaper graphs
"${generator}" "${isf}"/inputshaper/"${newfilename}" -o "${isf}"/inputshaper/resonances_"${axis}"_"${date}".png
done <<< "$(find /tmp -type f -name "resonances_*.csv" 2>&1 | grep -v "Permission")"
}
function plot_belts_graph {
local date_ext generator filename belt
date_ext="$(date +%Y%m%d_%H%M%S)"
generator="${KLIPPER_FOLDER}/scripts/graph_accelerometer.py"
# For each file
while read filename; do
# Wait for the file handler to be released by Klipper
while is_fopen "${filename}"; do
sleep 3
done
# We extract the belt tested from the filename
belt="$(basename "${filename}" | cut -d '_' -f4 | cut -d '.' -f1 | sed -e 's/\(.*\)/\U\1/')"
# And we move it to the result folder while injecting the date and belt inside the filename
mv "${filename}" "${isf}"/belts/belt_"${date_ext}"_"${belt}".csv
done <<< "$(find /tmp -type f -name "raw_data_axis*.csv" 2>&1 | grep -v "Permission")"
sync && sleep 2
# Finally we compute the belts graph
"${generator}" -c "${isf}"/belts/belt_"${date_ext}"_*.csv -o "${isf}"/belts/belts_"${date_ext}".png
}
function plot_vibr_graph {
local date_ext generator filename newfilename
date_ext="$(date +%Y%m%d_%H%M%S)"
generator="${SCRIPTS_FOLDER}/graph_vibrations.py"
# For each file
while read filename; do
# Wait for the file handler to be released by Klipper
while is_fopen "${filename}"; do
sleep 3
done
# Cleanup of the filename and moving it in the result folder
newfilename="$(echo ${filename} | sed -e "s/\\/tmp\/adxl345/vibr_${date_ext}/")"
mv "${filename}" "${isf}"/vibrations/"${newfilename}"
done <<< "$(find /tmp -type f -name "adxl345-*.csv" 2>&1 | grep -v "Permission")"
sync && sleep 2
# We compute the vibration graphs using all the csv files
"${generator}" "${isf}"/vibrations/vibr_"${date_ext}"*.csv -o "${isf}"/vibrations/vibrations_"${date_ext}".png -a "$1" -k "${KLIPPER_FOLDER}"
# Finally we cleanup the folder by moving the csv files in an archive
tar cfz "${isf}"/vibrations/vibrations_"${date_ext}".tar.gz "${isf}"/vibrations/vibr_"${date_ext}"*.csv
rm "${isf}"/vibrations/vibr_"${date_ext}"*.csv
}
function clean_files {
local filename keep1 keep2 old csv date
keep1=$(( ${STORE_RESULTS} + 1 ))
keep2=$(( ${STORE_RESULTS} * 2 + 1))
while read filename; do
if [ ! -z "${filename}" ]; then
old+=("${filename}")
csv="$(basename "${filename}" | cut -d '.' -f1)"
old+=("${isf}"/inputshaper/"${csv}".csv)
fi
done <<< "$(find "${isf}"/inputshaper/ -type f -name '*.png' -printf '%T@ %p\n' | sort -k 1 -n -r | sed 's/^[^ ]* //' | tail -n +"${keep2}")"
while read filename; do
if [ ! -z "${filename}" ]; then
old+=("${filename}")
date="$(basename "${filename}" | cut -d '.' -f1 | awk -F'_' '{print $2"_"$3}')"
old+=("${isf}"/belts/belt_"${date}"_A.csv)
old+=("${isf}"/belts/belt_"${date}"_B.csv)
fi
done <<< "$(find "${isf}"/belts/ -type f -name '*.png' -printf '%T@ %p\n' | sort -k 1 -n -r | sed 's/^[^ ]* //' | tail -n +"${keep1}")"
while read filename; do
if [ ! -z "${filename}" ]; then
old+=("${filename}")
csv="$(basename "${filename}" | cut -d '.' -f1)"
old+=("${isf}"/vibrations/"${csv}".tar.gz)
fi
done <<< "$(find "${isf}"/vibrations/ -type f -name '*.png' -printf '%T@ %p\n' | sort -k 1 -n -r | sed 's/^[^ ]* //' | tail -n +"${keep1}")"
if [ "${#old[@]}" -ne 0 -a "${STORE_RESULTS}" -ne 0 ]; then
for rmv in "${old[@]}"; do
rm "${rmv}"
done
fi
}
#############################
### MAIN ####################
#############################
if [ ! -d "${RESULTS_FOLDER}/inputshaper" ]; then
mkdir -p "${RESULTS_FOLDER}/inputshaper"
fi
if [ ! -d "${RESULTS_FOLDER}/belts" ]; then
mkdir -p "${RESULTS_FOLDER}/belts"
fi
if [ ! -d "${RESULTS_FOLDER}/vibrations" ]; then
mkdir -p "${RESULTS_FOLDER}/vibrations"
fi
isf="${RESULTS_FOLDER//\~/${HOME}}"
case ${1} in
SHAPER|shaper)
plot_shaper_graph
;;
BELTS|belts)
plot_belts_graph
;;
VIBRATIONS|vibrations)
plot_vibr_graph ${2}
;;
*)
echo -e "\nUsage:"
echo -e "\t${0} SHAPER, BELTS or VIBRATIONS"
echo -e "\t\tSHAPER\tGenerate input shaper diagram"
echo -e "\t\tBELT\tGenerate belt tension diagram"
echo -e "\t\tVIBRATIONS axis-name\tGenerate vibration response diagram\n"
exit 1
esac
clean_files
echo "Graphs created. You will find the results in ${isf}"