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) """ )