added thousands notation and fixing latex
This commit is contained in:
parent
bd51824bd5
commit
9ccf422c4a
263
main.py
263
main.py
|
|
@ -9,12 +9,14 @@ import math
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from math import gcd
|
from math import gcd
|
||||||
|
|
||||||
import streamlit as st
|
import streamlit as st
|
||||||
|
|
||||||
# Optional PDF export (reportlab is installed in your environment)
|
# Optional PDF export (reportlab is installed in your environment)
|
||||||
try:
|
try:
|
||||||
from reportlab.lib.pagesizes import A4
|
from reportlab.lib.pagesizes import A4
|
||||||
from reportlab.pdfgen import canvas
|
from reportlab.pdfgen import canvas
|
||||||
|
|
||||||
REPORTLAB_OK = True
|
REPORTLAB_OK = True
|
||||||
except Exception:
|
except Exception:
|
||||||
REPORTLAB_OK = False
|
REPORTLAB_OK = False
|
||||||
|
|
@ -73,10 +75,109 @@ def clamp_float(x: float, lo: float, hi: float) -> float:
|
||||||
return max(lo, min(hi, x))
|
return max(lo, min(hi, x))
|
||||||
|
|
||||||
|
|
||||||
|
# ---- SI-style numeric input (Slovenia formatting) ----
|
||||||
|
def format_si_number(x: float, decimals: int = 0) -> str:
|
||||||
|
"""Format number like 360.000 (thousands='.', decimal=',')."""
|
||||||
|
if x is None:
|
||||||
|
return ""
|
||||||
|
sign = "-" if x < 0 else ""
|
||||||
|
x = abs(float(x))
|
||||||
|
|
||||||
|
p = 10 ** decimals
|
||||||
|
x = round(x * p) / p
|
||||||
|
|
||||||
|
int_part = int(x)
|
||||||
|
frac_part = x - int_part
|
||||||
|
|
||||||
|
int_str = f"{int_part:,}".replace(",", ".") # thousands
|
||||||
|
if decimals <= 0:
|
||||||
|
return f"{sign}{int_str}"
|
||||||
|
|
||||||
|
frac_str = f"{frac_part:.{decimals}f}".split(".")[1]
|
||||||
|
return f"{sign}{int_str},{frac_str}"
|
||||||
|
|
||||||
|
|
||||||
|
def parse_si_number(s: str, allow_float: bool = True) -> float:
|
||||||
|
"""
|
||||||
|
Accept:
|
||||||
|
360000
|
||||||
|
360.000
|
||||||
|
360 000
|
||||||
|
360.000,25
|
||||||
|
360000.25
|
||||||
|
"""
|
||||||
|
if s is None:
|
||||||
|
raise ValueError("Empty")
|
||||||
|
t = s.strip().replace(" ", "")
|
||||||
|
if t == "":
|
||||||
|
raise ValueError("Empty")
|
||||||
|
|
||||||
|
if "," in t:
|
||||||
|
# decimal comma -> remove thousands '.' and convert comma to '.'
|
||||||
|
t = t.replace(".", "")
|
||||||
|
t = t.replace(",", ".")
|
||||||
|
else:
|
||||||
|
# no comma: dot might be thousands or decimal
|
||||||
|
if "." in t:
|
||||||
|
last = t.split(".")[-1]
|
||||||
|
if len(last) == 3 and last.isdigit():
|
||||||
|
t = t.replace(".", "") # thousands separators
|
||||||
|
# else keep '.' as decimal point
|
||||||
|
|
||||||
|
val = float(t)
|
||||||
|
if not allow_float and abs(val - int(val)) > 1e-12:
|
||||||
|
raise ValueError("Integer required")
|
||||||
|
return float(int(val)) if not allow_float else val
|
||||||
|
|
||||||
|
|
||||||
|
def si_number_input(
|
||||||
|
label: str,
|
||||||
|
key: str,
|
||||||
|
value: float,
|
||||||
|
decimals: int = 0,
|
||||||
|
allow_float: bool = False,
|
||||||
|
min_value: float | None = None,
|
||||||
|
help: str | None = None,
|
||||||
|
):
|
||||||
|
txt_key = f"{key}__txt"
|
||||||
|
err_key = f"{key}__err"
|
||||||
|
|
||||||
|
# init state
|
||||||
|
if key not in st.session_state:
|
||||||
|
st.session_state[key] = value
|
||||||
|
if txt_key not in st.session_state:
|
||||||
|
st.session_state[txt_key] = format_si_number(value, decimals)
|
||||||
|
if err_key not in st.session_state:
|
||||||
|
st.session_state[err_key] = ""
|
||||||
|
|
||||||
|
def _commit():
|
||||||
|
raw = st.session_state.get(txt_key, "")
|
||||||
|
try:
|
||||||
|
v = parse_si_number(raw, allow_float=allow_float)
|
||||||
|
if min_value is not None and v < min_value:
|
||||||
|
raise ValueError(f"Must be ≥ {min_value}")
|
||||||
|
|
||||||
|
st.session_state[key] = v
|
||||||
|
st.session_state[err_key] = ""
|
||||||
|
|
||||||
|
# ✅ normalize display to SI formatting
|
||||||
|
st.session_state[txt_key] = format_si_number(v, decimals)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
st.session_state[err_key] = str(e)
|
||||||
|
|
||||||
|
st.text_input(label, key=txt_key, help=help, on_change=_commit)
|
||||||
|
|
||||||
|
# show error (if any)
|
||||||
|
if st.session_state.get(err_key):
|
||||||
|
st.error(f"Invalid number for '{label}': {st.session_state[err_key]}")
|
||||||
|
|
||||||
|
return st.session_state[key]
|
||||||
|
|
||||||
def build_markdown_report(data: dict) -> str:
|
def build_markdown_report(data: dict) -> str:
|
||||||
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
lines = []
|
lines = []
|
||||||
lines.append(f"# Delta ASDA-A2 Commissioning Report")
|
lines.append("# Delta ASDA-A2 Commissioning Report")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append(f"- Generated: **{ts}**")
|
lines.append(f"- Generated: **{ts}**")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
@ -144,7 +245,6 @@ def markdown_to_pdf_bytes(title: str, md_text: str) -> bytes:
|
||||||
y = height - margin
|
y = height - margin
|
||||||
|
|
||||||
for raw in md_text.splitlines():
|
for raw in md_text.splitlines():
|
||||||
# simple wrap
|
|
||||||
line = raw.rstrip("\n")
|
line = raw.rstrip("\n")
|
||||||
if not line:
|
if not line:
|
||||||
y -= line_height
|
y -= line_height
|
||||||
|
|
@ -152,7 +252,7 @@ def markdown_to_pdf_bytes(title: str, md_text: str) -> bytes:
|
||||||
new_page()
|
new_page()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
chunks = [line[i:i + max_width_chars] for i in range(0, len(line), max_width_chars)]
|
chunks = [line[i : i + max_width_chars] for i in range(0, len(line), max_width_chars)]
|
||||||
for chunk in chunks:
|
for chunk in chunks:
|
||||||
c.drawString(margin, y, chunk)
|
c.drawString(margin, y, chunk)
|
||||||
y -= line_height
|
y -= line_height
|
||||||
|
|
@ -340,7 +440,6 @@ def template_blocks() -> dict[str, list[str]]:
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
st.set_page_config(page_title="Delta ASDA-A2 Engineering Tool", layout="wide")
|
st.set_page_config(page_title="Delta ASDA-A2 Engineering Tool", layout="wide")
|
||||||
|
|
||||||
# default session values
|
|
||||||
defaults = {
|
defaults = {
|
||||||
"motor_counts_per_rev": 128000.0,
|
"motor_counts_per_rev": 128000.0,
|
||||||
"gear_ratio": 50.0,
|
"gear_ratio": 50.0,
|
||||||
|
|
@ -350,8 +449,8 @@ defaults = {
|
||||||
"pulley_circum_mm": 100.0,
|
"pulley_circum_mm": 100.0,
|
||||||
"controller_pulses_per_unit": 1.0,
|
"controller_pulses_per_unit": 1.0,
|
||||||
"ratio_limit": 2_147_483_647,
|
"ratio_limit": 2_147_483_647,
|
||||||
"delta_min_ratio": 1.0 / 50.0, # you referenced 1/50
|
"delta_min_ratio": 1.0 / 50.0, # you referenced 1/50
|
||||||
"delta_max_ratio": 25600.0, # you referenced 25600
|
"delta_max_ratio": 25600.0, # you referenced 25600
|
||||||
"smooth_min_counts_per_user_unit": 5000.0,
|
"smooth_min_counts_per_user_unit": 5000.0,
|
||||||
"motor_rated_rpm": 3000.0,
|
"motor_rated_rpm": 3000.0,
|
||||||
"motor_rated_torque_nm": 1.27,
|
"motor_rated_torque_nm": 1.27,
|
||||||
|
|
@ -379,44 +478,56 @@ page = st.sidebar.radio(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Global reset
|
|
||||||
with st.sidebar:
|
with st.sidebar:
|
||||||
if st.button("Reset all inputs"):
|
if st.button("Reset all inputs"):
|
||||||
|
# reset numeric values
|
||||||
for k, v in defaults.items():
|
for k, v in defaults.items():
|
||||||
st.session_state[k] = v
|
st.session_state[k] = v
|
||||||
|
# reset text inputs used by si_number_input
|
||||||
|
for k in list(st.session_state.keys()):
|
||||||
|
if k.endswith("__txt"):
|
||||||
|
del st.session_state[k]
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
# Pages
|
# Pages
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
if page == "Theory & Architecture":
|
if page == "Theory & Architecture":
|
||||||
st.title("📚 Theory & Architecture")
|
st.title("📚 Theory & Architecture")
|
||||||
|
|
||||||
|
st.markdown("### What this tool does")
|
||||||
|
st.write(
|
||||||
|
"Helps you set **electronic gearing (PUU / P1-44 & P1-45)** and perform quick "
|
||||||
|
"**speed/torque sanity checks** for gearbox systems."
|
||||||
|
)
|
||||||
|
|
||||||
|
st.markdown("### Core equation")
|
||||||
|
st.latex(r"\text{Motor encoder counts} = \text{Command pulses} \times \frac{P1\text{-}44}{P1\text{-}45}")
|
||||||
|
|
||||||
|
st.markdown("### With a gearbox")
|
||||||
st.markdown(
|
st.markdown(
|
||||||
r"""
|
"- Motor counts per **load revolution** = (motor counts / motor rev) × (gear ratio)\n"
|
||||||
This tool helps you set up **electronic gearing (PUU / P1-44 & P1-45)** and speed/torque safety checks for gearbox systems.
|
"- Choose **user units per load revolution** (example: **360** for degrees)\n"
|
||||||
|
"- Include **controller pulses per user unit** if your controller scales commands"
|
||||||
|
)
|
||||||
|
st.latex(
|
||||||
|
r"\frac{P1\text{-}44}{P1\text{-}45}="
|
||||||
|
r"\frac{\text{motor counts per load rev}}{\text{units per load rev}\times\text{controller pulses per unit}}"
|
||||||
|
)
|
||||||
|
|
||||||
### Core equation
|
st.markdown("### What “smoothness” means (practically)")
|
||||||
\[
|
st.write(
|
||||||
\text{Motor encoder counts} = \text{Command pulses} \times \frac{P1-44}{P1-45}
|
"If **counts per user unit** is too low, motion can feel “steppy” at low speed. "
|
||||||
\]
|
"This app shows **counts/user-unit** and warns if you drop below your threshold."
|
||||||
|
)
|
||||||
### With a gearbox
|
st.info(
|
||||||
- Motor counts per **load revolution** = (motor counts / motor rev) × (gear ratio)
|
"Tip: If you command in **degrees**, 360 units/rev is a clean choice. "
|
||||||
- Choose user units per load revolution (e.g. **360 for degrees**)
|
"If ratio becomes too large/small, scale units (e.g., 0.1° or 0.01°)."
|
||||||
|
|
||||||
\[
|
|
||||||
\frac{P1-44}{P1-45} = \frac{\text{motor counts per load rev}}{\text{units per load rev}\times\text{controller pulses per unit}}
|
|
||||||
\]
|
|
||||||
|
|
||||||
### What “smoothness” really means
|
|
||||||
A good rule of thumb is keeping **counts per user unit** high enough to avoid coarse stepping at low speed.
|
|
||||||
This app shows **counts per user unit** and warns you if it drops below your chosen minimum.
|
|
||||||
"""
|
|
||||||
)
|
)
|
||||||
|
|
||||||
elif page == "PUU Calculator":
|
elif page == "PUU Calculator":
|
||||||
st.title("🔢 Universal PUU Calculator (P1-44 / P1-45)")
|
st.title("🔢 Universal PUU Calculator (P1-44 / P1-45)")
|
||||||
|
|
||||||
st.caption(
|
st.caption(
|
||||||
"Compute electronic gearing for Delta ASDA-A2. Includes presets, exact vs drive-friendly fraction, and validations."
|
"Compute electronic gearing for Delta ASDA-A2. Includes presets, exact vs drive-friendly fraction, and validations."
|
||||||
)
|
)
|
||||||
|
|
@ -426,14 +537,18 @@ elif page == "PUU Calculator":
|
||||||
with col1:
|
with col1:
|
||||||
st.subheader("Input")
|
st.subheader("Input")
|
||||||
|
|
||||||
st.session_state.motor_counts_per_rev = st.number_input(
|
# BIG numbers => SI formatting (360.000 style)
|
||||||
|
st.session_state.motor_counts_per_rev = si_number_input(
|
||||||
"Motor encoder counts per motor revolution",
|
"Motor encoder counts per motor revolution",
|
||||||
min_value=1.0,
|
key="motor_counts_per_rev",
|
||||||
value=float(st.session_state.motor_counts_per_rev),
|
value=float(st.session_state.motor_counts_per_rev),
|
||||||
step=1000.0,
|
decimals=0,
|
||||||
|
allow_float=False,
|
||||||
|
min_value=1,
|
||||||
help="Examples: 128000, 131072, 1048576 (depends on encoder + drive setting).",
|
help="Examples: 128000, 131072, 1048576 (depends on encoder + drive setting).",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Smaller engineering values can remain number_input
|
||||||
st.session_state.gear_ratio = st.number_input(
|
st.session_state.gear_ratio = st.number_input(
|
||||||
"Gear ratio (motor rev per load rev)",
|
"Gear ratio (motor rev per load rev)",
|
||||||
min_value=0.0001,
|
min_value=0.0001,
|
||||||
|
|
@ -483,12 +598,16 @@ elif page == "PUU Calculator":
|
||||||
)
|
)
|
||||||
st.session_state.units_per_load_rev = float(st.session_state.pulley_circum_mm)
|
st.session_state.units_per_load_rev = float(st.session_state.pulley_circum_mm)
|
||||||
else:
|
else:
|
||||||
st.session_state.units_per_load_rev = st.number_input(
|
st.session_state.units_per_load_rev = si_number_input(
|
||||||
"User units per load revolution",
|
"User units per load revolution",
|
||||||
min_value=0.0001,
|
key="units_per_load_rev",
|
||||||
value=float(st.session_state.units_per_load_rev),
|
value=float(st.session_state.units_per_load_rev),
|
||||||
step=1.0,
|
|
||||||
)
|
decimals=0, # <-- shows 360 or 360.000, never 360.00
|
||||||
|
allow_float=False, # <-- integer only (degrees etc.)
|
||||||
|
min_value=1,
|
||||||
|
help="Example: 360 for degrees. You may type 360000 or 360.000 (same).",
|
||||||
|
)
|
||||||
|
|
||||||
st.session_state.controller_pulses_per_unit = st.number_input(
|
st.session_state.controller_pulses_per_unit = st.number_input(
|
||||||
"Controller command pulses per user unit",
|
"Controller command pulses per user unit",
|
||||||
|
|
@ -498,11 +617,14 @@ elif page == "PUU Calculator":
|
||||||
help="If 1 pulse = 1 user unit, keep 1. If 10 pulses per degree, enter 10.",
|
help="If 1 pulse = 1 user unit, keep 1. If 10 pulses per degree, enter 10.",
|
||||||
)
|
)
|
||||||
|
|
||||||
st.session_state.ratio_limit = st.number_input(
|
# BIG integer => SI formatting
|
||||||
|
st.session_state.ratio_limit = si_number_input(
|
||||||
"Max integer limit for P1-44 / P1-45 (safety)",
|
"Max integer limit for P1-44 / P1-45 (safety)",
|
||||||
|
key="ratio_limit",
|
||||||
|
value=float(st.session_state.ratio_limit),
|
||||||
|
decimals=0,
|
||||||
|
allow_float=False,
|
||||||
min_value=1000,
|
min_value=1000,
|
||||||
value=int(st.session_state.ratio_limit),
|
|
||||||
step=1000,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
with st.expander("Delta A2 ratio limits (editable)"):
|
with st.expander("Delta A2 ratio limits (editable)"):
|
||||||
|
|
@ -530,24 +652,24 @@ elif page == "PUU Calculator":
|
||||||
)
|
)
|
||||||
|
|
||||||
# Compute PUU
|
# Compute PUU
|
||||||
motor_counts_per_load_rev = st.session_state.motor_counts_per_rev * st.session_state.gear_ratio
|
motor_counts_per_load_rev = float(st.session_state.motor_counts_per_rev) * float(st.session_state.gear_ratio)
|
||||||
denom_units = st.session_state.units_per_load_rev * st.session_state.controller_pulses_per_unit
|
denom_units = float(st.session_state.units_per_load_rev) * float(st.session_state.controller_pulses_per_unit)
|
||||||
target_ratio = motor_counts_per_load_rev / denom_units
|
target_ratio = motor_counts_per_load_rev / denom_units
|
||||||
|
|
||||||
try:
|
try:
|
||||||
puu = compute_puu(
|
puu = compute_puu(
|
||||||
motor_counts_per_rev=st.session_state.motor_counts_per_rev,
|
motor_counts_per_rev=float(st.session_state.motor_counts_per_rev),
|
||||||
gear_ratio=st.session_state.gear_ratio,
|
gear_ratio=float(st.session_state.gear_ratio),
|
||||||
units_per_load_rev=st.session_state.units_per_load_rev,
|
units_per_load_rev=float(st.session_state.units_per_load_rev),
|
||||||
controller_pulses_per_unit=st.session_state.controller_pulses_per_unit,
|
controller_pulses_per_unit=float(st.session_state.controller_pulses_per_unit),
|
||||||
ratio_limit=int(st.session_state.ratio_limit),
|
ratio_limit=int(st.session_state.ratio_limit),
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
st.error(f"PUU computation error: {e}")
|
st.error(f"PUU computation error: {e}")
|
||||||
st.stop()
|
st.stop()
|
||||||
|
|
||||||
counts_per_user_unit_load = motor_counts_per_load_rev / st.session_state.units_per_load_rev
|
counts_per_user_unit_load = motor_counts_per_load_rev / float(st.session_state.units_per_load_rev)
|
||||||
units_per_motor_rev = st.session_state.units_per_load_rev / st.session_state.gear_ratio
|
units_per_motor_rev = float(st.session_state.units_per_load_rev) / float(st.session_state.gear_ratio)
|
||||||
|
|
||||||
validations = validate_delta_limits(
|
validations = validate_delta_limits(
|
||||||
ratio=puu.chosen_ratio,
|
ratio=puu.chosen_ratio,
|
||||||
|
|
@ -561,7 +683,6 @@ elif page == "PUU Calculator":
|
||||||
with col2:
|
with col2:
|
||||||
st.subheader("Result")
|
st.subheader("Result")
|
||||||
|
|
||||||
# Headline metrics
|
|
||||||
m1, m2, m3 = st.columns(3)
|
m1, m2, m3 = st.columns(3)
|
||||||
m1.metric("P1-44 (N)", f"{puu.n_final}")
|
m1.metric("P1-44 (N)", f"{puu.n_final}")
|
||||||
m2.metric("P1-45 (M)", f"{puu.d_final}")
|
m2.metric("P1-45 (M)", f"{puu.d_final}")
|
||||||
|
|
@ -579,17 +700,17 @@ elif page == "PUU Calculator":
|
||||||
|
|
||||||
st.markdown("### Sanity checks")
|
st.markdown("### Sanity checks")
|
||||||
st.write(f"- Motor counts per **load rev**: **{motor_counts_per_load_rev:.3f}**")
|
st.write(f"- Motor counts per **load rev**: **{motor_counts_per_load_rev:.3f}**")
|
||||||
st.write(f"- User units per **load rev**: **{st.session_state.units_per_load_rev:.6f}**")
|
st.write(f"- User units per **load rev**: **{float(st.session_state.units_per_load_rev):.6f}**")
|
||||||
st.write(f"- Counts per **user unit** (load side): **{counts_per_user_unit_load:.3f}**")
|
st.write(f"- Counts per **user unit** (load side): **{counts_per_user_unit_load:.3f}**")
|
||||||
st.write(f"- User units per **motor rev**: **{units_per_motor_rev:.6f}**")
|
st.write(f"- User units per **motor rev**: **{units_per_motor_rev:.6f}**")
|
||||||
|
|
||||||
if counts_per_user_unit_load >= st.session_state.smooth_min_counts_per_user_unit:
|
if counts_per_user_unit_load >= float(st.session_state.smooth_min_counts_per_user_unit):
|
||||||
st.success(
|
st.success(
|
||||||
f"Smoothness OK: counts/user-unit = {counts_per_user_unit_load:.1f} ≥ {st.session_state.smooth_min_counts_per_user_unit:.1f}"
|
f"Smoothness OK: counts/user-unit = {counts_per_user_unit_load:.1f} ≥ {float(st.session_state.smooth_min_counts_per_user_unit):.1f}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
st.warning(
|
st.warning(
|
||||||
f"Low smoothness: counts/user-unit = {counts_per_user_unit_load:.1f} < {st.session_state.smooth_min_counts_per_user_unit:.1f}. "
|
f"Low smoothness: counts/user-unit = {counts_per_user_unit_load:.1f} < {float(st.session_state.smooth_min_counts_per_user_unit):.1f}. "
|
||||||
"Consider increasing counts per unit (e.g., change pulses/unit, change unit scaling)."
|
"Consider increasing counts per unit (e.g., change pulses/unit, change unit scaling)."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -602,8 +723,11 @@ elif page == "PUU Calculator":
|
||||||
else:
|
else:
|
||||||
st.success(v)
|
st.success(v)
|
||||||
|
|
||||||
# Suggestions if out-of-range
|
sugg = suggestions_if_out_of_range(
|
||||||
sugg = suggestions_if_out_of_range(puu.chosen_ratio, st.session_state.delta_min_ratio, st.session_state.delta_max_ratio)
|
puu.chosen_ratio,
|
||||||
|
float(st.session_state.delta_min_ratio),
|
||||||
|
float(st.session_state.delta_max_ratio),
|
||||||
|
)
|
||||||
if sugg:
|
if sugg:
|
||||||
st.markdown("### Fix suggestions")
|
st.markdown("### Fix suggestions")
|
||||||
for s in sugg:
|
for s in sugg:
|
||||||
|
|
@ -611,7 +735,6 @@ elif page == "PUU Calculator":
|
||||||
|
|
||||||
st.divider()
|
st.divider()
|
||||||
|
|
||||||
# Copy-to-clipboard (simple HTML button)
|
|
||||||
st.markdown("### Quick copy")
|
st.markdown("### Quick copy")
|
||||||
txt = f"P1-44={puu.n_final}, P1-45={puu.d_final}"
|
txt = f"P1-44={puu.n_final}, P1-45={puu.d_final}"
|
||||||
st.code(txt)
|
st.code(txt)
|
||||||
|
|
@ -627,7 +750,6 @@ elif page == "PUU Calculator":
|
||||||
|
|
||||||
elif page == "Speed Translator":
|
elif page == "Speed Translator":
|
||||||
st.title("⚡ Speed Translator (Motor ↔ Gearbox ↔ Load ↔ User Units)")
|
st.title("⚡ Speed Translator (Motor ↔ Gearbox ↔ Load ↔ User Units)")
|
||||||
|
|
||||||
st.caption("Convert between motor RPM, load RPM, and user units/s based on gearbox and unit definition.")
|
st.caption("Convert between motor RPM, load RPM, and user units/s based on gearbox and unit definition.")
|
||||||
|
|
||||||
col1, col2 = st.columns(2)
|
col1, col2 = st.columns(2)
|
||||||
|
|
@ -642,11 +764,14 @@ elif page == "Speed Translator":
|
||||||
step=1.0,
|
step=1.0,
|
||||||
)
|
)
|
||||||
|
|
||||||
st.session_state.units_per_load_rev = st.number_input(
|
st.session_state.units_per_load_rev = si_number_input(
|
||||||
"User units per load revolution",
|
"User units per load revolution",
|
||||||
min_value=0.0001,
|
key="units_per_load_rev",
|
||||||
value=float(st.session_state.units_per_load_rev),
|
value=float(st.session_state.units_per_load_rev),
|
||||||
step=1.0,
|
decimals=0, # <-- shows 360 or 360.000, never 360.00
|
||||||
|
allow_float=False, # <-- integer only (degrees etc.)
|
||||||
|
min_value=1,
|
||||||
|
help="Example: 360 for degrees. You may type 360000 or 360.000 (same).",
|
||||||
)
|
)
|
||||||
|
|
||||||
st.session_state.motor_rated_rpm = st.number_input(
|
st.session_state.motor_rated_rpm = st.number_input(
|
||||||
|
|
@ -699,16 +824,13 @@ elif page == "Speed Translator":
|
||||||
st.write(f"- Load RPS: **{speed['Load RPS']:.4f}**")
|
st.write(f"- Load RPS: **{speed['Load RPS']:.4f}**")
|
||||||
st.write(f"- User units/min: **{speed['User units / min']:.3f}**")
|
st.write(f"- User units/min: **{speed['User units / min']:.3f}**")
|
||||||
|
|
||||||
if speed["Motor RPM"] > st.session_state.motor_rated_rpm:
|
if speed["Motor RPM"] > float(st.session_state.motor_rated_rpm):
|
||||||
st.error(
|
st.error(f"❌ Motor RPM exceeds rated RPM: {speed['Motor RPM']:.1f} > {float(st.session_state.motor_rated_rpm):.1f}")
|
||||||
f"❌ Motor RPM exceeds rated RPM: {speed['Motor RPM']:.1f} > {st.session_state.motor_rated_rpm:.1f}"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
st.success("✅ Motor RPM within rated RPM.")
|
st.success("✅ Motor RPM within rated RPM.")
|
||||||
|
|
||||||
elif page == "Torque Estimator":
|
elif page == "Torque Estimator":
|
||||||
st.title("🧲 Torque Estimator (Gearbox Amplification)")
|
st.title("🧲 Torque Estimator (Gearbox Amplification)")
|
||||||
|
|
||||||
st.caption("Quick estimator: output torque ≈ motor torque × gear ratio × efficiency.")
|
st.caption("Quick estimator: output torque ≈ motor torque × gear ratio × efficiency.")
|
||||||
|
|
||||||
col1, col2 = st.columns(2)
|
col1, col2 = st.columns(2)
|
||||||
|
|
@ -754,9 +876,7 @@ elif page == "Torque Estimator":
|
||||||
m1.metric("Output rated torque (Nm)", f"{tor['Estimated output rated torque (Nm)']:.2f}")
|
m1.metric("Output rated torque (Nm)", f"{tor['Estimated output rated torque (Nm)']:.2f}")
|
||||||
m2.metric("Output peak torque (Nm)", f"{tor['Estimated output peak torque (Nm)']:.2f}")
|
m2.metric("Output peak torque (Nm)", f"{tor['Estimated output peak torque (Nm)']:.2f}")
|
||||||
|
|
||||||
st.info(
|
st.info("Safety tip: during first tests, limit torque (P1-12/P1-13) because gearbox output torque can be huge.")
|
||||||
"Safety tip: during first tests, limit torque (P1-12/P1-13) because gearbox output torque can be huge."
|
|
||||||
)
|
|
||||||
|
|
||||||
elif page == "Parameter Guide":
|
elif page == "Parameter Guide":
|
||||||
st.title("🛠️ Essential Parameter Setup")
|
st.title("🛠️ Essential Parameter Setup")
|
||||||
|
|
@ -774,9 +894,7 @@ elif page == "Parameter Guide":
|
||||||
)
|
)
|
||||||
|
|
||||||
st.subheader("2. Speed & Torque Limits")
|
st.subheader("2. Speed & Torque Limits")
|
||||||
st.info(
|
st.info("Gear reduction increases output torque and reduces output speed. Use limits to protect mechanics.")
|
||||||
"Gear reduction increases output torque and reduces output speed. Use limits to protect mechanics."
|
|
||||||
)
|
|
||||||
st.markdown(
|
st.markdown(
|
||||||
"""
|
"""
|
||||||
- **P1-02 (Speed Limit):** Set to motor-rated speed or your machine limit.
|
- **P1-02 (Speed Limit):** Set to motor-rated speed or your machine limit.
|
||||||
|
|
@ -805,8 +923,7 @@ elif page == "Parameter Guide":
|
||||||
2. Set value to 10.
|
2. Set value to 10.
|
||||||
3. Press 'SET'.
|
3. Press 'SET'.
|
||||||
4. Power Cycle (Off/On).
|
4. Power Cycle (Off/On).
|
||||||
""".strip(),
|
""".strip()
|
||||||
language="markdown",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
with col_b:
|
with col_b:
|
||||||
|
|
@ -822,7 +939,6 @@ elif page == "Parameter Guide":
|
||||||
|
|
||||||
elif page == "Commissioning Checklist":
|
elif page == "Commissioning Checklist":
|
||||||
st.title("✅ Commissioning Checklist (Field Workflow)")
|
st.title("✅ Commissioning Checklist (Field Workflow)")
|
||||||
|
|
||||||
st.caption("A practical sequence to minimize mistakes and avoid mechanical damage.")
|
st.caption("A practical sequence to minimize mistakes and avoid mechanical damage.")
|
||||||
|
|
||||||
steps = [
|
steps = [
|
||||||
|
|
@ -869,7 +985,6 @@ elif page == "Export Report":
|
||||||
st.title("🧾 Export Commissioning Report (Markdown / PDF)")
|
st.title("🧾 Export Commissioning Report (Markdown / PDF)")
|
||||||
st.caption("Generates a report of your current inputs, PUU result, checks, speed and torque estimates.")
|
st.caption("Generates a report of your current inputs, PUU result, checks, speed and torque estimates.")
|
||||||
|
|
||||||
# Recompute PUU + checks for report
|
|
||||||
puu = compute_puu(
|
puu = compute_puu(
|
||||||
motor_counts_per_rev=float(st.session_state.motor_counts_per_rev),
|
motor_counts_per_rev=float(st.session_state.motor_counts_per_rev),
|
||||||
gear_ratio=float(st.session_state.gear_ratio),
|
gear_ratio=float(st.session_state.gear_ratio),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue