279 lines
9.5 KiB
Python
279 lines
9.5 KiB
Python
|
|
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., 30–60%) 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)
|
|||
|
|
"""
|
|||
|
|
)
|