Brick.AGX python interface development
Project description
BRICK AGX
The brickagx package implements all Brick bundles such as Physics, Robotics, DriveTrain and Simulation using AGX Dynamics Real-time multi-body simulation. The package contains python bindings and native libraries needed to load and run .brick files.
Prerequisites
- Python 3.9 on Windows or OSX
- Python 3.8 on Ubuntu 20.04
- Python 3.10 on Ubuntu 22.04
- AGX Dynamics and an AGX Dynamics License
BRICK version | Requires AGX Dynamics version |
---|---|
0.0.14 - 0.0.15 | 2.36.1.4 |
0.0.16 - 0.0.27 | 2.36.1.5 |
0.1.0 | 2.36.1.5 |
0.2.0 - 0.2.1 | 2.37.0.1 |
0.3.0 - | 2.37.1.0 |
Install
To get the version corresponding to your AGX on Windows do:
setup_env.bat
pip install %AGX_DATA_DIR%/agx-pypi
pip install -U brickagx
To get the version corresponding to your AGX on OSX and Linux do:
source setup_env.sh
pip3 install $AGX_DATA_DIR/agx-pypi
pip3 install -U brickagx
License
Usage Examples
Given the python file and brick file below, run with:
python3 inverted_pendulum.py
To just simulate the brick file without controllers, do:
brickview inverted_pendulum.brick
or python3 -m rebrick.view inverted_pendulum.brick
Store contents below in a new file named inverted_pendulum.brick
:
Rod is Physics3D.RigidBody:
inertia.mass: 10
geometry is Physics3D.Box:
size: Math.Vec3.fromXYZ(0.1, 0.1, 1)
arrow is Physics3D.Box:
local_transform:
position.z: 0.5
rotation: Math.Quat.angleAxis(Math.PI / 4, Math.Vec3.Y_AXIS())
size: Math.Vec3.fromXYZ(0.071, 0.1, 0.071)
mate_connector is Physics3D.MateConnector:
position.z: -geometry.size.z * 0.7
main_axis: Math.Vec3.Y_AXIS()
normal: Math.Vec3.Z_AXIS()
Cart is Physics3D.RigidBody:
inertia.mass: 10
geometry is Physics3D.Box:
size: Math.Vec3.fromXYZ(0.1, 0.1, 0.1)
connector is Physics3D.MateConnector:
main_axis: Math.Vec3.X_AXIS()
normal: Math.Vec3.Z_AXIS()
rotated_connector is Physics3D.MateConnector:
main_axis: Math.Vec3.Y_AXIS()
normal: Math.Vec3.Z_AXIS()
PendulumScene is Physics3D.System:
world_connector is Physics3D.MateConnector:
main_axis: Math.Vec3.X_AXIS()
normal: Math.Vec3.Z_AXIS()
cart is Cart
rod is Rod
prismatic is Physics3D.Prismatic:
charges: [world_connector, cart.connector]
cart_motor is Physics3D.LinearVelocityMotor:
desired_speed: 0
charges: prismatic.charges
hinge is Physics3D.Hinge:
initial_angle: 0
charges: [cart.rotated_connector, rod.mate_connector]
motor_input is Simulation.LinearVelocityMotorVelocityInput:
motor: cart_motor
hinge_angle_output is Simulation.HingeAngleOutput:
hinge: hinge
hinge_angular_velocity_output is Simulation.HingeAngularVelocityOutput:
hinge: hinge
cart_position_output is Simulation.RigidBodyPositionOutput:
rigid_body: cart
cart_velocity_output is Simulation.RigidBodyVelocityOutput:
rigid_body: cart
Store contents below in a new file named inverted_pendulum.py
:
import agxOSG
import agxSDK
import os
import signal
from brickbundles import bundle_path
# Import useful utilities to access the current simulation, graphics root and application
from agxPythonModules.utils.environment import init_app, simulation, root
from rebrick import Math, Simulation, Signals
from rebrick import InputSignalListener, OutputSignalListener, load_brick_file
def file_dir():
return os.path.dirname(os.path.abspath(__file__))
def pendulum():
return f"{file_dir()}/inverted_pendulum.brick"
class PDController:
def __init__(self, kp, kd, goal):
self.kp = kp
self.kd = kd
self.goal = goal
def observe(self, x, xdot):
error = self.goal - x
return self.kp * error - self.kd * xdot
class CartController(agxSDK.StepEventListener):
motor_input: Simulation.LinearVelocityMotorVelocityInput
cart: PDController
pole: PDController
def __init__(self, motor_input: Simulation.LinearVelocityMotorVelocityInput):
super().__init__()
self.motor_input = motor_input
self.cart = PDController(kp=10, kd=5, goal=0)
self.pole = PDController(kp=20, kd=5, goal=0)
def pre(self, t):
if t == 0.0:
hinge_angle = 0
hinge_angular_velocity = 0
cart_position = Math.Vec3.fromXYZ(0,0,0)
cart_velocity = Math.Vec3.fromXYZ(0,0,0)
else:
signal_values = {signal.source().getName():signal.value() for signal in Signals.getOutputSignals()}
hinge_angle = signal_values["PendulumScene.hinge_angle_output"]
hinge_angular_velocity = signal_values["PendulumScene.hinge_angular_velocity_output"]
cart_position = signal_values["PendulumScene.cart_position_output"]
cart_velocity = signal_values["PendulumScene.cart_velocity_output"]
u_cart = self.cart.observe(cart_position.x(), cart_velocity.x())
u_pole = self.pole.observe(hinge_angle, hinge_angular_velocity)
Signals.sendInputSignal(Simulation.RealInputSignal.create(-u_cart - u_pole, self.motor_input))
def buildScene():
result = load_brick_file(simulation(), pendulum(), bundle_path(), "")
assembly = result.assembly()
brick_scene = result.brick_object()
# Add a signal listener so that signals are picked up from inputs
input_signal_listener = InputSignalListener(assembly)
output_signal_listener = OutputSignalListener(assembly, brick_scene)
simulation().add(input_signal_listener, InputSignalListener.RECOMMENDED_PRIO)
simulation().add(output_signal_listener, OutputSignalListener.RECOMMENDED_PRIO)
simulation().add(assembly.get())
agxOSG.createVisual(assembly.get(), root())
motor_input: Simulation.LinearVelocityMotorVelocityInput = brick_scene.getDynamic("motor_input").asObject()
controller = CartController(motor_input)
simulation().add(controller)
def handler(signum, frame):
os._exit(0)
signal.signal(signal.SIGINT, handler)
init = init_app(name=__name__,
scenes=[(buildScene, '1')],
autoStepping=True, # Default: False
onInitialized=lambda app: print('App successfully initialized.'),
onShutdown=lambda app: print('App successfully shut down.'))
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Hashes for brickagx-0.3.0-cp310-cp310-manylinux_2_35_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a6f41e718d958301ed58cb6c7e53b93a2be0a8cda777449edfe3aa14b9c6027a |
|
MD5 | 80905815f6d5b711a84a95eba52e08c5 |
|
BLAKE2b-256 | 720cd9f08c6e4d76900a8dd4eeb7abd96c53ec25fce6ccb8c9560c10ce15f7f9 |
Hashes for brickagx-0.3.0-cp39-cp39-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 06630a78688f5ffd9ce92e3b2e86ef05d3616052f388697848c234e7808d057e |
|
MD5 | 1479c05a79317a72ed568e9811f414a1 |
|
BLAKE2b-256 | 493882fa3f91244f640d44b0460c856e858d31eeaaea500f1e72cda5204829be |
Hashes for brickagx-0.3.0-cp39-cp39-macosx_12_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | efa43328899c678aad9e50d0b6d994c6aa49b2968942457003fd67884a10ae51 |
|
MD5 | 37f0cf23d5e2320c7720efb48a6e6cdb |
|
BLAKE2b-256 | f93e9f73eee37fe1f5b95190472b828ad4731d11167168cd6a0e746eda91c9d2 |
Hashes for brickagx-0.3.0-cp39-cp39-macosx_11_0_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8c4d35c7d235ced2ce537f0a14896d3d75747fa7b3cd84d1d3c69cb4e825ef1e |
|
MD5 | 833592ce82b1704759ea24b7a4aed743 |
|
BLAKE2b-256 | 61e05978f4e5cac64f0240eebc9038c7eed652c184b6a0b300182831162d7ddd |
Hashes for brickagx-0.3.0-cp38-cp38-manylinux_2_31_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6a678a02af0af163ee9f1d62f7dcf3cd55911263f847159863c2d21f6ada4ee2 |
|
MD5 | 99d9e31a7ce530dc70736f6d166cbfd0 |
|
BLAKE2b-256 | 1d7b3916a9d26aceb23fb97f1114c41ecfe61b7782ef3b0eeb4b361049a24216 |