Add a 3D model
6 minute read
The last step gives your dashboard a digital twin: a 3D model of your robot or machine in the Grid 3D widget, with its parts moved by parameters from your application. The guide below is the 3D models page of the Grid documentation, shown here so you can finish the walkthrough without leaving it.
The Grid 3D widget shows a 3D model, a digital twin, of your robot or machine, and moves its parts with live parameters from your application: a joint turns when the real joint turns. You build the model in Blender or a CAD tool, export it as a glTF file, and write a small JSON file that links each moving part to a parameter.
The video shows the whole workflow, from creating a model to linking it to an application:
Prepare the model
The widget moves an object by setting its position, rotation or scale relative to its parent. So how you build the model decides how it moves:
- Build with z up. The camera treats z as up. In Blender’s glTF exporter, switch +Y Up off under Transform.
- Put each moving part’s origin at its pivot. In Blender, place the 3D cursor on the joint and use Object > Set Origin > Origin to 3D Cursor.
- Parent the parts in a chain, base to tool, so each part moves with the one before it.
- Apply rotation and scale to every moving part (Object > Apply > Rotation & Scale), so its local axes line up with the joint.
- Give moving parts simple names, without spaces, dots or other special characters. See the name rules below.
- Export as
.glb, the binary format. Tick Apply Modifiers under Geometry if you use modifiers.
Keep the file small, so the dashboard loads quickly on a tablet: the stock robot models are 4 to 8 MB. There is no hard limit. Draco-compressed files are not supported. A .gltf text file also works, as long as its buffers and textures are embedded in it.
How object names change on import
The importer changes some characters in object names. Use the changed name in the JSON file:
| In Blender | In the widget | Example |
|---|---|---|
| A space | Becomes _ |
Upper Arm becomes Upper_Arm |
. : / [ ] |
Removed | Cube.001 becomes Cube001 |
| The same name twice in one file | _1, _2 and so on are added |
The second Link becomes Link_1 |
The widget writes the loaded scene to the browser console, so you can look up the final names there.
Write the model JSON
The JSON file tells the widget which model files to load and which parameter moves which object. The paths of model files are relative to the JSON file. This minimal file loads one model and turns the object Link1 with the first joint position:
{
"files": [
{ "file": "robot.glb" }
],
"objects": [
{
"name": "Link1",
"links": [
{ "link": "root/ManipulatorControl/jointPositionsActual", "channel": 0, "axis": "rz" }
]
}
]
}
Each entry in links has these fields:
| Field | What it does | Default |
|---|---|---|
link |
The parameter path. Required | |
channel |
The element of an array parameter. Ignored for a single value | 0 |
axis |
What the value sets, see the next table. Required | |
gain, offset |
The widget uses value × gain + offset |
1, 0 |
value |
A fixed value, used while the parameter has no data |
axis |
Sets | Values read |
|---|---|---|
x, y, z |
Position along one local axis, in m | 1 |
rx, ry, rz |
Rotation about one local axis, in rad | 1 |
position |
Position x, y, z | 3, from channel on |
rotationZYX |
Rotation z, y, x | 3, from channel on |
pose |
Position x, y, z, then rotation z, y, x: a pose such as a tool pose | 6, from channel on |
s, sx, sy, sz |
Scale: all axes, or one | 1 |
visible |
Shows the object when the value is 0.5 or more |
1 |
opacity |
Transparency, from 0 to 1 |
1 |
The widget does not convert units: positions are in metres and rotations in radians, relative to the object’s parent. For a parameter in degrees, use gain 0.0174533; for millimetres, 0.001.
Example: the joints of a stock robot
The 3D model of the store package MCX-Anthropomorphic-Robot.gui links every joint the same way. Joint 1 turns Link1 about its z axis:
{
"name": "Link1",
"link": "root/ManipulatorControl/jointPositionsActual",
"channel": 0,
"axis": "rz",
"castShadow": true,
"addEnvironmentMap": true
}
This older form puts link, channel and axis directly on the object, for a single link. The tool frame follows the tool pose with "axis": "pose" on root/ManipulatorControl/manipulatorToolPoseActual.
To find an object inside another one, separate the names with *: "Robot2*Link1" finds Link1 under Robot2. Use this when you load two models with the same object names. Give each one its own name in files, because duplicates across files are not renamed.
The file can also set the camera, lights, an environment map and a trace line of the tool path. See the model JSON reference for every option.
Add it to the dashboard
- Upload the model files and the JSON file to your Grid project, in the same folder or with matching relative paths.
- Add a 3D widget to your canvas.
- In its model property, select the JSON file.
The widget has two more settings: frequency divider, how often the parameters update (default 100), and disable view navigation, which locks the camera.
Things to know
- Materials are shared.
opacitychanges the object’s material, and every other object in the same file that uses that material changes with it. Give an object its own material before you make it transparent. - Shadows cost computing power. Objects cast no shadows unless you set
castShadoworreceiveShadowon them. Keep these to a few objects on slower devices. - Only changed values are applied, so a parameter that does not change does not cost anything.
Next: Step 7: final check, to test every step.