I made a code for my ESP32 to control my robotic arm ( 5 Axes ; 5 steppermotors ) when it gets coordinates through the serialport like e.g.: “1000, 1000, 1000, 1000, 1000.
Then, I have code in Blender witch should read the angles from the Bones of the 3d Moddel of the Arm witch I rigged up.
Somehow, only the first Coordinate seems to be right.
When the Arm is in its zeroposition, it gives me these coordinates: Sending angles: 0,0,0,29947,-29947 (these are wrong)
When I play the animation a little bit further, it gives me numbers, that are way to high, still zero and i’m not shure if it is correct that some are negative…
: 22874,0,-29947,0,-632
I don’t fully understand how and why it is reading the angles like this and I,m still very new.
I hope that somebody can help me out 😉
Blender Python Script:
import bpy
import math
import serial
import time
import threading
port = 'COM3'
# Thread lock for serial writing
serial_lock = threading.Lock()
# Connect to the serial port
try:
ser = serial.Serial(port, 9600)
print("Connected to: " + ser.portstr)
except serial.SerialException as e:
print(f"Could not open port {port}: {e}")
raise
armature_name = 'Armature'
# Function to get the armature object safely
def get_armature():
try:
ob = bpy.data.objects[armature_name]
bpy.context.view_layer.objects.active = ob
bpy.ops.object.mode_set(mode='POSE')
return ob
except KeyError:
print(f"Armature '{armature_name}' not found in the current scene")
return None
except ReferenceError:
print(f"ReferenceError: Armature '{armature_name}' has been removed")
return None
ob = get_armature()
if ob is None:
raise KeyError(f"Failed to initialize armature '{armature_name}'")
# Adding appropriate offsets for all 5 motors
offsets = [0, 0, 0, 0, 0]
gear_ratio = 5.5 * 5.5 * 5.5 #Planetary gearbox in the robotic arm
def get_local_orientation(pose_bone):
local_orientation = pose_bone.matrix.to_euler()
if pose_bone.parent is None:
return local_orientation
else:
x = local_orientation.x - pose_bone.parent.matrix.to_euler().x
y = local_orientation.y - pose_bone.parent.matrix.to_euler().y
z = local_orientation.z - pose_bone.parent.matrix.to_euler().z
return (x, y, z)
def sendAngles():
ob = get_armature()
if ob is None:
return
bones = [
'Dreinen', # first Bone
'LowerArm', # second bone
'UpperArm', # ...
'UpperArm2',
'UpperArm3'
]
if len(bones) != len(offsets):
raise ValueError("The number of bones does not match the number of offsets")
angles = []
for i, bone_name in enumerate(bones):
try:
bone = ob.pose.bones[bone_name]
except KeyError:
print(f"Bone '{bone_name}' not found in armature '{armature_name}'")
continue
angle = math.degrees(get_local_orientation(bone)[2]) + offsets[i]
# Convert angle to steps considering the gear ratio
steps = int(angle * gear_ratio)
angles.append(str(steps))
angle_str = ','.join(angles)
print("Sending angles:", angle_str) # Debug print
with serial_lock:
try:
if ser.is_open:
ser.write(angle_str.encode('UTF-8'))
time.sleep(0.1) # Add delay between writes
else:
print("Serial port is not open")
except serial.SerialException as e:
print(f"Serial write error: {e}")
def frameChange(passedScene):
try:
sendAngles()
except Exception as e:
print(f"Error in frameChange handler: {e}")
bpy.app.handlers.frame_change_pre.append(frameChange)
# Additional setup verification prints
print("Script started.")
print(f"Armature name: {armature_name}")
print(f"Connected to: {ser.portstr}")
print(f"Offsets: {offsets}")
print(f"Gear ratio: {gear_ratio}")
# Print bone names to verify they are correct
for bone_name in ['Dreinen', 'LowerArm', 'UpperArm', 'UpperArm2', 'UpperArm3']:
if bone_name in ob.pose.bones:
print(f"{bone_name} found.")
else:
print(f"Bone '{bone_name}' not found in armature '{armature_name}'.")
# End the serial connection properly when done
import atexit
def close_serial():
if ser.is_open:
ser.close()
print("Closed serial connection.")
atexit.register(close_serial)
Example in the console:
Connected to: COM3
Script started.
Armature name: Armature
Connected to: COM3
Offsets: [0, 0, 0, 0, 0]
Gear ratio: 166.375
Dreinen found.
LowerArm found.
UpperArm found.
UpperArm2 found.
UpperArm3 found.
Sending angles: 0,0,0,29947,-29947
Sending angles: 0,0,0,29947,-29947
Sending angles: 255,0,0,-29947,29913
Sending angles: 1114,0,0,-29947,29806
Sending angles: 7286,0,0,-29947,29418
Sending angles: 13887,0,0,-29947,29346
Sending angles: 18548,0,0,-29947,-527
Sending angles: 20776,0,0,-29947,-463
Sending angles: 18548,0,0,-29947,-527
Sending angles: 20776,0,0,-29947,-463
Sending angles: 20776,0,0,-29947,-463
Sending angles: 21885,0,0,-29947,-468
Sending angles: 22778,0,-29947,0,-599
Sending angles: 22874,0,-29947,0,-632
Sending angles: 22874,0,-29947,0,-632
I tried giving the ESP32 the Coordinates manually through the serialmonitor in arduinoIDE. That worked perfectly.
I also tried giving the code to chatgpt but this didn’t really help…
Mr. Sunny is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.