streamlit-delta-PUU-calculator/main.py
2026-01-06 18:05:40 +01:00

279 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import streamlit as st
from math import gcd
# ----------------------------
# Helpers
# ----------------------------
def simplify_fraction(n: int, d: int) -> tuple[int, int]:
if d == 0:
raise ValueError("Denominator cannot be 0.")
if n == 0:
return 0, 1
g = gcd(abs(n), abs(d))
n //= g
d //= g
# Keep denominator positive
if d < 0:
n *= -1
d *= -1
return n, d
def scale_down_to_limit(n: int, d: int, limit: int) -> tuple[int, int]:
"""
If numerator/denominator exceed 'limit', scale them down proportionally.
Keeps ratio approximately the same (exact if divisible), then re-simplifies.
"""
if n == 0:
return 0, 1
n_abs, d_abs = abs(n), abs(d)
if n_abs <= limit and d_abs <= limit:
return n, d
# Scale by the maximum overflow factor
factor = max((n_abs + limit - 1) // limit, (d_abs + limit - 1) // limit)
n2 = n // factor
d2 = d // factor
# Avoid zeroing out
if n2 == 0:
n2 = 1 if n > 0 else -1
if d2 == 0:
d2 = 1
return simplify_fraction(n2, d2)
# ----------------------------
# Page config + nav
# ----------------------------
st.set_page_config(page_title="Delta ASDA-A2 Engineering Tool", layout="wide")
st.sidebar.title("Configuration")
page = st.sidebar.radio(
"Go to",
["Theory & Architecture", "PUU Calculator", "Parameter Guide", "ASDA-Soft Guide"],
)
# ----------------------------
# Pages
# ----------------------------
if page == "Theory & Architecture":
st.title("📚 Theory & Architecture")
st.markdown(
"""
This tool helps you set up **electronic gearing (PUU / P1-44 & P1-45)** and the **core safety/tuning parameters**
for a system with a gearbox (e.g., **50:1**).
### Concept (simple)
Most motion controllers output **position command pulses**.
The servo drive converts those pulses into **motor encoder counts** using an **electronic gear ratio**:
\[
\\text{Motor encoder counts} = \\text{Command pulses} \\times \\frac{P1-44}{P1-45}
\]
So you choose **P1-44 / P1-45** to match *your desired “user unit”* (degrees, mm, etc.) at the **load side**.
### With a gearbox
- Motor counts per **load revolution** = *(motor encoder counts per motor rev)* × *(gear ratio)*
- If you want e.g. **360 units per load rev** (degrees), then:
\[
\\frac{P1-44}{P1-45} = \\frac{\\text{motor counts per load rev}}{\\text{units per load rev} \\times \\text{controller pulses per unit}}
\]
Use the **PUU Calculator** page to get clean integers.
"""
)
elif page == "PUU Calculator":
st.title("🔢 Universal PUU Calculator (P1-44 / P1-45)")
st.caption(
"Goal: convert your controller command pulses into the correct motor encoder counts, "
"including gearbox ratio, and optionally define a meaningful user unit (deg/mm/etc.)."
)
col1, col2 = st.columns(2)
with col1:
st.subheader("Input")
motor_counts_per_rev = st.number_input(
"Motor encoder counts per motor revolution",
min_value=1,
value=128000,
step=1000,
help="Common values: 128000, 131072, 1048576 ... depends on encoder/resolution & drive setting.",
)
gear_ratio = st.number_input(
"Gear ratio (motor rev per load rev)",
min_value=1.0,
value=50.0,
step=1.0,
help="For 50:1 reduction, motor turns 50 rev while load turns 1 rev => enter 50.",
)
units_per_load_rev = st.number_input(
"User units per load revolution",
min_value=1,
value=360,
step=1,
help="Examples: degrees=360, turns=1, mm per rev for a leadscrew (e.g. 5 mm/rev => 5).",
)
controller_pulses_per_unit = st.number_input(
"Controller command pulses per user unit",
min_value=1.0,
value=1.0,
step=1.0,
help="If your controller outputs 1 pulse = 1 user unit, keep 1. "
"If it outputs e.g. 10 pulses per degree, enter 10.",
)
ratio_limit = st.number_input(
"Max integer limit for P1-44 / P1-45 (safety)",
min_value=1000,
value=2_147_483_647,
step=1000,
help="Keeps numbers within typical 32-bit signed range. "
"If you know the drive's tighter limit, set it here.",
)
# Calculate
# motor_counts_per_load_rev = motor_counts_per_rev * gear_ratio
# Desired motor counts per controller pulse = motor_counts_per_load_rev / (units_per_load_rev * controller_pulses_per_unit)
motor_counts_per_load_rev = motor_counts_per_rev * gear_ratio
denom_units = units_per_load_rev * controller_pulses_per_unit
st.divider()
# Convert to integer fraction:
# We want P1-44/P1-45 = motor_counts_per_load_rev / denom_units
# If denom_units isn't integer, scale to preserve precision.
# Use 1e6 scaling for decimals, then simplify.
SCALE = 1_000_000
n_raw = int(round(motor_counts_per_load_rev * SCALE))
d_raw = int(round(denom_units * SCALE))
n_s, d_s = simplify_fraction(n_raw, d_raw)
n_final, d_final = scale_down_to_limit(n_s, d_s, int(ratio_limit))
with col2:
st.subheader("Result")
st.success("Recommended electronic gear ratio for PUU:")
st.markdown(
f"""
- **P1-44 (Numerator / N):** **{n_final}**
- **P1-45 (Denominator / M):** **{d_final}**
"""
)
# Show what it means
pulses_to_motor_counts = n_final / d_final
st.write(f"✅ This means: **1 controller pulse → {pulses_to_motor_counts:.6f} motor encoder counts**")
# Derived helpful values
motor_counts_per_user_unit = motor_counts_per_load_rev / units_per_load_rev
controller_pulses_per_load_rev = units_per_load_rev * controller_pulses_per_unit
motor_counts_per_controller_rev = controller_pulses_per_load_rev * pulses_to_motor_counts
st.markdown("### Sanity checks")
st.write(f"- Motor counts per **load rev**: **{motor_counts_per_load_rev:.3f}**")
st.write(f"- User units per **load rev**: **{units_per_load_rev:.3f}**")
st.write(f"- Motor counts per **user unit** (load side): **{motor_counts_per_user_unit:.3f}**")
st.write(f"- Controller pulses per **load rev**: **{controller_pulses_per_load_rev:.3f}**")
st.write(f"- Motor counts generated by **controller pulses per load rev**: **{motor_counts_per_controller_rev:.3f}**")
st.info(
"Tip: The last line should match (or be very close to) motor counts per load rev. "
"If it's far off, check encoder counts, gear ratio, and pulses-per-unit."
)
st.info(
"Recommended Minimum: It is generally recommended to keep the PUU per motor revolution above 5000 to avoid 'stepping' or vibration at low speeds."
)
st.info(
f"Electronic Gear Ratio Limit: Delta A2 allows a ratio between $1/50$ and $25600$. "
f"Your ratio of {motor_counts_per_load_rev}/{units_per_load_rev}{motor_counts_per_load_rev / units_per_load_rev:.3f} "
f"is well within this safe range."
)
elif page == "Parameter Guide":
st.title("🛠️ Essential Parameter Setup")
st.write("Beyond the PUU (P1-44/45), these parameters are critical for a 50:1 gearbox system.")
st.subheader("1. The 'Big Three' for Gearbox Safety")
st.markdown(
"""
| Parameter | Name | Recommended Value | Why? |
| :--- | :--- | :--- | :--- |
| **P1-44** | Numerator (N) | *From Calculator* | Sets electronic gear / user units. |
| **P1-45** | Denominator (M) | *From Calculator* | Sets electronic gear / user units. |
| **P1-37** | Load to Motor Inertia | **10.0 ~ 20.0** | A 50:1 gearbox increases reflected inertia significantly. Start here for tuning. |
"""
)
st.subheader("2. Speed & Torque Limits")
st.info(
"With 50:1 reduction, output torque is multiplied ~50× while output speed is divided ~50×. "
"Use limits to protect mechanics during first tests."
)
st.markdown(
"""
- **P1-02 (Speed Limit):** Set to motor-rated safe speed (e.g., 3000 RPM) to prevent overspeed.
- **P1-12 / P1-13 (Torque Limit):** Start conservative (e.g., 3060%) during first motion tests to avoid smashing end-stops.
"""
)
st.divider()
st.subheader("🔄 Factory Reset (Set to Default)")
st.warning("Warning: Resetting will erase all PUU and tuning settings!")
col_a, col_b = st.columns(2)
with col_a:
st.markdown("#### Via Drive Keypad")
st.code(
"""
1. Go to Parameter P2-08.
2. Set value to 10.
3. Press 'SET'.
4. Power Cycle (Off/On).
""".strip(),
language="markdown",
)
with col_b:
st.markdown("#### Via ASDA-Soft")
st.markdown(
"""
1. Open **Parameter Editor**.
2. Click **Initial** / **Factory Default**.
3. Confirm and click **Write**.
4. Restart the Drive.
"""
)
elif page == "ASDA-Soft Guide":
st.title("💾 Implementation in ASDA-Soft")
st.markdown(
"""
To apply your **P1-44** and **P1-45** values:
1. Open **Parameter Editor**
2. Select **Group 1** (Basic Parameters)
3. Enter **P1-44** and **P1-45**
4. Click **Write to Drive**
5. **Power cycle / restart** the drive if required for the change to take effect
### Quick workflow
- Calculate PUU in the **PUU Calculator**
- Set **P1-44 / P1-45**
- Set safe limits (**P1-02**, **P1-12**, **P1-13**)
- Then tune (**P1-37** and auto-tuning if you use it)
"""
)