Instructions to use JackDH/microduck-rolling-start with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Microduck
How to use JackDH/microduck-rolling-start with Microduck:
# Replace SLOT with the slot specified in the model card (walk, stand, sitstand, ground_pick, kick_left, kick_right, roulade). sudo robotctl policy load SLOT JackDH/microduck-rolling-start
- Notebooks
- Google Colab
- Kaggle
File size: 4,266 Bytes
b791e4c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | """Export the skating, rolling and learned landing actions as one ONNX policy."""
import learn
import numpy as np
import onnx
from onnx import TensorProto, helper, numpy_helper
def export(weights, destination):
nodes, constants = [], []
def constant(name, value, dtype=np.float32):
constants.append(numpy_helper.from_array(np.asarray(value, dtype=dtype), name))
return name
def node(kind, name, *inputs, **attributes):
nodes.append(helper.make_node(kind, inputs, [name], name=name, **attributes))
return name
def column(name, ix):
return node(
"Gather", name, "obs", constant(name + "_idx", [ix], np.int64), axis=1
)
def scaled_clip(value, factor, name):
scaled = node(
"Mul", name + "_scaled", value, constant(name + "_factor", factor)
)
return node("Clip", name, scaled, neg_one, one)
zero = constant("zero", 0)
one = constant("one", 1)
neg_one = constant("neg_one", -1)
cue = column("cue", 60)
phase = [
node("Greater", "after_" + str(i), cue, constant("boundary_" + str(i), i + 0.5))
for i in range(5)
]
models = {}
for name in learn.BASE_MODELS:
file = learn.model_file(name)
source = onnx.compose.add_prefix(onnx.load(str(file)), name + "/")
scale = 1.12 if name == "roll" else 1.0
divisor = np.ones(61, np.float32)
divisor[34:48] = scale
mask = np.ones(61, np.float32)
mask[48 if name == "roll" else 49 :] = 0
prepared = node(
"Div", name + "_obs", "obs", constant(name + "_divisor", divisor)
)
node(
"Mul", source.graph.input[0].name, prepared, constant(name + "_mask", mask)
)
nodes.extend(source.graph.node)
constants.extend(source.graph.initializer)
models[name] = node(
"Mul",
name + "_action",
source.graph.output[0].name,
constant(name + "_gain", scale),
)
base = node("Where", "recovery_base", phase[3], models["rise"], models["roll"])
arr = np.asarray(weights, np.float32)
biases = arr[:24].reshape(4, 6)
bias = constant("phase2", biases[0])
for n in range(1, 4):
bias = node(
"Where",
"bias" + str(n),
phase[n + 1],
constant("phase" + str(n + 2), biases[n]),
bias,
)
pitch_gravity = column("pitch_gravity", 3)
roll_gravity = column("roll_gravity", 4)
pitch_rate = scaled_clip(column("pitch_rate_body", 1), 0.14, "pitch_rate")
roll_rate = scaled_clip(column("roll_rate_body", 0), 0.15, "roll_rate")
def vector_term(obs, name, arr):
return node("Mul", name, obs, constant(name + "_weights", arr))
# Sum the feedback before adding the offsets, as in the trained policy.
pitch_terms = node(
"Add",
"pitch_feedback",
vector_term(pitch_gravity, "pitch_gravity_term", arr[24:27]),
vector_term(pitch_rate, "pitch_rate_term", arr[27:30]),
)
roll_terms = node(
"Add",
"roll_feedback",
vector_term(roll_gravity, "roll_gravity_term", arr[30]),
vector_term(roll_rate, "roll_rate_term", arr[31]),
)
zeros = node("Mul", "zeros", pitch_rate, zero)
feedback = node("Concat", "feedback", pitch_terms, zeros, zeros, roll_terms, axis=1)
activated = node("Tanh", "bounded", node("Add", "raw", bias, feedback))
adjustment = node(
"MatMul", "joint_adjustment", activated, constant("joint_map", learn.MAP)
)
corrected = node("Add", "corrected", base, adjustment)
roll_or_recovery = node("Where", "trick", phase[1], corrected, base)
node("Where", "actions", phase[0], roll_or_recovery, models["skate"])
graph = helper.make_graph(
nodes,
"skate_land_skate",
[helper.make_tensor_value_info("obs", TensorProto.FLOAT, [1, 61])],
[helper.make_tensor_value_info("actions", TensorProto.FLOAT, [1, 14])],
constants,
)
model = helper.make_model(
graph, ir_version=8, opset_imports=[helper.make_opsetid("", 18)]
)
onnx.checker.check_model(model, full_check=True)
onnx.save(model, str(destination))
|