3

I'm hoping to 3D print a simple robot controlled by an Arduino microcontroller, but first I am prototyping the design in Blender — I'm experimenting with controls, movements, actions etc. How do I move/rotate part of the robot in Blender — let's say "Robot_Arm_Lower" — to a predefined position? It only needs to be a simple button somewhere that just executes a basic command along the lines of "on button press move 'Robot_Arm_Lower' by rotating xyz and moving to location xyz". I'm guessing I need a simple Python script but I'm not sure where to start.

Hope that makes sense? Thank you.

Ben Clarke
  • 153
  • 5

2 Answers2

4

I put together a small addon for you:

bl_info = {
    "name": "Move & rotate",
    "blender": (2, 80, 0),
    "location": "VIEW_3D > Tools > Move and rotate"
    }

import bpy
from bpy.types import (Panel,Operator,AddonPreferences,PropertyGroup)

xyz_rot = (0,0,0)
xyz_loc = (1,1,1)

class MYADDON_OT_rotate_obj(bpy.types.Operator):
    """rotate the obj"""
    bl_idname = "myops.rotate_obj"
    bl_label = "rotate_obj"

    def execute(self, context):
        #convert degrees to radians
        x = xyz_rot[0]*pi/180
        y = xyz_rot[1]*pi/180
        z = xyz_rot[2]*pi/180
        xyz_rot = (x,y,z)

        #Rotates all the selected objects: if you know the name of the obj you want to rotate use
        #bpy.data.objects["Robot_Arm_Lower"].rotation_euler = xyz_rot
        for obj in bpy.context.selected_objects:
            obj.rotation_euler = xyz_rot
        return {'FINISHED'}

class MYADDON_OT_move_obj(bpy.types.Operator):
    """move the obj"""
    bl_idname = "myops.move_obj"
    bl_label = "move_obj"

    def execute(self, context):
        #moves all the selected objects: if you know the name of the obj you want to move use
        #bpy.data.objects["Robot_Arm_Lower"].location = xyz_loc
        for obj in bpy.context.selected_objects:
            obj.location = xyz_loc
        return {'FINISHED'}
#-------------------UI-----------------------------------------------------

class MYOPS_PT_move_obj(bpy.types.Panel):
    """Creates a Panel in the Tool tab"""
    bl_label = "Rotate & Move"
    bl_idname = "MYOPS_PT_move_obj_ui"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Rotate & move"
    bl_context = "objectmode"

    @classmethod
    def poll(self,context):
        return True

    def draw(self, context):
        layout = self.layout
        scene = context.scene

        #Label
        layout.operator("myops.rotate_obj", text = "Rotate")
        layout.operator("myops.move_obj", text = "Move")

#-------------REGISTRATION--------------------
classes = (
    MYADDON_OT_rotate_obj,
    MYADDON_OT_move_obj,
    ROTATE_MOVE_PT_tool,
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)

if __name__ == "__main__":
    register()
    #Sometimes i get some registration errors when debugging an addon. If you get the same error try uncommenting the following lines
    #unregister()
    #register()

you may want to modify it to fit your needs: for example you may want to create 2 sliders to control the xyz_rot and xyz_loc from the UI without having to re-run the addon (btw, you don't need to install it from the user preferences like normal addons, you can just use it like a script if you want).

the addon/script creates a panel in the tool tab, but feel free to move it where you want The custom panel is on the top right


EDIT

As you mention in the comment you are running Blender 2.79b and you don't know how to use python, so you could try to use the following script:

import bpy
from math import pi

#change your parameters here
move = True          #If "True" the objects move: write "False" to disable it
rotate = True        #If "True" the objects rotate: write "False" to disable it
xyz_rot = (0,0,0)    #What rotation you want your objects to have (in degrees)
xyz_loc = (1,1,1)    #What position you want your objects to have
objName = ""         #The name of the object you want to move/rotate, if you need to move one object only.
#                     If you leave it as "" the script will move/rotate all the selected objects. (Recommended)

# ------------- CODE ----------------
#Rotates all the selected objects (or the desired object if objName is not "")
if rotate:
    #convert degrees to radians
    x = xyz_rot[0]*pi/180
    y = xyz_rot[1]*pi/180
    z = xyz_rot[2]*pi/180
    xyz_rot = (x,y,z)

    if objName == "":
        for obj in bpy.context.selected_objects:
            obj.rotation_euler = xyz_rot
    else:
        bpy.data.objects[objName].rotation_euler = xyz_rot


#Moves all the selected objects (or the desired object if objName is not "")
if move:
    if objName == "":
        for obj in bpy.context.selected_objects:
            obj.location = xyz_loc
    else:
        bpy.data.objects[objName].location = xyz_loc

To run it, just paste it in the text editor, play with the parameters at the top and hit the "run script" button.

Every time you run it the selected objects (or the object you put in objName) will rotate and/or move based on the two flags ("move" and "rotate") and the two "xyz_loc" and "xyz_rot".

This should work both in 2.79 and 2.80, but you don't get the fancy panel and buttons of the precedent code

Tareyes
  • 1,794
  • 6
  • 18
  • 2
    Please try to adhere to blender's class naming convention https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Python_API/Addons – batFINGER Aug 12 '19 at 11:54
  • 2
    Oh sorry, I'm still new to that convenction ahah – Tareyes Aug 12 '19 at 13:05
  • Wow, thank you @Tareyes for taking the time to write that code. Unfortunately I should've mentioned that I'm a complete noob to Python and Blender scripting so I'm not sure where to start. Do I just copy and paste that code into the Python script console? I tried that and nothing happened. I should point out that I'm using Blender 2.79b if that makes any difference? Maybe I'm trying to run before I can walk? I just assumed I could write some simple code and it would work — I'm fairly experienced with JavaScript coding so I suppose I naively thought it would be very similar. Thanks again – Ben Clarke Aug 13 '19 at 02:45
  • 1
    @BenClarke I edited my answer with a second script that should work in your case. To run it you need to paste it in the text editor (not the python console: that allows you to insert only one line of code at the time) and press "run script" – Tareyes Aug 13 '19 at 13:07
  • Thank you again @Tareyes. With the help of your code I managed to achieve what I was aiming for. See answer below. Couldn't have got there without your help! :) – Ben Clarke Aug 13 '19 at 13:56
0

Okay, so thanks to the answers above I managed to do what I was aiming for (kind of). I've now got a custom panel in the Blender UI that performs specific movements/rotations when certain buttons are pressed. It is currently VERY basic but I am brand new to Python and Blender scripting so hopefully I will build upon this code during this project.

The current working version of the code is below (Blender 2.79b). Thanks for everyone's help that enabled me to get to this stage :)

bl_info = {
"name": "Robot Controls",
"blender": (2, 79, 0)
}

import bpy
from bpy.types import (Panel,Operator,PropertyGroup)

# Import math to convert radians to degrees
from math import pi

# This is just a simple object to hold some location/rotation variables
class ROBOT_ARM_L:
    Rx = 90*(pi/180)
    Ry = 0
    Rz = 0
    rotateTo = (Rx,Ry,Rz)    
    moveTo = (0.053666,-2.17661,0.706597)

# ------------------------------------------------------------------------
#    Rotate - This performs the rotation
# ------------------------------------------------------------------------

class ROBOT_ARM_L_OT_rotate_obj(bpy.types.Operator):
    bl_idname = "myops.rotate_obj"
    bl_label = "rotate_obj"

    def execute(self, context):
        obj = bpy.data.objects["Robot_Arm_Lower"]
        obj.rotation_euler = ROBOT_ARM_L.rotateTo
        return {'FINISHED'}

# ------------------------------------------------------------------------
#    Move - This performs the movement (location)
# ------------------------------------------------------------------------

class ROBOT_ARM_L_OT_move_obj(bpy.types.Operator):
    bl_idname = "myops.move_obj"
    bl_label = "move_obj"

    def execute(self, context):
        obj = bpy.data.objects["Robot_Arm_Lower"]
        obj.location = ROBOT_ARM_L.moveTo
        return {'FINISHED'}

# ----------------------------------------------------------------------------
#    Panel - This creates the custom panel/buttons in the UI 
# ----------------------------------------------------------------------------

class OBJECT_PT_CustomPanel(Panel):
    bl_idname = "object.custom_panel"
    bl_label = "Robot Controls"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "TOOLS"    
    bl_category = "Tools"
    bl_context = "objectmode"   

    @classmethod
    def poll(self,context):
        return True

    def draw(self, context):
        layout = self.layout
        scene = context.scene

        #Label
        layout.operator("myops.rotate_obj", text = "Left Arm Rotate")
        layout.operator("myops.move_obj", text = "Left Arm Move")    

# ------------------------------------------------------------------------
#    Registration
# ------------------------------------------------------------------------

def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)
    del bpy.types.Scene.my_tool

if __name__ == "__main__":
    register()


The above code results in this custom panel:

enter image description here

Ben Clarke
  • 153
  • 5
  • Glad to help, and if I were you I would try Blender 2.8 – Tareyes Aug 14 '19 at 15:09
  • Just to let you know, it's your decision... If you are accepting your own answer, you don't get any extra reputation. In case you accept the other answer (which isn't really different in comparison) Tareyes will gain a little bit of extra rep (15) for all the effort. – brockmann Aug 15 '19 at 11:38
  • Sure, no problem. I'm not trying to increase my rep — I'm just here for knowledge! :) – Ben Clarke Aug 15 '19 at 11:48
  • lol, thanks you guys ahah – Tareyes Aug 16 '19 at 08:54
  • @Tareyes Can you help me please to modify your script so that I can translate a bone in a rig when you press a button 1 moves bone 'abc' x=1 LOCAL and the other button 2 x=0 LOCAL? – Eric Huelin May 10 '20 at 16:56
  • @EricHuelin I'm sorry, I'm not sure I understood what you mean, I think you should probably create a new question, maybe with a link to this one, so that you have the space to explain a bit better, and maybe provide some examples – Tareyes May 11 '20 at 17:48
  • @Tareyes I will pose a question so you can merit the well deserved rewards, the question was just how to make: press a button = bone translates = keyframes that event. The bone is in an armature. – Eric Huelin May 11 '20 at 18:26
  • @EricHuelin You can use the code I wrote, you just need to change how you access your object: I don't know what is your knowledge of Python, but you can just select the armature and access its bones like any other object (for help ust google how to access an armature's bones or look at it in the Python console). as for the keyframes, you don't need scripting, since you can activate the auto keyframes (every time you move an objects, it places a keyframe there). – Tareyes May 18 '20 at 08:38
  • @Tareyes I posted my question because I only know how to use Python scripts with already written and I either change or copy/paste code but I never found anything that controls a bone or I would have not end up here, here is my last resort. – Eric Huelin May 18 '20 at 19:59
  • @EricHuelin Actually it's just copy paste: https://blenderartists.org/t/using-bone-translate-to-move-a-bone/511333/7

    There are pleanty of resources on bones and other primitive functionality in Python, a Google search will show you them. In particular in the execute() function of the classes you need to select the bones instead of the object and change the location of both the tail and the head of the bone (something like bpy.data.objects["Armature"].data.edit_bones["Bone"].translate(new_position). It's really simple actually, just take a look on google, you might learn a lot ;)

    – Tareyes May 26 '20 at 12:20