a
    Vj\9                     @   s   d Z ddlZddlZddlmZ dd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zd(ddZdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd)d#d$Zed%krddlZeeejd&krejd& neejjd' Zeee dS )*zRobot spec -> MJCF.

The spec JSON is the single source of truth: this module turns it into a MuJoCo
model, and bench/js/robot.js turns the same file into three.js meshes. If you
change the spec schema, change both.
    N)Pathc                 C   sB   t | }t|}W d    n1 s(0    Y  t| |d< |S )N_path)openjsonloadstr)pathfspec r   (/home/ghrups/robot-bench/trainer/mjcf.py	load_spec   s    
(r   c                 C   s   d dd | D S )N c                 s   s   | ]}t |d V  qdS ).6gN)float).0cr   r   r   	<genexpr>       z_v.<locals>.<genexpr>)join)xr   r   r   _v   s    r   c                 C   s"   dt | d  dt | d  dS )Nzfromto="fromr   to")r   )gr   r   r   _capsule_fromto   s    r   c                 C   s  | d }d| dg}|dv rF| t|  | d| d dd n|dkr| dt| d	  d d
| v r| dt| d
  d n|dkr| d| d dd d
| v r| dt| d
  d nX|dkr| dt| d	  d d
| v r(| dt| d
  d ntd|d| v rJ| d| d dd d| v rn| dt| d  d d| v r| dt| d  d d| v r| d| d  d | ddu r| d d| d d| d S )Ntypetype="r   )ZcapsuleZcylindersize="radiusr   boxsizepospos="sphereZ	ellipsoidzunsupported geom type masszmass="rgbargba="friction
friction="namename="ZcollideFzcontype="0" conaffinity="0"r   <geom />)appendr   r   
ValueErrorgetr   )r   indenttbitsr   r   r   	_geom_xml   s:    






r5   c                 C   s   d| d  ddt | dg d dg}|d| dd	 d |d
t | ddg d |d d| d d| d S )Nr,   r+   r   r$   r#   r   r   r   r   r   r%   r   r"   {Gzt?zrgba="1 0.4 0 0.25"r   z<site r.   r   r1   r/   r   )sr2   r4   r   r   r   	_site_xmlD   s
    , 
r:   c                 C   s   d| d  dd|  dd dg}d| v rF|dt| d  d |  d	r\|d
 nFd| v r| d \}}|dt|ddt|dd |d dD ](}|| v r|| d| | dd qd| d d| d S )Nr,   r+   r   r   r   Zhingeaxiszaxis="
continuouszlimited="false"	range_degzrange="r   r   zlimited="true")dampingarmaturefrictionloss	stiffnessz="z<joint r.   )r1   r/   r   mathradiansr   )jr2   r4   lohikeyr   r   r   
_joint_xmlL   s    $
(
rH   c                 C   s   d| d  ddt | dg d dg}d| v rP|dt | d  d n"d	| v rr|d
t | d	  d d| v r|d| d dd d| d d| d S )Nr,   r+   r   r$   r#   r6   xyaxeszxyaxes="eulerzeuler="fovyzfovy="r   r   z<camera r.   r8   )r   r2   r4   r   r   r   _camera_xml\   s    ,rL   Fc           	   
   C   s.  d| }| d| d  dt | dg d dg}|rT| dd	rT|| d
 d| v r|| d r||t| d |d  | dg D ]}|t||d  q| dg D ]}|t||d  q| dg D ]}|t||d  q| dg D ]}|t||d  q|| d d|S )Nr   z<body name="r+   z" pos="r#   r6   z">r   Fz  <freejoint name="root"/>joint   geomssitescameraschildrenz</body>
)	r   r1   r/   rH   r5   r:   rL   	_body_xmlr   )	bodyr2   is_rootpadoutr   r9   r   childr   r   r   rT   i   s     ,rT   c           
   	   C   s  |  di }| | dd}|s&dS dt|d  }t| dd}|d	kr^t| d
dnd}t| dd}| d}| d}	|du r|t|d  }|	du r|t| d| d }	|||| | |	| | t|d | d tj d | | d| ddudS )aM  Resolve an actuator's real limits from the motor part it names.

    A BLDC's torque is Kt * current, and Kt is 8.27/Kv. Putting the motor in
    the spec rather than a hand-written force_range means the model saturates
    where the real hardware saturates, which is most of what decides whether a
    learned policy transfers.
    Zmotorsmotor Ng
ףp= @kvZ
gear_ratio      ?   Z
efficiencyg?Zvoltageg      8@Zrated_torqueZ
max_torqueZrated_current_aZmax_current_arN   g      N@)ktratiotau_conttau_peakZno_load_rad_srZ   Zfrom_datasheet)r1   r   rB   pi)
r
   alibmr_   r`   ZeffZvoltscontZpeakr   r   r   motor_limits|   s,    



 rh   c              	   C   s  d| }|  dd}t|| }d| d  dd| d  dg}|dkrd	}|d
|  dddd |  dp|r|d  |d gnddg}|dt| d n|dkrd}|d|  dddd |d|  dddd |  dpt|| d }|dt| d n\|dkrld}|d|  dddd |dt|  dddg d ntd||  dr| d }	n0|r|dkrdnd}
||
  ||
 g}	nd }	|	r|dt|	 d |d | d d| d! S )"Nr   modetorquer,   r+   r   joint="rM   rZ   zgear="gearr]   r   Z
ctrl_rangera   r^   zctrlrange="Zpositionzkp="Zkpg      >@zkv="r\   velocityi   zunsupported actuator mode Zforce_rangerb   zforcerange="<r.   )r1   rh   r/   r   _joint_range_radr0   r   )rd   r
   r2   rW   ri   Zlimr4   tagZcrfrrG   r   r   r   _actuator_xml   s>    
  

$
rt   c                 c   s*   | V  |  dg D ]}t|E d H  qd S )NrR   )r1   _walk)rU   r   r   r   r   ru      s    ru   c                 C   sH   t | d D ]&}|d}|r|d |kr|  S qtd|dd S )NrootrM   r+   z	no joint z in spec)ru   r1   KeyError)r
   r+   brD   r   r   r   
find_joint   s
    

ry   c                 C   sD   t | |}|dsd|vr$ddgS |d \}}t|t|gS )Nr<   r=   g      $g      $@)ry   r1   rB   rC   )r
   r+   rD   rE   rF   r   r   r   rq      s
    
rq   c           
      C   s   d| }| d }h d}h d}h d}||v rBd| d  d}nb||v r||  d	d}|  d
|  d}	d| d|	 d}n(||v rd| d  d}ntd||d| d| d  d| d S )Nr   r   >   ZgyroZaccelerometerZvelocimeterZtouchrangefinderZmagnetometer>   ZframeangvelZframeposZframelinvelZ	framequatZ
framezaxis>   ZjointactuatorfrcZjointposZjointvelzsite="siter   objtypeobjnamez	objtype="z" objname="rk   rM   zunsupported sensor type rp   z name="r+   z" r.   )r1   r0   )
r9   r2   rW   r3   Z
site_typesZframe_typesZjoint_typesrefr|   r}   r   r   r   _sensor_xml   s    r   c              	   C   s   d| }d| d  dd|  dd ddt|  d	g d
 dg}|  dddkrr|dt| d  d n|dt| d  d |dt|  dg d d d| v r|dt| d  d |d d| d S )z;Static scenery a task brings with it: steps, ramps, blocks.r   r,   r+   r   r   r   r!   r$   r#   r6   r   r"   r(   r'   )g?gGz?g(\?r^   r)   r*   r-   r.   )r1   r   r/   r   )pr2   rW   r4   r   r   r   	_prop_xml   s     "r   c                    s    di }  di }| di }| drPd}dt| dg d d	 }nRd
}dj| ddtt| ddtt| ddt| dg dd}| dd}t d ddd}ddd |pg D }	d fdd  dg D }
ddd   dg D } d d }dd| d	d| d	d | d	d! d d" d# d  d	d$ d d" d# d  d	g}d% d  d&| d'd( d)| d*d+ d,t| d-g d. d/| d0| d|	 d| d1|
 d2| d| d3S )4aw  world.floor may carry bank_deg / pitch_deg to tilt the ground.

    It has to be baked in here rather than set later: MuJoCo precomputes the
    frame of static world geoms, so writing geom_quat at runtime changes the
    number but leaves the plane's normal pointing straight up, and nothing
    happens. That silently produced identical results at 3, 6 and 10 degrees.
    simworldfloorZhillszA<hfield name="hills" nrow="120" ncol="120" size="6 6 0.09 0.03"/>zJ<geom name="floor" type="hfield" hfield="hills" material="grid" friction="r)   )r]   r7   g-C6?z"/>r[   zs<geom name="floor" type="plane" size="{fs} {fs} 0.05" material="grid" euler="{be:.6g} {pe:.6g} 0" friction="{fr}"/>r"   g      (@Zbank_degg        Z	pitch_deg)fsZbeZpers   rv      T)rV   rS   c                 s   s   | ]}t |d V  qdS r   N)r   )r   r   r   r   r   r   *  r   zspec_to_mjcf.<locals>.<genexpr>c                 3   s   | ]}t | d V  qdS r   )rt   )r   rd   r
   r   r   r   +  r   	actuatorsc                 s   s   | ]}t |d V  qdS r   )r   )r   r9   r   r   r   r   ,  r   sensorsr+   z7    <framequat name="gt_quat" objtype="xbody" objname="z5    <framepos name="gt_pos" objtype="xbody" objname="z6    <framezaxis name="gt_up" objtype="xbody" objname="z%    <velocimeter name="gt_vel" site="rP   r   z    <gyro name="gt_gyro" site="z<mujoco model="a+  ">
  <compiler angle="radian" autolimits="true"/>
  <!-- 64M arena: the default 14M ran out during the limp heap's contact
       pile-up (rollers + wheels + chassis + joints on their stops) and
       MuJoCo took the whole Python process down with it -->
  <size memory="64M"/>
  <option timestep="timestepgMb`?z" integrator="
integratorZimplicitfastz"
          gravity="gravity)r   r   gQ#a2  " cone="elliptic" impratio="3"/>

  <default>
    <!-- solref is the contact's stiffness as a time constant. At 0.005 the
         floor is effectively rigid (636 N knee-fold spikes). 0.04 gives with
         1mm under standing load, but a 2 m/s JUMP landing drives the tyre
         48mm in for ~120ms - visually through the floor (operator caught
         it). MEASURED before "fixing": 0.02 and 0.03 both collapse the
         balance bench bakes (5.0 -> 1.2) and crater the jump seed - every
         learned gain is tuned to this compliance, which acts as the tyre-
         and-suspension model. It stays 0.04; the sink is the suspension
         working. Revisit only alongside a full-ladder relearn, ideally
         with real-tyre data from the hardware. -->
    <geom solref="0.04 1" condim="4"/>
    <site group="3"/>
  </default>

  <asset>
    <texture name="grid" type="2d" builtin="checker" rgb1="0.82 0.83 0.85" rgb2="0.72 0.73 0.76"
             width="512" height="512"/>
    <material name="grid" texture="grid" texrepeat="24 24" reflectance="0.05"/>
    zX
  </asset>

  <worldbody>
    <light pos="0 0 3" dir="0 0 -1" directional="true"/>
    z
  </worldbody>

  <actuator>
z
  </actuator>

  <sensor>
z
  </sensor>
</mujoco>
)r1   r   formatrB   rC   r   rT   r   )r
   Zpropsr   r   r   Zfloor_assetZ
floor_geomZfsizebodiesZsceneryr   r   Z	root_nametruthr   r   r   spec_to_mjcf  sf    

 




!"#'+,r   __main__r^   zrobots/wheeled_biped.json)F)N)__doc__r   rB   pathlibr   r   r   r   r5   r:   rH   rL   rT   rh   rt   ru   ry   rq   r   r   r   __name__syslenargv__file__parentr
   printr   r   r   r   <module>   s2   (
&*
i