Download runtime/robot_cell.py from rasitcesur/Manufacturing-MoE: direct link, hf CLI and curl.
- Browser
- Download file 10.4 kB
-
https://huggingface.co/rasitcesur/Manufacturing-MoE/resolve/main/runtime/robot_cell.py
- Command line
-
hf download hf://rasitcesur/Manufacturing-MoE/runtime/robot_cell.py
-
curl -L -o robot_cell.py https://huggingface.co/rasitcesur/Manufacturing-MoE/resolve/main/runtime/robot_cell.py
10.4 kB
| """Manufacturing-MoE shared robot-cell inverse dynamics and energy accounting. | |
| Not a qualified RSW/TIG WPS or thermal-metallurgical solver. | |
| """ | |
| from __future__ import annotations | |
| import sys,math | |
| from pathlib import Path | |
| import numpy as np | |
| ROOT=Path(__file__).resolve().parents[1] | |
| from arc_welding_physics import timed_robot_motion,duration_for_joint_motion,external_axis_energy,external_idle_W,external_trajectory,quintic_trajectory,torch_trajectory | |
| COMPONENTS=('robot_joint_drives_Wh','robot_controller_Wh','process_power_source_Wh','process_actuator_Wh','cooling_Wh','fume_extraction_Wh','gas_valve_Wh','source_standby_Wh','external_axes_Wh') | |
| def machine_source(rng,process,ood=False): | |
| spot=process=='rsw' | |
| return dict(source_nominal_efficiency=.84 if spot else .87, | |
| source_nameplate_W=120000. if spot else 9000., | |
| process_actuator_nominal_W=420. if spot else 34., | |
| cooling_nominal_W=420. if spot else 170., | |
| fume_extraction_nominal_W=90. if spot else 120., | |
| gas_valve_nominal_W=0. if spot else 8., | |
| source_standby_nominal_W=85. if spot else 64., | |
| private_source_efficiency=float(rng.uniform(.67,.76) if ood else rng.uniform(.80,.91)), | |
| private_actuator_scale=float(rng.uniform(1.24,1.50) if ood else rng.uniform(.83,1.17)), | |
| private_cooling_scale=float(rng.uniform(1.19,1.46) if ood else rng.uniform(.80,1.20)), | |
| private_fume_scale=float(rng.uniform(1.16,1.43) if ood else rng.uniform(.83,1.17)), | |
| private_valve_scale=float(rng.uniform(.85,1.18)), | |
| private_contact_scale=float(rng.uniform(1.18,1.40) if ood else rng.uniform(.86,1.14)), | |
| private_transfer_eff=float(rng.uniform(.91,.97) if ood else rng.uniform(.965,.994))) | |
| def public_source(src):return {k:v for k,v in src.items() if not k.startswith('private_')} | |
| def current_setting(rng,process,material,thickness): | |
| if process=='rsw': | |
| amp=float(rng.uniform(5500,13000) if material!='aluminum' else rng.uniform(18000,27500)) | |
| force=float(rng.uniform(1500,5600));res=float(rng.uniform(.000055,.00017)) | |
| return dict(current_A=amp,electrode_force_N=force,contact_resistance_nominal_ohm=res, | |
| squeeze_s=float(rng.uniform(.12,.40)),pulse_s=float(rng.uniform(.08,.34)), | |
| hold_s=float(rng.uniform(.10,.34)),pulses=int(rng.integers(1,4)), | |
| inter_pulse_s=float(rng.uniform(.025,.075)),gas_flow_L_min=0.,filler_diameter_mm=0., | |
| filler_feed_m_min=0.,travel_speed_mm_s=0.,ac_mode=0.,pulse_duty=float(rng.uniform(.55,.95))) | |
| ac=int(material=='aluminum' and rng.random()<.80) | |
| amp=float(rng.uniform(70,190));volts=float(rng.uniform(9,16)) | |
| filler=int(rng.random()<.70);dia=float(rng.choice([1.0,1.2,1.6,2.0])) if filler else 0. | |
| feed=float(rng.uniform(.35,1.5)) if filler else 0. | |
| return dict(current_A=amp,voltage_V=volts,gas_flow_L_min=float(rng.uniform(8,17)), | |
| filler_diameter_mm=dia,filler_feed_m_min=feed,travel_speed_mm_s=float(rng.uniform(1.7,5.4)), | |
| ac_mode=ac,pulse_duty=float(rng.uniform(.55,.95)),squeeze_s=0.,pulse_s=0.,hold_s=0.,pulses=0, | |
| inter_pulse_s=0.,electrode_force_N=0.,contact_resistance_nominal_ohm=0.) | |
| def probes(source,process,rng): | |
| # SIX prior independent load tests, not the predicted welding job. | |
| levels=np.array([0.,.25,.40,.55,.72,.90]);vals=[] | |
| for x in levels: | |
| if process=='rsw': | |
| I=12000*x | |
| # prior gauge: circuit equivalent resistance under a standardized electrode force | |
| nominal_power=(I*I*.000110) | |
| actual_power=nominal_power*source['private_contact_scale']/source['private_source_efficiency'] | |
| else: | |
| nominal_power=(180*x)*(12.5) | |
| actual_power=nominal_power/source['private_source_efficiency'] | |
| p=source['source_standby_nominal_W']+source['cooling_nominal_W']*source['private_cooling_scale']+actual_power | |
| vals.append(float(p*(1+rng.normal(0,.002)))) | |
| return np.asarray(vals,np.float32) | |
| def robot_segment(cfg,seg,T): | |
| r=timed_robot_motion(cfg,np.asarray(seg['q0']),np.asarray(seg['q1']),T,float(seg.get('payload_kg',1.7)),steps=12) | |
| e,nom=external_axis_energy(cfg,seg,T,12) | |
| return r,e,nom | |
| def totals_common(cfg,source,program,process): | |
| comp={k:0. for k in COMPONENTS} | |
| nom={k:0. for k in COMPONENTS} | |
| source_w=source['source_standby_nominal_W'];cool=source['cooling_nominal_W'];fume=source['fume_extraction_nominal_W'] | |
| ctrl_w=cfg['electronic_power_W']+16*cfg['n'] | |
| total_t=active_t=0.;arc_heat=0.;deposit=0.;consumed=0.;gas=0.;spots=0 | |
| spot_detail=[] | |
| for seg in program['segments']: | |
| q0=np.asarray(seg['q0']);q1=np.asarray(seg['q1']) | |
| motion_T=duration_for_joint_motion(cfg,q0,q1,.7) | |
| if seg['kind']=='travel' or process=='rsw':T=motion_T | |
| else: | |
| qseq,_,_=quintic_trajectory(q0,q1,1.,12) | |
| tcp=external_trajectory(cfg,seg,torch_trajectory(cfg,qseq,seg['tip_index'])) | |
| path_mm=float(np.linalg.norm(np.diff(tcp,axis=0),axis=1).sum()*1000) | |
| T=max(motion_T,path_mm/max(program['setting']['travel_speed_mm_s'],.001)) | |
| r,e,enom=robot_segment(cfg,seg,T) | |
| comp['robot_joint_drives_Wh']+=r['robot_joint_drives_Wh'];nom['robot_joint_drives_Wh']+=r['nominal_robot_joint_drives_Wh'] | |
| comp['robot_controller_Wh']+=r['robot_controller_Wh'];nom['robot_controller_Wh']+=r['robot_controller_Wh'] | |
| comp['external_axes_Wh']+=e;nom['external_axes_Wh']+=enom | |
| t=T | |
| if seg['kind'] in ('arc','spot'): | |
| if process=='rsw': | |
| s=program['setting'];nd=s['pulses'];tw=s['pulse_s'];wait=s['inter_pulse_s']*(nd-1) | |
| t_hold=s['squeeze_s']+nd*tw+wait+s['hold_s'] | |
| t+=t_hold | |
| # dynamic resistance proxy: electrode force contact compression, interface heating and cooling. | |
| timegrid=np.linspace(0,1,12) | |
| resistance=s['contact_resistance_nominal_ohm']*(.7+.3*np.exp(-1.2*timegrid))*np.power(2800/s['electrode_force_N'],.18) | |
| resistance=np.clip(resistance,1e-6,.001) | |
| i_rms=s['current_A']*math.sqrt(s['pulse_duty']) | |
| Q_nom=i_rms**2*float(resistance.mean())*nd*tw | |
| Q_actual=Q_nom*source['private_contact_scale'] | |
| comp['process_power_source_Wh']+=Q_actual/source['private_source_efficiency']/3600 | |
| nom['process_power_source_Wh']+=Q_nom/source['source_nominal_efficiency']/3600 | |
| heat=Q_actual*.66/1000;arc_heat+=heat | |
| spots+=1;active_t+=nd*tw | |
| nominal_act=source['process_actuator_nominal_W']*(.35+s['electrode_force_N']/6500) | |
| comp['process_actuator_Wh']+=nominal_act*source['private_actuator_scale']*t_hold/3600 | |
| nom['process_actuator_Wh']+=nominal_act*t_hold/3600 | |
| spot_detail.append(dict(heat_kJ=heat,electrode_force_N=s['electrode_force_N'],contact_resistance_ohm=float(resistance.mean()))) | |
| else: | |
| s=program['setting'];active_t+=T | |
| arc_W=s['current_A']*s['voltage_V']*(s['pulse_duty']*(1.08 if s['ac_mode'] else 1.0)+(1-s['pulse_duty'])*.68) | |
| nom['process_power_source_Wh']+=arc_W/source['source_nominal_efficiency']*T/3600 | |
| comp['process_power_source_Wh']+=arc_W/source['private_source_efficiency']*T/3600 | |
| arc_heat+=arc_W*T*(.66 if s['ac_mode'] else .73)/1000 | |
| if s['filler_diameter_mm']>0: | |
| rho=.00270 if program['material']=='aluminum' else .0079 | |
| consumed_t=math.pi*s['filler_diameter_mm']**2/4*(s['filler_feed_m_min']*1000*T/60)*rho | |
| consumed+=consumed_t;deposit+=consumed_t*source['private_transfer_eff'] | |
| act=source['process_actuator_nominal_W']*(.2+s['filler_feed_m_min']) | |
| nom['process_actuator_Wh']+=act*T/3600 | |
| comp['process_actuator_Wh']+=act*source['private_actuator_scale']*T/3600 | |
| # Source standby, controller/servo holding and auxiliaries across ALL phases. | |
| nom['source_standby_Wh']+=source_w*t/3600;comp['source_standby_Wh']+=source_w*t/3600 | |
| nom['cooling_Wh']+=cool*t/3600;comp['cooling_Wh']+=cool*source['private_cooling_scale']*t/3600 | |
| nom['fume_extraction_Wh']+=fume*t/3600;comp['fume_extraction_Wh']+=fume*source['private_fume_scale']*t/3600 | |
| extra=t-T | |
| if extra>0: | |
| nom['robot_controller_Wh']+=ctrl_w*extra/3600;comp['robot_controller_Wh']+=ctrl_w*extra/3600 | |
| hold=float(np.sum((2+.35*np.asarray(cfg['mass'])))) | |
| nom['robot_joint_drives_Wh']+=hold*extra/3600 | |
| comp['robot_joint_drives_Wh']+=hold*cfg['private_driver_loss']*extra/3600 | |
| en=external_idle_W(cfg,nominal=False);en0=external_idle_W(cfg,nominal=True) | |
| comp['external_axes_Wh']+=en*extra/3600;nom['external_axes_Wh']+=en0*extra/3600 | |
| total_t+=t | |
| s=program['setting'] | |
| if process=='tig': | |
| gas_t=active_t+program['shielding_preflow_s']+program['shielding_postflow_s'] | |
| gas=gas_t*s['gas_flow_L_min']/60 | |
| nom['gas_valve_Wh']+=source['gas_valve_nominal_W']*gas_t/3600 | |
| comp['gas_valve_Wh']+=source['gas_valve_nominal_W']*source['private_valve_scale']*gas_t/3600 | |
| tail=program['shielding_preflow_s']+program['shielding_postflow_s']+program['cooling_tail_s'] | |
| else:tail=program['cooling_tail_s'] | |
| total_t+=tail | |
| for k,wat in [('robot_controller_Wh',ctrl_w),('source_standby_Wh',source_w),('cooling_Wh',cool),('fume_extraction_Wh',fume)]: | |
| nom[k]+=wat*tail/3600 | |
| mult={'cooling_Wh':source['private_cooling_scale'],'fume_extraction_Wh':source['private_fume_scale']}.get(k,1.) | |
| comp[k]+=wat*mult*tail/3600 | |
| hold=sum(2+.35*float(m) for m in cfg['mass']) | |
| comp['robot_joint_drives_Wh']+=hold*cfg['private_driver_loss']*tail/3600 | |
| nom['robot_joint_drives_Wh']+=hold*tail/3600 | |
| nom['external_axes_Wh']+=external_idle_W(cfg,nominal=True)*tail/3600 | |
| comp['external_axes_Wh']+=external_idle_W(cfg,nominal=False)*tail/3600 | |
| return dict(time_s=total_t,energy_Wh=sum(comp.values()),material_added_g=deposit,wire_consumed_g=consumed, | |
| gas_consumed_L=gas,spot_count=spots,heat_to_workpiece_kJ=arc_heat,active_time_s=active_t, | |
| components=comp,nominal_components=nom,spot_detail=spot_detail) | |