Skip to content
Snippets Groups Projects
Commit 63d8dee3 authored by Henrik Lindgren's avatar Henrik Lindgren
Browse files

initial commit

parents
No related branches found
No related tags found
No related merge requests found
# Robotarm Simulator
Blender scene and export script for creating animations for the Dofbot robotic arm.
## Todo
- [ ] Add/subtract correct offsets to angles to match with Dofbot angles
- [ ] Add constraints to angles
- [ ] Fix mirrored part of claw
File added
import math
import json
import bpy
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty
from bpy.types import Operator
def print(data):
for window in bpy.context.window_manager.windows:
screen = window.screen
for area in screen.areas:
if area.type == 'CONSOLE':
override = {'window': window, 'screen': screen, 'area': area}
bpy.ops.console.scrollback_append(override, text=str(data), type="OUTPUT")
# Alternative way to get animation data
# Takes the keyframes instead of going through frame by frame
def get_animaiton_data(servo_object):
for fcurve in servo_object.animation_data.action.fcurves:
for keyframe_point in fcurve.keyframe_points:
yield keyframe_point.co
SERVO_NAMES = ['bottom_rotation', 'joint_1', 'joint_2', 'joint_3', 'claw_grip', 'claw_rotation']
def get_servo_objects():
return [bpy.data.objects[servo_name] for servo_name in SERVO_NAMES]
def get_moving_angle(servo_name, rot_deg):
if servo_name == 'bottom_rotation':
return rot_deg.z
if servo_name == 'joint_1':
return rot_deg.y
if servo_name == 'joint_2':
return rot_deg.y
if servo_name == 'joint_3':
return rot_deg.y
if servo_name == 'claw_rotation':
return rot_deg.z
if servo_name == 'claw_grip':
return rot_deg.x
def frame2time(frame):
fps = bpy.context.scene.render.fps
return int(frame/fps*1000)
class RotationDegrees:
def __init__(self, euler_rot):
self.x = round(math.degrees(euler_rot.x))
self.y = round(math.degrees(euler_rot.y))
self.z = round(math.degrees(euler_rot.z))
# This method of stepping through frame by frame and looking at the objects matrix_world
# was taken from the below export script by @astronotter
# https://gist.github.com/astronotter/faec735fc5e270df57741705052096ac
def get_servo_data():
frame_range = range(bpy.context.scene.frame_start, bpy.context.scene.frame_end + 1)
for obj in get_servo_objects():
previous_angle = None
for frame in frame_range:
bpy.context.scene.frame_set(frame)
matrix = obj.matrix_world.copy()
# posx, posy, posz = matrix.to_translation()[:]
# scalex, scaley, scalez = matrix.to_scale()[:]
rot_deg = RotationDegrees(matrix.to_euler())
angle = get_moving_angle(obj.name, rot_deg)
if previous_angle == angle:
continue
previous_angle = angle
yield (obj.name, [frame2time(frame), angle])
def calc_servo_data():
servos = {
'bottom_rotation': [],
'joint_1': [],
'joint_2': [],
'joint_3': [],
'claw_rotation': [],
'claw_grip': []
}
for servo_name, servo_data_point in get_servo_data():
servos[servo_name].append(servo_data_point)
return servos
class ExportDofbotAnimation(Operator, ExportHelper):
"""Exports Dofbot animation as json"""
bl_idname = "export_dofbot.json_animation" # important since its how bpy.ops.import_test.some_data is constructed
bl_label = "Export Dofbot Json Animation"
# ExportHelper mixin class uses this
filename_ext = ".json"
filter_glob: StringProperty(
default="*.json",
options={'HIDDEN'},
maxlen=255, # Max internal buffer length, longer would be clamped.
)
def execute(self, context):
servo_data = calc_servo_data()
with open(self.filepath, 'w') as f:
f.write(json.dumps(servo_data))
return {'FINISHED'}
# Only needed if you want to add into a dynamic menu
def menu_func_export(self, context):
self.layout.operator(ExportDofbotAnimation.bl_idname, text="Dofbot Animation Export")
# Register and add to the "file selector" menu (required to use F3 search "Text Export Operator" for quick access).
def register():
bpy.utils.register_class(ExportDofbotAnimation)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
def unregister():
bpy.utils.unregister_class(ExportDofbotAnimation)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
if __name__ == "__main__":
register()
# test call
bpy.ops.export_dofbot.json_animation('INVOKE_DEFAULT')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment