Graphics demo#

Requirements:

In this tutorial we will:

  • Create a two-link pendulum multibody

  • Attach a primitive geometry to a body

  • Attach a 3D mesh geometry to a body

  • Setup web-based 3d visualization

  • Render to a file

import atexit
import numpy as np
from typing import cast
from pathlib import Path

from IPython.display import display, Image

from Karana.Core import discard, allReady
from Karana.Frame import FrameContainer
from Karana.Math import IntegratorType
from Karana.Dynamics import (
    Multibody,
    PhysicalBody,
    PhysicalBody,
    HingeType,
    PhysicalHinge,
    PinSubhinge,
    StatePropagator,
    TimedEvent,
)
from Karana.Math import SpatialInertia, HomTran
from Karana.Scene import (
    SphereGeometry,
    Color,
    PhysicalMaterialInfo,
    PhysicalMaterial,
    AssimpImporter,
)
from Karana.Scene import ProxySceneNode, ProxyScenePart
from Karana.Models import Gravity, UniformGravity, UpdateProxyScene, SyncRealTime, OutputUpdateType
resources = Path().absolute().parent / "resources"
dodecahedron_file = str(resources / "dodecahedron.obj")

Create the multibody and lookup important objects#

mb = createMbody()

# get the first body
bd1 = mb.getBody("bd1")

# get the second body
bd2 = mb.getBody("bd2")

Geometry setup#

We create 3d geometries with associated material properties and attach them to bodies. This is commonly useful for collision detection and 3d visualization.

cleanup_graphics, web_scene = mb.setupGraphics(port=0, wait_for_clients=1)
proxy_scene = mb.getScene()

# create a ball geometry to be used for both bodies
ball_geom = SphereGeometry(0.1)

# load a dodecahedron geometry from file
importer = AssimpImporter()
d12_geom = importer.importFrom(dodecahedron_file).geometries[0]

# create red and blue materials to color the bodies
mat_info = PhysicalMaterialInfo()
mat_info.color = Color.BLUE
blue = PhysicalMaterial(mat_info)
mat_info.color = Color.RED
red = PhysicalMaterial(mat_info)

# create a ProxyScenePart and attach it to the body
bd1_part = ProxyScenePart("bd1_part", scene=proxy_scene, geometry=ball_geom, material=blue)
bd1_part.attachTo(bd1)

bd2_part = ProxyScenePart("bd2_part", scene=proxy_scene, geometry=d12_geom, material=red)
bd2_part.attachTo(bd2)
bd2_part.setScale(0.2)

# create some unattached objects (implicitly attached to the root frame)
root_scene_node = ProxySceneNode("root_scene_node", scene=proxy_scene)

del red, blue, mat_info, d12_geom, ball_geom
[WebUI] Listening at http://newton:37145

Setup camera angle and add ornamental parts#

# position the viewpoint camera of the visualization
web_scene.defaultCamera().pointCameraAt([0.4, 4, -0.9], [0, 0, -1], [0, 0, 1])

# visualize axes for important frames
root_scene_node.graphics().showAxes(0.5)
bd1_part.graphics().showAxes(0.5)
bd2_part.graphics().showAxes(0.5)

# add a trail to track the motion of body 2
bd2_part.graphics().trail()

proxy_scene.update()
# set up state propagator
sp = StatePropagator(mb, IntegratorType.CVODE)
integ = sp.getIntegrator()

# Create a UniformGravity model, and set it's gravitational acceleration.
ug = Gravity("grav_model", sp, UniformGravity("uniform_gravity"), mb)
ug.getGravityInterface().setGravity(np.array([0, 0, -9.81]), 0.0, OutputUpdateType.PRE_HOP)
del ug

# Makes sure the visualization scene is updated after each state change.
UpdateProxyScene("update_proxy_scene", sp, proxy_scene)

# sync the simulation time with real-time.
SyncRealTime("sync_real_time", sp, 1.0)

Register callback for end of each step#

def post_step_fn(t, x):
    """Print out the time and state.

    Parameters
    ----------
    t : float
        The current time.
    x : NDArray[np.float64]
       The current state.
    """
    print(f"t = {float(integ.getTime())/1e9}s; x = {integ.getX()}")


sp.fns.post_hop_fns["update_and_info"] = post_step_fn

Initialize state and time#

x_init = np.array([0.5, -0.5, 0.0, 0.0])
t_init = np.timedelta64(0, "ns")
sp.setTime(t_init)
sp.setState(x_init)

Register event to limit step size#

h = np.timedelta64(int(1e7), "ns")
t = TimedEvent("hop_size", h, lambda _: None, False)
t.period = h

# register after time has been initialized
sp.registerTimedEvent(t)
del t

print(f"t = {float(integ.getTime())/1e9}s; x = {integ.getX()}")
t = 0.0s; x = [ 0.5 -0.5  0.   0. ]

Run the simulation#

The advanceTo time below can be increased to lengthen the simulation

sp.advanceTo(2.0)
t = 0.01s; x = [ 0.49982015 -0.49974123 -0.03596831  0.05175138]
t = 0.02s; x = [ 0.49928071 -0.49896507 -0.07191633  0.10347647]
t = 0.03s; x = [ 0.49838198 -0.4976719  -0.1078237   0.1551488 ]
t = 0.04s; x = [ 0.49712446 -0.49586238 -0.14366998  0.20674165]
t = 0.05s; x = [ 0.49550887 -0.49353744 -0.17943465  0.25822791]
t = 0.06s; x = [ 0.49353612 -0.49069829 -0.21509696  0.30957993]
t = 0.07s; x = [ 0.49120735 -0.48734641 -0.25063602  0.36076938]
t = 0.08s; x = [ 0.48852389 -0.48348355 -0.28603067  0.41176716]
t = 0.09s; x = [ 0.48548729 -0.4791118  -0.32125945  0.46254319]
t = 0.1s; x = [ 0.48209933 -0.47423353 -0.3563006   0.51306637]
t = 0.11s; x = [ 0.47836198 -0.46885142 -0.39113199  0.56330441]
t = 0.12s; x = [ 0.47427746 -0.4629685  -0.42573109  0.61322375]
t = 0.13s; x = [ 0.46984821 -0.45658812 -0.46007495  0.66278942]
t = 0.14s; x = [ 0.46507689 -0.44971401 -0.49414016  0.71196496]
t = 0.15s; x = [ 0.45996641 -0.44235025 -0.52790281  0.76071232]
t = 0.16s; x = [ 0.45451992 -0.43450132 -0.56133849  0.80899176]
t = 0.17s; x = [ 0.44874082 -0.42617211 -0.59442222  0.85676179]
t = 0.18s; x = [ 0.44263274 -0.41736793 -0.62712848  0.90397908]
t = 0.19s; x = [ 0.43619959 -0.40809453 -0.65943117  0.95059846]
t = 0.2s; x = [ 0.42944555 -0.39835811 -0.69130362  0.99657282]
t = 0.21s; x = [ 0.42237504 -0.38816538 -0.72271853  1.04185315]
t = 0.22s; x = [ 0.4149928  -0.37752353 -0.75364807  1.08638849]
t = 0.23s; x = [ 0.4073038  -0.36644027 -0.7840638   1.13012601]
t = 0.24s; x = [ 0.39931333 -0.35492386 -0.81393676  1.17301099]
t = 0.25s; x = [ 0.39102697 -0.34298309 -0.84323743  1.21498694]
t = 0.26s; x = [ 0.38245059 -0.33062734 -0.87193583  1.25599565]
t = 0.27s; x = [ 0.37359036 -0.3178666  -0.90000157  1.29597734]
t = 0.28s; x = [ 0.36445277 -0.30471143 -0.92740384  1.33487081]
t = 0.29s; x = [ 0.3550446  -0.29117302 -0.95411157  1.37261364]
t = 0.3s; x = [ 0.34537296 -0.2772632  -0.98009348  1.40914232]
t = 0.31s; x = [ 0.33544526 -0.26299444 -1.00531816  1.44439262]
t = 0.32s; x = [ 0.32526922 -0.24837983 -1.02975421  1.47829975]
t = 0.33s; x = [ 0.31485291 -0.23343314 -1.05337033  1.51079873]
t = 0.34s; x = [ 0.30420466 -0.21816877 -1.07613552  1.5418247 ]
t = 0.35s; x = [ 0.29333314 -0.20260177 -1.09801912  1.57131329]
t = 0.36s; x = [ 0.28224731 -0.18674784 -1.11899107  1.59920099]
t = 0.37s; x = [ 0.27095645 -0.1706233  -1.139022    1.62542558]
t = 0.38s; x = [ 0.2594701  -0.15424507 -1.15808345  1.64992652]
t = 0.39s; x = [ 0.24779811 -0.13763071 -1.17614798  1.6726454 ]
t = 0.4s; x = [ 0.23595056 -0.12079829 -1.19318941  1.69352636]
t = 0.41s; x = [ 0.22393781 -0.10376648 -1.20918296  1.71251655]
t = 0.42s; x = [ 0.21177047 -0.08655443 -1.22410542  1.72956655]
t = 0.43s; x = [ 0.19945934 -0.06918177 -1.23793532  1.74463073]
t = 0.44s; x = [ 0.18701547 -0.05166857 -1.25065307  1.75766775]
t = 0.45s; x = [ 0.17445005 -0.0340353  -1.26224115  1.76864081]
t = 0.46s; x = [ 0.16177446 -0.01630274 -1.27268417  1.77751807]
t = 0.47s; x = [ 1.49000225e-01  1.50799066e-03 -1.28196903e+00  1.78427285e+00]
t = 0.48s; x = [ 0.13613898  0.01937557 -1.290085    1.78888397]
t = 0.49s; x = [ 0.12320245  0.03727847 -1.29702377  1.79133584]
t = 0.5s; x = [ 0.11020245  0.05519506 -1.30277953  1.79161867]
t = 0.51s; x = [ 0.09715081  0.0731036  -1.30734895  1.78972851]
t = 0.52s; x = [ 0.08405942  0.09098239 -1.31073124  1.78566728]
t = 0.53s; x = [ 0.07094014  0.10880974 -1.31292804  1.77944272]
t = 0.54s; x = [ 0.0578048   0.12656408 -1.31394346  1.77106831]
t = 0.55s; x = [ 0.04466519  0.144224   -1.31378393  1.76056308]
t = 0.56s; x = [ 0.03153301  0.16176832 -1.31245817  1.74795145]
t = 0.57s; x = [ 0.01841988  0.17917611 -1.30997705  1.73326297]
t = 0.58s; x = [ 0.00533728  0.19642677 -1.30635345  1.71653197]
t = 0.59s; x = [-0.00770343  0.21350007 -1.30160213  1.69779733]
t = 0.6s; x = [-0.02069106  0.23037618 -1.2957396   1.67710201]
t = 0.61s; x = [-0.03361458  0.24703573 -1.28878394  1.65449275]
t = 0.62s; x = [-0.04646316  0.26345982 -1.28075461  1.63001962]
t = 0.63s; x = [-0.05922616  0.27963008 -1.27167232  1.60373565]
t = 0.64s; x = [-0.07189317  0.29552868 -1.26155886  1.57569638]
t = 0.65s; x = [-0.08445398  0.31113835 -1.25043689  1.54595946]
t = 0.66s; x = [-0.09689862  0.32644241 -1.23832984  1.51458428]
t = 0.67s; x = [-0.10921737  0.34142478 -1.22526172  1.48163152]
t = 0.68s; x = [-0.12140074  0.35606999 -1.21125698  1.44716285]
t = 0.69s; x = [-0.13343947  0.37036319 -1.19634038  1.4112405 ]
t = 0.7s; x = [-0.14532459  0.38429016 -1.18053686  1.37392699]
t = 0.71s; x = [-0.15704734  0.3978373  -1.16387143  1.33528481]
t = 0.72s; x = [-0.16859923  0.41099163 -1.1463691   1.29537613]
t = 0.73s; x = [-0.17997201  0.42374081 -1.12805472  1.25426257]
t = 0.74s; x = [-0.1911577   0.43607307 -1.10895297  1.21200496]
t = 0.75s; x = [-0.20214853  0.44797729 -1.0890883   1.16866315]
t = 0.76s; x = [-0.212937    0.45944292 -1.0684848   1.12429587]
t = 0.77s; x = [-0.22351584  0.47045998 -1.04716625  1.07896054]
t = 0.78s; x = [-0.23387802  0.48101909 -1.02515605  1.03271322]
t = 0.79s; x = [-0.24401673  0.49111139 -1.00247719  0.98560845]
t = 0.8s; x = [-0.25392541  0.50072857 -0.97915224  0.93769923]
t = 0.81s; x = [-0.2635977   0.50986286 -0.95520337  0.88903697]
t = 0.82s; x = [-0.27302747  0.51850697 -0.93065233  0.83967142]
t = 0.83s; x = [-0.28220881  0.52665411 -0.90552047  0.78965071]
t = 0.84s; x = [-0.29113601  0.53429796 -0.87982874  0.73902131]
t = 0.85s; x = [-0.29980359  0.54143265 -0.85359774  0.68782809]
t = 0.86s; x = [-0.30820624  0.54805278 -0.82684769  0.63611433]
t = 0.87s; x = [-0.31633888  0.55415334 -0.79959853  0.58392173]
t = 0.88s; x = [-0.32419661  0.55972976 -0.77186987  0.53129055]
t = 0.89s; x = [-0.33177474  0.56477782 -0.7436811   0.47825959]
t = 0.9s; x = [-0.33906876  0.56929374 -0.71505136  0.42486628]
t = 0.91s; x = [-0.34607436  0.57327406 -0.6859996   0.37114678]
t = 0.92s; x = [-0.35278741  0.5767157  -0.65654464  0.31713606]
t = 0.93s; x = [-0.35920397  0.57961593 -0.62670515  0.26286795]
t = 0.94s; x = [-0.36532029  0.58197231 -0.59649976  0.2083753 ]
t = 0.95s; x = [-0.37113281  0.58378279 -0.56594703  0.15369001]
t = 0.96s; x = [-0.37663814  0.58504558 -0.53506553  0.09884316]
t = 0.97s; x = [-0.38183309  0.58575922 -0.50387387  0.04386515]
t = 0.98s; x = [-0.38671464  0.58592254 -0.47239072 -0.01121426]
t = 0.99s; x = [-0.39127999  0.58553469 -0.44063486 -0.06636578]
t = 1.0s; x = [-0.39552649  0.58459508 -0.40862526 -0.1215605 ]
t = 1.01s; x = [-0.39945171  0.58310343 -0.37638102 -0.17676977]
t = 1.02s; x = [-0.4030534   0.58105973 -0.34392151 -0.23196508]
t = 1.03s; x = [-0.40632949  0.57846427 -0.31126635 -0.28711796]
t = 1.04s; x = [-0.40927814  0.57531761 -0.27843545 -0.34219979]
t = 1.05s; x = [-0.41189768  0.57162061 -0.24544909 -0.39718176]
t = 1.06s; x = [-0.41418667  0.56737441 -0.2123279  -0.45203468]
t = 1.07s; x = [-0.41614386  0.56258044 -0.17909294 -0.50672888]
t = 1.08s; x = [-0.41776822  0.55724046 -0.14576571 -0.56123406]
t = 1.09s; x = [-0.41905894  0.5513565  -0.11236821 -0.6155192 ]
t = 1.1s; x = [-0.42001543  0.54493091 -0.07892296 -0.66955237]
t = 1.11s; x = [-0.42063732  0.5379664  -0.04545306 -0.72330065]
t = 1.12s; x = [-0.42092448  0.53046596 -0.01198218 -0.77672998]
t = 1.13s; x = [-0.42087704  0.52243298  0.02146535 -0.82980504]
t = 1.14s; x = [-0.42049534  0.51387117  0.05486458 -0.88248914]
t = 1.15s; x = [-0.41977999  0.50478463  0.08818981 -0.93474405]
t = 1.16s; x = [-0.41873188  0.49517785  0.12141466 -0.98652995]
t = 1.17s; x = [-0.41735213  0.48505573  0.15451199 -1.03780532]
t = 1.18s; x = [-0.41564216  0.47442359  0.1874539  -1.08852677]
t = 1.19s; x = [-0.41360366  0.46328719  0.2202117  -1.13864908]
t = 1.2s; x = [-0.41123863  0.45165276  0.25275592 -1.188125  ]
t = 1.21s; x = [-0.40854936  0.43952701  0.28505627 -1.23690529]
t = 1.22s; x = [-0.40553842  0.42691715  0.31708169 -1.28493864]
t = 1.23s; x = [-0.40220875  0.41383091  0.34880034 -1.33217166]
t = 1.24s; x = [-0.39856355  0.40027657  0.3801796  -1.3785489 ]
t = 1.25s; x = [-0.3946064   0.38626297  0.41118616 -1.42401286]
t = 1.26s; x = [-0.39034118  0.37179955  0.44178599 -1.46850407]
t = 1.27s; x = [-0.38577215  0.35689634  0.47194445 -1.51196119]
t = 1.28s; x = [-0.38090388  0.34156399  0.50162637 -1.55432111]
t = 1.29s; x = [-0.37574133  0.32581379  0.53079608 -1.59551915]
t = 1.3s; x = [-0.37028979  0.3096577   0.55941757 -1.63548921]
t = 1.31s; x = [-0.36455492  0.29310832  0.58745456 -1.67416406]
t = 1.32s; x = [-0.35854277  0.27617896  0.61487067 -1.71147561]
t = 1.33s; x = [-0.3522597   0.25888358  0.64162955 -1.74735518]
t = 1.34s; x = [-0.34571249  0.24123686  0.66769505 -1.78173393]
t = 1.35s; x = [-0.33890823  0.22325414  0.69303141 -1.81454319]
t = 1.36s; x = [-0.33185441  0.20495145  0.71760343 -1.84571493]
t = 1.37s; x = [-0.32455883  0.18634552  0.74137668 -1.8751822 ]
t = 1.38s; x = [-0.31702965  0.16745371  0.76431774 -1.90287961]
t = 1.39s; x = [-0.30927535  0.14829404  0.78639439 -1.92874382]
t = 1.4s; x = [-0.30130474  0.12888515  0.80757583 -1.95271409]
t = 1.41s; x = [-0.29312692  0.10924626  0.82783293 -1.97473277]
t = 1.42s; x = [-0.28475126  0.08939718  0.84713844 -1.9947458 ]
t = 1.43s; x = [-0.2761874   0.0693582   0.86546719 -2.01270324]
t = 1.44s; x = [-0.26744524  0.04915011  0.88279628 -2.02855973]
t = 1.45s; x = [-0.25853488  0.02879414  0.89910531 -2.04227491]
t = 1.46s; x = [-0.2494666   0.00831187  0.91437647 -2.05381389]
t = 1.47s; x = [-0.24025086 -0.01227478  0.92859476 -2.06314751]
t = 1.48s; x = [-0.23089825 -0.03294365  0.94174802 -2.0702527 ]
t = 1.49s; x = [-0.22141948 -0.05367235  0.95382707 -2.07511269]
t = 1.5s; x = [-0.21182531 -0.07443839  0.96482574 -2.07771715]
t = 1.51s; x = [-0.20212658 -0.09521917  0.97474087 -2.07806229]
t = 1.52s; x = [-0.19233411 -0.11599211  0.98357231 -2.07615088]
t = 1.53s; x = [-0.18245873 -0.13673469  0.99132287 -2.07199216]
t = 1.54s; x = [-0.17251123 -0.15742451  0.99799822 -2.06560173]
t = 1.55s; x = [-0.16250232 -0.17803936  1.00360678 -2.05700132]
t = 1.56s; x = [-0.15244262 -0.19855727  1.00815957 -2.0462185 ]
t = 1.57s; x = [-0.14234261 -0.21895657  1.01167007 -2.03328642]
t = 1.58s; x = [-0.13221264 -0.23921596  1.01415397 -2.01824334]
t = 1.59s; x = [-0.12206289 -0.25931454  1.01562904 -2.00113226]
t = 1.6s; x = [-0.11190336 -0.27923187  1.01611482 -1.98200046]
t = 1.61s; x = [-0.10174382 -0.29894798  1.01563248 -1.96089899]
t = 1.62s; x = [-0.09159386 -0.31844346  1.01420451 -1.9378822 ]
t = 1.63s; x = [-0.08146281 -0.33769943  1.01185451 -1.91300722]
t = 1.64s; x = [-0.07135976 -0.35669761  1.00860698 -1.88633349]
t = 1.65s; x = [-0.06129357 -0.37542031  1.00448704 -1.85792222]
t = 1.66s; x = [-0.05127284 -0.39385047  0.99952029 -1.82783595]
t = 1.67s; x = [-0.04130591 -0.41197166  0.9937325  -1.79613811]
t = 1.68s; x = [-0.03140084 -0.42976807  0.98714953 -1.76289257]
t = 1.69s; x = [-0.02156548 -0.44722456  0.97979707 -1.72816323]
t = 1.7s; x = [-0.01180738 -0.4643266   0.97170052 -1.69201372]
t = 1.71s; x = [-0.00213387 -0.48106031  0.96288485 -1.65450702]
t = 1.72s; x = [ 0.007448   -0.49741243  0.95337447 -1.61570519]
t = 1.73s; x = [ 0.01693139 -0.5133703   0.94319312 -1.57566914]
t = 1.74s; x = [ 0.0263097  -0.52892189  0.9323638  -1.53445835]
t = 1.75s; x = [ 0.03557658 -0.54405575  0.92090867 -1.49213079]
t = 1.76s; x = [ 0.04472586 -0.55876097  0.90884903 -1.44874266]
t = 1.77s; x = [ 0.05375161 -0.57302725  0.89620528 -1.40434838]
t = 1.78s; x = [ 0.06264808 -0.58684476  0.88299686 -1.3590004 ]
t = 1.79s; x = [ 0.07140973 -0.60020424  0.86924227 -1.31274923]
t = 1.8s; x = [ 0.08003117 -0.6130969   0.85495907 -1.26564335]
t = 1.81s; x = [ 0.0885072  -0.62551442  0.84016387 -1.21772921]
t = 1.82s; x = [ 0.09683279 -0.63744894  0.82487238 -1.16905122]
t = 1.83s; x = [ 0.10500304 -0.64889304  0.8090994  -1.11965183]
t = 1.84s; x = [ 0.11301322 -0.6598397   0.7928589  -1.06957147]
t = 1.85s; x = [ 0.12085871 -0.67028232  0.77616399 -1.01884868]
t = 1.86s; x = [ 0.12853503 -0.68021466  0.75902707 -0.96752016]
t = 1.87s; x = [ 0.13603781 -0.68963082  0.74145978 -0.91562079]
t = 1.88s; x = [ 0.14336282 -0.69852528  0.72347309 -0.86318377]
t = 1.89s; x = [ 0.15050591 -0.70689281  0.70507737 -0.81024064]
t = 1.9s; x = [ 0.15746304 -0.71472851  0.68628244 -0.75682144]
t = 1.91s; x = [ 0.16423026 -0.72202775  0.6670976  -0.70295471]
t = 1.92s; x = [ 0.17080372 -0.7287862   0.64753172 -0.64866769]
t = 1.93s; x = [ 0.17717965 -0.73499979  0.62759329 -0.59398632]
t = 1.94s; x = [ 0.18335437 -0.7406647   0.60729045 -0.53893539]
t = 1.95s; x = [ 0.18932428 -0.74577734  0.5866311  -0.48353864]
t = 1.96s; x = [ 0.19508583 -0.75033439  0.56562291 -0.42781882]
t = 1.97s; x = [ 0.2006356  -0.75433272  0.54427343 -0.37179784]
t = 1.98s; x = [ 0.20597019 -0.75776942  0.52259007 -0.31549682]
t = 1.99s; x = [ 0.21108631 -0.76064179  0.50058022 -0.25893623]
t = 2.0s; x = [ 0.21598073 -0.76294734  0.4782513  -0.20213597]
<SpStatusEnum.REACHED_END_TIME: 1>
web_scene.renderToFile("render.png")
display(Image("render.png"))
../../../_images/41f73c825a86fb8e82bf4cb4b00c70f87be0d1a5ed497dd1fa27777e03552a3d.png

Cleanup#

def cleanup():
    """Cleanup the simulation."""
    global integ, bd1, bd2, bd1_part, bd2_part, root_scene_node, web_scene, proxy_scene
    del integ, bd1, bd2, bd1_part, bd2_part, root_scene_node, web_scene, proxy_scene

    discard(sp)
    cleanup_graphics()

    fc = mb.frameContainer()
    discard(mb)
    discard(fc)


atexit.register(cleanup)
<function __main__.cleanup()>

Summary#

You now know how to add visual geometries to a simulation and render to a file.