幻尔串口总线舵机控制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)

React Hooks 是 React 16.8 中新增的特性,它可以让你在函数组件中使用 state、生命周期钩子等 React 特性。使用 Hooks 可以让你写出更简洁、可复用且易于测试的代码。 React Hooks 提供了一系列的 Hook 函数,包括 useState、useEffect、useContext、useReducer、useCallback、useMemo、useRef、useImperativeHandle、useLayoutEffect 和 useDebugValue。每个 Hook 都有特定的用途,可以帮助你处理不同的问题。 下面是 React Hooks 的一些常用 Hook 函数: 1. useState useState 是最常用的 Hook 之一,它可以让你在函数组件中使用 state。useState 接受一个初始状态值,并返回一个数组,数组的第一个值是当前 state 值,第二个值是更新 state 值的函数。 ``` const [count, setCount] = useState(0); ``` 2. useEffect useEffect 可以让你在组件渲染后执行一些副作用操作,比如订阅事件、异步请求数据等。useEffect 接受两个参数,第一个参数是一个回调函数,第二个参数是一个数组,用于控制 useEffect 的执行时机。 ``` useEffect(() => { // 这里可以执行副作用操作 }, [dependencies]); ``` 3. useContext useContext 可以让你在组件树中获取 context 的值。它接受一个 context 对象,并返回该 context 的当前值。 ``` const value = useContext(MyContext); ``` 4. useRef useRef 可以让你在组件之间共享一个可变的引用。它返回一个对象,该对象的 current 属性可以存储任何值,并在组件的生命周期中保持不变。 ``` const ref = useRef(initialValue); ref.current = value; ``` 5. useCallback useCallback 可以让你缓存一个函数,以避免在每次渲染时都创建一个新的函数实例。它接受一个回调函数和一个依赖数组,并返回一个 memoized 的回调函数。 ``` const memoizedCallback = useCallback(() => { // 这里是回调函数的逻辑 }, [dependencies]); ``` 6. useMemo useMemo 可以让你缓存一个计算结果,以避免在每次渲染时都重新计算。它接受一个计算函数和一个依赖数组,并返回一个 memoized 的计算结果。 ``` const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); ``` 以上就是 React Hooks 的一些常用 Hook 函数,它们可以帮助你更好地处理组件状态、副作用、上下文和性能优化等问题。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值