Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
R
robotarm-simulator
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Henrik Lindgren
robotarm-simulator
Commits
fe3fcde2
Commit
fe3fcde2
authored
2 years ago
by
Henrik Lindgren
Browse files
Options
Downloads
Patches
Plain Diff
add control panel and pose feature
parent
63d8dee3
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
exporter.py
+166
-29
166 additions, 29 deletions
exporter.py
with
166 additions
and
29 deletions
exporter.py
+
166
−
29
View file @
fe3fcde2
...
...
@@ -3,9 +3,15 @@ import json
import
bpy
from
bpy_extras.io_utils
import
ExportHelper
from
bpy.props
import
StringProperty
from
bpy.props
import
StringProperty
,
IntProperty
,
PointerProperty
from
bpy.types
import
Operator
import
requests
DOFBOT_IP
=
'
192.168.50.172
'
DOFBOT_PORT
=
5000
def
print
(
data
):
for
window
in
bpy
.
context
.
window_manager
.
windows
:
...
...
@@ -33,17 +39,17 @@ def get_servo_objects():
def
get_moving_angle
(
servo_name
,
rot_deg
):
if
servo_name
==
'
bottom_rotation
'
:
return
rot_deg
.
z
return
rot_deg
.
z
+
90
if
servo_name
==
'
joint_1
'
:
return
rot_deg
.
y
return
rot_deg
.
y
+
90
if
servo_name
==
'
joint_2
'
:
return
rot_deg
.
y
return
rot_deg
.
y
+
90
if
servo_name
==
'
joint_3
'
:
return
rot_deg
.
y
return
rot_deg
.
y
+
90
if
servo_name
==
'
claw_rotation
'
:
return
rot_deg
.
z
return
rot_deg
.
z
+
90
if
servo_name
==
'
claw_grip
'
:
return
rot_deg
.
x
return
rot_deg
.
x
*
2
def
frame2time
(
frame
):
...
...
@@ -58,9 +64,15 @@ class RotationDegrees:
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_angle
(
servo_object
):
rot_deg
=
RotationDegrees
(
servo_object
.
rotation_euler
)
angle
=
get_moving_angle
(
servo_object
.
name
,
rot_deg
)
# print((frame, servo_object.name, angle, servo_object.rotation_euler))
return
angle
def
get_servo_data
():
frame_range
=
range
(
bpy
.
context
.
scene
.
frame_start
,
bpy
.
context
.
scene
.
frame_end
+
1
)
...
...
@@ -68,21 +80,35 @@ def get_servo_data():
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
)
angle
=
get_servo_angle
(
obj
)
if
previous_angle
==
angle
:
continue
previous_angle
=
angle
yield
(
obj
.
name
,
[
frame2time
(
frame
),
angle
])
bpy
.
context
.
scene
.
frame_set
(
1
)
def
collect_servo_data_snapshot
():
servos
=
{
'
bottom_rotation
'
:
[],
'
joint_1
'
:
[],
'
joint_2
'
:
[],
'
joint_3
'
:
[],
'
claw_rotation
'
:
[],
'
claw_grip
'
:
[]
}
for
obj
in
get_servo_objects
():
angle
=
get_servo_angle
(
obj
)
servos
[
obj
.
name
].
append
([
2000
,
angle
])
return
servos
def
c
alc
_servo_data
():
def
c
ollect
_servo_data
():
servos
=
{
'
bottom_rotation
'
:
[],
'
joint_1
'
:
[],
...
...
@@ -98,10 +124,44 @@ def calc_servo_data():
return
servos
class
DofbotProperties
(
bpy
.
types
.
PropertyGroup
):
dofbot_ip
:
StringProperty
(
name
=
"
IP
"
,
description
=
"
The IP address of the Dofbot
"
,
default
=
DOFBOT_IP
,
)
dofbot_port
:
StringProperty
(
name
=
"
Port
"
,
description
=
"
The port of the Dofbot control API
"
,
default
=
str
(
DOFBOT_PORT
),
)
class
DofbotRunAnimation
(
Operator
):
"""
Run animation on dofbot
"""
bl_label
=
"
Run animation
"
bl_idname
=
"
dofbot.run_animation
"
def
execute
(
self
,
context
):
run_animation
()
return
{
'
FINISHED
'
}
class
DofbotSetCurrentPose
(
Operator
):
"""
Set Dofbot to the current pose
"""
bl_label
=
"
Set pose
"
bl_idname
=
"
dofbot.set_current_pose
"
def
execute
(
self
,
context
):
set_current_pose
()
return
{
'
FINISHED
'
}
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
"
bl_idname
=
'
dofbot.export_
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
"
...
...
@@ -113,31 +173,108 @@ class ExportDofbotAnimation(Operator, ExportHelper):
)
def
execute
(
self
,
context
):
servo_data
=
c
alc
_servo_data
()
servo_data
=
c
ollect
_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
"
)
class
ExportDofbotPose
(
Operator
,
ExportHelper
):
"""
Exports Dofbot pose as json
"""
bl_idname
=
'
dofbot.export_json_pose
'
# important since its how bpy.ops.import_test.some_data is constructed
bl_label
=
''
# "Export Dofbot Json Pose"
# 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
=
collect_servo_data_snapshot
()
with
open
(
self
.
filepath
,
'
w
'
)
as
f
:
f
.
write
(
json
.
dumps
(
servo_data
))
return
{
'
FINISHED
'
}
class
DofbotPanel
(
bpy
.
types
.
Panel
):
"""
Open Dofbot Control Panel
"""
bl_label
=
'
Dofbot Control
'
bl_idname
=
'
wm.dofbot_panel
'
bl_space_type
=
'
VIEW_3D
'
bl_region_type
=
'
UI
'
bl_category
=
'
Dofbot Control
'
def
draw
(
self
,
context
):
layout
=
self
.
layout
dofbot
=
context
.
scene
.
dofbot
row
=
layout
.
row
()
row
.
prop
(
dofbot
,
'
dofbot_ip
'
)
row
=
layout
.
row
()
row
.
prop
(
dofbot
,
'
dofbot_port
'
)
row
=
layout
.
row
()
row
.
operator
(
'
dofbot.run_animation
'
,
icon
=
'
PLAY
'
)
row
.
operator
(
'
dofbot.export_json_animation
'
,
icon
=
'
EXPORT
'
)
row
=
layout
.
row
()
row
.
operator
(
'
dofbot.set_current_pose
'
,
icon
=
'
FF
'
)
row
.
operator
(
'
dofbot.export_json_pose
'
,
icon
=
'
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
(
DofbotProperties
)
bpy
.
types
.
Scene
.
dofbot
=
PointerProperty
(
type
=
DofbotProperties
)
bpy
.
utils
.
register_class
(
DofbotPanel
)
bpy
.
utils
.
register_class
(
DofbotRunAnimation
)
bpy
.
utils
.
register_class
(
DofbotSetCurrentPose
)
bpy
.
utils
.
register_class
(
ExportDofbotAnimation
)
bpy
.
types
.
TOPBAR_MT_file_export
.
append
(
menu_func_export
)
bpy
.
utils
.
register_class
(
ExportDofbotPose
)
def
unregister
():
bpy
.
utils
.
unregister_class
(
DofbotProperties
)
del
bpy
.
types
.
scene
.
dofbot
bpy
.
utils
.
unregister_class
(
DofbotPanel
)
bpy
.
utils
.
unregister_class
(
DofbotRunAnimation
)
bpy
.
utils
.
unregister_class
(
DofbotSetCurrentPose
)
bpy
.
utils
.
unregister_class
(
ExportDofbotAnimation
)
bpy
.
types
.
TOPBAR_MT_file_export
.
remove
(
menu_func_export
)
bpy
.
utils
.
unregister_class
(
ExportDofbotPose
)
def
send_motion
(
servo_data
):
requests
.
post
(
'
http://
'
+
DOFBOT_IP
+
'
:
'
+
str
(
DOFBOT_PORT
)
+
'
/motion
'
,
json
=
servo_data
)
def
run_animation
():
servo_data
=
collect_servo_data
()
send_motion
(
servo_data
)
def
set_current_pose
():
servo_data
=
collect_servo_data_snapshot
()
send_motion
(
servo_data
)
def
export_animation
():
bpy
.
ops
.
export_dofbot
.
json_animation
(
'
INVOKE_DEFAULT
'
)
if
__name__
==
"
__main__
"
:
register
()
# test call
bpy
.
ops
.
export_dofbot
.
json_animation
(
'
INVOKE_DEFAULT
'
)
# # test call
# bpy.ops.export_dofbot.json_animation('INVOKE_DEFAULT')
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment