幻尔串口总线舵机控制Python SDK

一、材料准备

幻尔总线舵机(我用的是xArm机械臂)

幻尔TTL/USB调试板(一定要是幻尔的,其他牌子的调试板驱动不了舵机)

二、Python SDK

"""
串口舵机Python SDK
----------------------------------------------
"""
import serial
import time
import ctypes

###################################################################################################
# 幻尔科技总线舵机通信协议
###################################################################################################
ROBOT_SERVO_FRAME_HEADER = 0x55
ROBOT_SERVO_MOVE_TIME_WRITE = 1  # 该命令发送给舵机,舵机将在参数时间内从当前角度匀速转动到参数角度
ROBOT_SERVO_MOVE_TIME_READ = 2  # 读取发送给舵机的角度运动指令
ROBOT_SERVO_MOVE_TIME_WAIT_WRITE = 7  # 舵机转动指令,等待一段时间后转动
ROBOT_SERVO_MOVE_TIME_WAIT_READ = 8  # 读取上面的指令
ROBOT_SERVO_MOVE_START = 11  # 舵机转动指令,舵机立即开始转动
ROBOT_SERVO_MOVE_STOP = 12  # 舵机停止指令
ROBOT_SERVO_ID_WRITE = 13  # 重新写入舵机ID
ROBOT_SERVO_ID_READ = 14  # 读取舵机的ID值
ROBOT_SERVO_ANGLE_OFFSET_ADJUST = 17  # 舵机转动角度偏差调整
ROBOT_SERVO_ANGLE_OFFSET_WRITE = 18  # 保存偏差值
ROBOT_SERVO_ANGLE_OFFSET_READ = 19  # 读取偏差值
ROBOT_SERVO_ANGLE_LIMIT_WRITE = 20  # 设置舵机转动的范围
ROBOT_SERVO_ANGLE_LIMIT_READ = 21  # 读取舵机转动的范围
ROBOT_SERVO_VIN_LIMIT_WRITE = 22  # 设置舵机的电压范围
ROBOT_SERVO_VIN_LIMIT_READ = 23  # 读取舵机的电压范围
ROBOT_SERVO_TEMP_MAX_LIMIT_WRITE = 24  # 设置舵机内部最高温度
ROBOT_SERVO_TEMP_MAX_LIMIT_READ = 25  # 读取舵机允许最高温度
ROBOT_SERVO_TEMP_READ = 26  # 读取舵机实时温度
ROBOT_SERVO_VIN_READ = 27  # 读取舵机实时电压
ROBOT_SERVO_POS_READ = 28  # 读取舵机当前实际角度位置值
ROBOT_SERVO_OR_MOTOR_MODE_WRITE = 29  # 控制舵机的转速
ROBOT_SERVO_OR_MOTOR_MODE_READ = 30  # 读取舵机控制模式的相关参数
ROBOT_SERVO_LOAD_OR_UNLOAD_WRITE = 31  # 设置舵机内部电机是否掉电
ROBOT_SERVO_LOAD_OR_UNLOAD_READ = 32  # 读取舵机内部电机状态
ROBOT_SERVO_LED_CTRL_WRITE = 33  # 设置LED灯状态
ROBOT_SERVO_LED_CTRL_READ = 34  # 读取LED灯状态
ROBOT_SERVO_LED_ERROR_WRITE = 35  # 设置导致LED灯闪烁报警的值
ROBOT_SERVO_LED_ERROR_READ = 36  # 读取舵机故障报警值

serialHandle = serial.Serial("COM5", 115200)  # 初始化串口, 波特率为115200
time_out = 50


###################################################################################################
# 舵机与PC通信
###################################################################################################
def checksum(buf):
    """计算校验和"""
    check_sum = 0x00
    for b in buf:
        check_sum += b
    check_sum = check_sum - 0x55 - 0x55
    check_sum = ~check_sum  # 取反
    return check_sum & 0xff


def serial_servo_write(ID=None, w_cmd=None, dat1=None, dat2=None):
    """写指令"""
    buf = bytearray(b'\x55\x55')  # 帧头
    buf.append(ID)
    # 指令长度
    if dat1 is None and dat2 is None:
        buf.append(3)
    elif dat1 is not None and dat2 is None:
        buf.append(4)
    elif dat1 is not None and dat2 is not None:
        buf.append(7)

    buf.append(w_cmd)  # 指令
    # 写数据
    if dat1 is None and dat2 is None:
        pass
    elif dat1 is not None and dat2 is None:
        buf.append(dat1 & 0xff)
    elif dat1 is not None and dat2 is not None:
        buf.extend([(0xff & dat1), (0xff & (dat1 >> 8))])  # 分低8位 高8位 放入缓存
        buf.extend([(0xff & dat2), (0xff & (dat2 >> 8))])  # 分低8位 高8位 放入缓存
    # 校验和
    buf.append(checksum(buf))

    serialHandle.write(buf)  # 发送


def serial_servo_read(ID=None, r_cmd=None):
    """发送读取命令"""
    buf = bytearray(b'\x55\x55')  # 帧头
    buf.append(ID)
    buf.append(3)  # 指令长度
    buf.append(r_cmd)  # 指令
    buf.append(checksum(buf))  # 校验和
    serialHandle.write(buf)  # 发送
    time.sleep(0.00034)


def serial_servo_get_r_msg(cmd):
    """获取指定读取数据命令的数据"""
    serialHandle.flushInput()  # 清空接收缓存
    time.sleep(0.005)  # 稍作延迟,等待接收完毕
    count = serialHandle.inWaiting()  # 获取接收缓存中的字节数
    if count != 0:
        recv_data = serialHandle.read(count)  # 读取接收到的数据
        try:
            if recv_data[0] == 0x55 and recv_data[1] == 0x55 and recv_data[4] == cmd:
                dat_len = recv_data[3]
                serialHandle.flushInput()  # 清空接收缓存
                if dat_len == 4:
                    return recv_data[5]
                elif dat_len == 5:
                    pos = 0xffff & (recv_data[5] | (0xff00 & (recv_data[6] << 8)))
                    return ctypes.c_int16(pos).value
                elif dat_len == 7:
                    pos1 = 0xffff & (recv_data[5] | (0xff00 & (recv_data[6] << 8)))
                    pos2 = 0xffff & (recv_data[7] | (0xff00 & (recv_data[8] << 8)))
                    return ctypes.c_int16(pos1).value, ctypes.c_int16(pos2).value
            else:
                return None
        except BaseException as e:
            print(e)
    else:
        serialHandle.flushInput()  # 清空接收缓存
        return None


###################################################################################################
# 舵机使用API
###################################################################################################
def setBusServoID(old_id, new_id):
    """配置舵机ID号,出厂默认为1"""
    serial_servo_write(old_id, ROBOT_SERVO_ID_WRITE, new_id)


def getBusServoID(ID=None):
    """读取串口舵机ID"""
    while True:
        if ID is None:  # 总线上只能有一个舵机
            serial_servo_read(0xfe, ROBOT_SERVO_ID_READ)
        else:
            serial_servo_read(ID, ROBOT_SERVO_ID_READ)
        # 获取内容
        msg = serial_servo_get_r_msg(ROBOT_SERVO_ID_READ)
        if msg is not None:
            return msg


def setBusServoPulse(ID, pulse, use_time):
    """驱动串口舵机运动到指定位置"""
    pulse = 0 if pulse < 0 else pulse
    pulse = 1000 if pulse > 1000 else pulse
    use_time = 0 if use_time < 0 else use_time
    use_time = 30000 if use_time > 30000 else use_time
    serial_servo_write(ID, ROBOT_SERVO_MOVE_TIME_WRITE, pulse, use_time)


def getBusServoPulse(ID):
    """
    读取舵机当前位置
    """
    while True:
        serial_servo_read(ID, ROBOT_SERVO_POS_READ)
        msg = serial_servo_get_r_msg(ROBOT_SERVO_POS_READ)
        if msg is not None:
            return msg


def stopBusServo(ID=None):
    """停止舵机运行"""
    serial_servo_write(ID, ROBOT_SERVO_MOVE_STOP)


def setBusServoDeviation(ID, d=0):
    """调整偏差"""
    serial_servo_write(ID, ROBOT_SERVO_ANGLE_OFFSET_ADJUST, d)


def saveBusServoDeviation(ID):
    """配置偏差,掉电保护"""
    serial_servo_write(ID, ROBOT_SERVO_ANGLE_OFFSET_WRITE)


def getBusServoDeviation(ID):
    """读取偏差值"""
    # 发送读取偏差指令
    count = 0
    while True:
        serial_servo_read(ID, ROBOT_SERVO_ANGLE_OFFSET_READ)
        # 获取
        msg = serial_servo_get_r_msg(ROBOT_SERVO_ANGLE_OFFSET_READ)
        count += 1
        if msg is not None:
            return msg
        if count > time_out:
            return None


def setBusServoAngleLimit(ID, low, high):
    """设置舵机转动范围"""
    serial_servo_write(ID, ROBOT_SERVO_ANGLE_LIMIT_WRITE, low, high)


def getBusServoAngleLimit(ID):
    """读取舵机转动范围"""
    while True:
        serial_servo_read(ID, ROBOT_SERVO_ANGLE_LIMIT_READ)
        msg = serial_servo_get_r_msg(ROBOT_SERVO_ANGLE_LIMIT_READ)
        if msg is not None:
            return msg


def setBusServoVinLimit(ID, low, high):
    """设置舵机电压范围"""
    serial_servo_write(ID, ROBOT_SERVO_VIN_LIMIT_WRITE, low, high)


def getBusServoVinLimit(ID):
    """读取舵机转动范围"""
    while True:
        serial_servo_read(ID, ROBOT_SERVO_VIN_LIMIT_READ)
        msg = serial_servo_get_r_msg(ROBOT_SERVO_VIN_LIMIT_READ)
        if msg is not None:
            return msg


def setBusServoMaxTemp(ID, m_temp):
    """设置舵机最高温度报警"""
    serial_servo_write(ID, ROBOT_SERVO_TEMP_MAX_LIMIT_WRITE, m_temp)


def getBusServoTempLimit(ID):
    """读取舵机温度报警范围"""
    while True:
        serial_servo_read(ID, ROBOT_SERVO_TEMP_MAX_LIMIT_READ)
        msg = serial_servo_get_r_msg(ROBOT_SERVO_TEMP_MAX_LIMIT_READ)
        if msg is not None:
            return msg


def getBusServoTemp(ID):
    """读取舵机温度"""
    while True:
        serial_servo_read(ID, ROBOT_SERVO_TEMP_READ)
        msg = serial_servo_get_r_msg(ROBOT_SERVO_TEMP_READ)
        if msg is not None:
            return msg


def getBusServoVin(ID):
    """读取舵机电压"""
    while True:
        serial_servo_read(ID, ROBOT_SERVO_VIN_READ)
        msg = serial_servo_get_r_msg(ROBOT_SERVO_VIN_READ)
        if msg is not None:
            return msg


def restBusServoPulse(old_id):
    # 舵机清零偏差和P值中位(500)
    setBusServoDeviation(old_id, 0)    # 清零偏差
    time.sleep(0.1)
    serial_servo_write(old_id, ROBOT_SERVO_MOVE_TIME_WRITE, 500, 100)    # 中位


def unloadBusServo(ID):
    serial_servo_write(ID, ROBOT_SERVO_LOAD_OR_UNLOAD_WRITE, 0)


def getBusServoLoadStatus(ID):
    """读取是否掉电"""
    while True:
        serial_servo_read(ID, ROBOT_SERVO_LOAD_OR_UNLOAD_READ)
        msg = serial_servo_get_r_msg(ROBOT_SERVO_LOAD_OR_UNLOAD_READ)
        if msg is not None:
            return msg

 三、调用说明

# 导入API
from servo import *



# 驱动舵机运动
setBusServoPulse(1, 500, 500)

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
### 回答1: 首先,需要安装幻尔总线舵机控制器的驱动程序。可以在幻尔官网下载对应的驱动程序,并根据其安装说明进行安装。 接着,在Linex系统下打开命令行终端,输入指令“sudo apt-get install ros-kinetic-dynamixel-sdk”安装dynamixel SDK库。 然后,在终端中输入指令“cd ~/catkin_ws/src”,创建ROS工作空间并进入src目录下。 在src目录下创建一个新的ROS功能包,例如“my_controller”,并进入该功能包目录,命令为“catkin_create_pkg my_controller roscpp dynamixel_sdk”。 在my_controller的src目录中新建一个名为“my_controller.cpp”的文件,并在其中编写控制器代码。控制器代码应包括幻尔总线舵机控制器的初始化、调用dynamixel SDK库函数进行舵机控制,以及与ROS节点交互的代码。 最后,在终端中编译my_controller功能包,指令为“cd ~/catkin_ws && catkin_make”即可完成。 在ROS节点中启动my_controller节点,并订阅控制舵机的话题,即可通过Linex系统控制幻尔总线舵机控制器。 ### 回答2: 幻尔总线舵机控制器在linex中的使用需要以下步骤: 1. 安装幻尔总线舵机控制器的驱动程序:首先,需要下载新版本的驱动程序,然后在linex系统上安装。此外,也可以通过安装ROS的方式来安装幻尔总线舵机控制器的驱动程序。 2. 连接幻尔总线舵机控制器:通过使用USB连接线将幻尔总线舵机控制器与linex电脑连接起来,使电脑能够识别控制器。 3. 运行幻尔总线舵机控制器:通过在linex终端窗口输入指定的控制命令,开启幻尔总线舵机控制器,就可以开始对舵机进行控制。 4. 控制幻尔总线舵机:通过输入相应的指令,可以实现对幻尔总线舵机的控制。例如,可以通过指定舵机的ID号和目标角度,来让舵机运动到指定的位置。 需要注意的是,在使用幻尔总线舵机控制器的过程中,需要对控制器和舵机的电源进行合理的使用和配置,以保证系统的稳定运行。此外,需要注意指令的正确性和顺序,避免控制器和舵机出现不必要的故障。 ### 回答3: 首先,我们需要在Linux系统上安装幻尔总线舵机控制器的驱动程序。幻尔总线舵机控制驱动程序提供了与硬件交互的接口,可以让我们在Linux系统上控制舵机。 接下来,我们需要编写控制程序,通过驱动程序向幻尔总线舵机控制器发送命令,控制舵机的旋转角度和速度。在编写程序时,我们需要了解幻尔总线舵机控制器的通信协议和命令格式,以确保程序能够正确与控制器进行通信。 一般来说,通过编写C语言Python等高级语言的程序来实现舵机控制。我们可以使用GPIO库来实现GPIO口的控制,使用串口通信库实现与幻尔总线舵机控制器的通信。 在实际使用中,我们需要根据舵机的型号和接口规格选择合适的幻尔总线舵机控制器,以及编写控制程序。在程序调试阶段,可以通过调试工具来监测和调试通信过程,确保程序能够正确地控制舵机。 总的来说,使用幻尔总线舵机控制器在Linux系统上控制舵机需要对硬件、通信协议和编程技术都具备一定的了解和掌握。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值