You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Webots中KUKA机器人多轴同步运动问题求助(4ms时间步长)

问题:Webots中KUKA机器人多轴同步运动异常

我用Webots模拟6轴KUKA机器人,当前仅启用3轴,控制器每4ms接收一次位置指令。调用axis.setPosition()时,仅第1轴运动,其余轴无响应且仿真画面无变化。尝试用多线程实现同步运动,问题仍未解决。求问如何在4ms时间步长下实现所有轴的同步运动?


初始代码

from bs4 import BeautifulSoup
import socket
import math
import time
from controller import Robot


robot = Robot()
timestep = int(robot.getBasicTimeStep())

serverIP = "127.0.0.1"
serverPort = 59152
bufferSize = 1024

# Create a datagram socket
print("DataParser started")

UDPServerSocket = socket.socket(
    family=socket.AF_INET, type=socket.SOCK_DGRAM)
print("Datagram socket created")

UDPServerSocket.bind((serverIP, serverPort))
print("Address and IP binded")

# Listen for incoming datagrams
port_input = "2345"
robotName = "kr10r1420"
shadowName = "kr10r1420_shadow"

print("Connected to dataParser")
axe1 = robot.getDevice("1_axis_motor_rot")
axe2 = robot.getDevice("2_axis_motor_rot")
axe3 = robot.getDevice("3_axis_motor_rot")
axe4 = robot.getDevice("4_axis_motor_rot")
axe5 = robot.getDevice("5_axis_motor_rot")
axe6 = robot.getDevice("6_axis_motor_rot")

UDPServerSocket.settimeout(600.0)

try:
    while robot.step(4) != -1:
        
        # print("Waiting for message")
        bytesAddressPair = UDPServerSocket.recvfrom(bufferSize)
        # f.write(str(time.time()) + '\n')
        print(str(time.time()) + " Timestep: " + str(timestep) + " " + str(axe1.getAcceleration()))
        message = bytesAddressPair[0]
        address = bytesAddressPair[1]
        # print(message.decode())
        # motor.setPosition(position)
        # motor.setPosition(1)
        
        tag = BeautifulSoup(message.decode(), 'html.parser')
        # ------------------ Robot ---------------------
        aipos = tag.find_all('aipos')[0]
        a1 = math.radians(float(aipos['a1']) + 90) # axis z -> axis x
        axe1.setPosition(a1)
        # robot.step(4)   
        # a2 = math.radians(float(aipos['a2']) + 90) # axis z -> axis x
        # axe2.setPosition(a2) 
        a3 = math.radians(float(aipos['a3']) - 90) # axis x -> axis z
        axe3.setPosition(a3) 
        # robot.step(4) 
        # a4 = math.radians(float(aipos['a4'])) # It's not really defined, how it should be
        # axe4.setPosition(a4) 
        # a5 = math.radians(float(aipos['a5'])) # It's not really defined, how it should be
        # axe5.setPosition(a5) 
        a6 = math.radians(float(aipos['a6'])) # It's not really defined, how it should be
        axe6.setPosition(4)        
        
        # print("axe1 " + str(a1) + " axe2 " + str(a2) + " axe3 " + str(a3) + " axe4 " + str(a4) + " axe5 " + str(a5) + " axe6 " + str(a6))
finally:
    print("File closed")
    # f.close()

多线程代码

from bs4 import BeautifulSoup
import socket
import math
import time
from controller import Robot
import threading


robot = Robot()
timestep = int(robot.getBasicTimeStep())

serverIP = "127.0.0.1"
serverPort = 59152
bufferSize = 1024

# Create a datagram socket
print("DataParser started")

UDPServerSocket = socket.socket(
    family=socket.AF_INET, type=socket.SOCK_DGRAM)
print("Datagram socket created")

UDPServerSocket.bind((serverIP, serverPort))
print("Address and IP binded")

# Listen for incoming datagrams
port_input = "2345"
robotName = "kr10r1420"
shadowName = "kr10r1420_shadow"

print("Connected to dataParser")
axe1 = robot.getDevice("1_axis_motor_rot")
axe2 = robot.getDevice("2_axis_motor_rot")
axe3 = robot.getDevice("3_axis_motor_rot")
axe4 = robot.getDevice("4_axis_motor_rot")
axe5 = robot.getDevice("5_axis_motor_rot")
axe6 = robot.getDevice("6_axis_motor_rot")

UDPServerSocket.settimeout(600.0)

a1 = 0
a3 = 0
a6 = 0

def update_motor1():
    while robot.step(timestep) != -1:
        axe1.setPosition(a1)

def update_motor3():
    while robot.step(timestep) != -1:
        axe3.setPosition(a3)

def update_motor6():
    while robot.step(timestep) != -1:
        axe6.setPosition(a6)

thread1 = threading.Thread(target=update_motor1)
thread3 = threading.Thread(target=update_motor3)
thread6 = threading.Thread(target=update_motor6)

thread1.start()
thread3.start()
thread6.start()


try:
    while robot.step(timestep) != -1:
        
        # print("Waiting for message")
        bytesAddressPair = UDPServerSocket.recvfrom(bufferSize)
        # f.write(str(time.time()) + '\n')
        # print(str(time.time()) + " Timestep: " + str(timestep) + " " + str(axe1.getAcceleration()))
        message = bytesAddressPair[0]
        address = bytesAddressPair[1]
        # print(message.decode())
        # motor.setPosition(position)
        # motor.setPosition(1)
        
        tag = BeautifulSoup(message.decode(), 'html.parser')
        # ------------------ Robot ---------------------
        aipos = tag.find_all('aipos')[0]
        a1 = math.radians(float(aipos['a1']) + 90) # axis z -> axis x
        # axe1.setPosition(a1)
        # robot.step(4)   
        # a2 = math.radians(float(aipos['a2']) + 90) # axis z -> axis x
        # axe2.setPosition(a2) 
        a3 = math.radians(float(aipos['a3']) - 90) # axis x -> axis z
        # axe3.setPosition(a3) 
        # robot.step(4) 
        # a4 = math.radians(float(aipos['a4'])) # It's not really defined, how it should be
        # axe4.setPosition(a4) 
        # a5 = math.radians(float(aipos['a5'])) # It's not really defined, how it should be
        # axe5.setPosition(a5) 
        a6 = math.radians(float(aipos['a6'])) # It's not really defined, how it should be
        # axe6.setPosition(4)        
        
        # print("axe1 " + str(a1) + " axe2 " + str(a2) + " axe3 " + str(a3) + " axe4 " + str(a4) + " axe5 " + str(a5) + " axe6 " + str(a6))
finally:
    print("File closed")
    thread1.join()
    thread2.join()
    thread3.join()

解决方案

Webots的仿真依赖单线程核心循环驱动,多线程会破坏其同步机制(robot.step()不能在多个线程中调用),这是问题的核心原因。以下是正确实现方式:

1. 核心原则

所有控制逻辑必须放在同一个robot.step()循环内,每个时间步内完成所有轴的位置更新,Webots会在该步结束后统一刷新所有关节状态,实现同步运动。

2. 修复步骤

  • 移除多线程:放弃多线程方案,回归单循环模式
  • 初始化电机参数:确保每个电机设置了合理的速度、加速度(默认值为0时电机无法运动)
  • 统一更新位置:在同一个时间步内完成所有轴的setPosition()调用,不要插入额外的robot.step()
  • 修正代码错误:比如多线程代码中thread2.join()的无效调用、初始代码中axe6.setPosition(4)的硬编码值

3. 修正后的完整代码

from bs4 import BeautifulSoup
import socket
import math
from controller import Robot


robot = Robot()
timestep = 4  # 直接指定4ms时间步,匹配需求

serverIP = "127.0.0.1"
serverPort = 59152
bufferSize = 1024

# 初始化UDP套接字
print("DataParser started")
UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
UDPServerSocket.bind((serverIP, serverPort))
print("Address and IP binded")

# 获取目标电机设备
axe1 = robot.getDevice("1_axis_motor_rot")
axe3 = robot.getDevice("3_axis_motor_rot")
axe6 = robot.getDevice("6_axis_motor_rot")

# 初始化电机运动参数
for motor in [axe1, axe3, axe6]:
    motor.setVelocity(motor.getMaxVelocity())  # 使用最大速度,可按需调整
    motor.setAcceleration(10)  # 设置加速度,避免卡顿

UDPServerSocket.settimeout(600.0)

try:
    while robot.step(timestep) != -1:
        # 接收UDP位置指令
        bytesAddressPair = UDPServerSocket.recvfrom(bufferSize)
        message = bytesAddressPair[0]
        
        # 解析指令
        tag = BeautifulSoup(message.decode(), 'html.parser')
        aipos = tag.find_all('aipos')[0]
        
        # 计算各轴目标位置(坐标系转换)
        a1 = math.radians(float(aipos['a1']) + 90)
        a3 = math.radians(float(aipos['a3']) - 90)
        a6 = math.radians(float(aipos['a6']))
        
        # 统一设置所有轴位置,Webots自动同步执行
        axe1.setPosition(a1)
        axe3.setPosition(a3)
        axe6.setPosition(a6)
        
finally:
    print("File closed")
    UDPServerSocket.close()

关键注意事项

  • robot.step()是仿真的核心心跳,所有控制逻辑必须在两次step之间完成
  • 若电机速度/加速度设为0,即使调用setPosition()也不会运动,必须初始化合理参数
  • recvfrom()是阻塞调用,若UDP指令发送间隔超时会导致控制器停止,可调整timeout或改用非阻塞模式

内容的提问来源于stack exchange,提问作者cedrik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 15:20:56