舵机之控制命令封装

在这一步又对舵机的命令做了一层封装,每一个指令对应的就是一种功能,方便后续进行处理。
这一部分在LeCmd里

前提:获取全部动作组文件

1.动作组文件夹

这个文件夹中存放的是所有的动作组文件
在这里插入图片描述

2.获取所有动作组文件

获取所有的动作组文件,并且文件是以.d6a结尾的,全部存放一个列表返回。
代码

#获取全部.d6a文件
#!/usr/bin/python3
# encoding: utf-8
import os
# 获取全部.d6a文件
def listActions(path):
    if not os.path.exists(path): # 如果path文件不存在  path可以为文件路径
        os.mkdir(path) # 创建这个目录  path 为文件路径
    pathlist = os.listdir(path)  # 返回指定文件夹包含的文件或文件夹
    actList = [] # 创建一个列表
    for f in pathlist:
        #print(f) # 输出这个路径下的所有文件
        if f[0] == '.':  # 以.开头的文件
            pass # 不需要
        else:
            if f[-4:] == '.d6a': # 后缀是.d6a的文件
                #print(f) # 输出所有.d6a的文件
                f.replace('-', '') # 把-替换为空格
                if f:
                    actList.append(f) # 添加到actList列表中
            else:
                pass
    return actList

if __name__ == '__main__':
    path = '/home/pi/Desktop/Serial_SteerEngine/ActionGroups'
    listActions(path)

一、各个指令的作用

1.cmd_i000 空指令

这部分啥也不干,一点用也没有

2.cmd_i001 设置16个舵机的位置

通过这个函数可以设置16个串口舵机的转动位置,必须是16个舵机一起,也就是相当于一个动作组

参数 par:
par[0]:串口舵机运行时间
par[1]:运行指令的长度
par[2]:id1 舵机的ID
par[3]:pos1 舵机的运行位置
par[4]:id2
par[5]:pos2
。。。

3.cmd_i002 停止动作组

通过这个命令可以停止全部舵机的运动。

参数 par:为空

4.cmd_i003 运行动作组

参数 sock:网络对象,此处没有使用。
data=["",""]:存放字符串的列表
data[0]:动作组的命令
data[1]:动作组运行的次数
调用的是runAction方法,此动作只执行一次,也就是说次数被屏蔽了。

5.cmd_i004 查询动作组

通过这个指令,查找所有的动作文件夹里的动作组,并且通过网络发送给请求者,有固定的帧格式

参数 sock:网络对象,需要给出一个要接收数据的对象
data=[]:这个没有用到

注释1
列出所有动作组的名称
在这里插入图片描述
注释2
列出每个动作组的开头
在这里插入图片描述

注释3
列出所有动作组
在这里插入图片描述

注释4
每10个动作组连成一个字符串
在这里插入图片描述
注释5
在这里插入图片描述
可以看出,这些数据格式是

数据头:I004
数据长度:44
这一帧的数据范围 是1-10 11-20.。。。40-44

6.cmd_i005 删除动作组

通过这个命令可以删除动作组,这个列表中有几个动作组的名字,就删除几个动作组

参数 sock:数据没有使用
data =[]:这个是动作组的名字的列表,有几个删几个

7.cmd_i006 删除所有动作组

参数 sock:数据没有使用
data =[]:数据没有使用

8.cmd_i007 设置任意舵机位置

通过这个命令可以设置任意舵机的位置,可以设置任意个数,可以不按顺序,只要id对应即可。

参数 sock:数据没有使用
data =[]:
data[0]: 舵机运行时间
data[1]:运行舵机的数目
data[2]:id1
data[3]:pos1
data[4]:id2
data[5]:pos2

9.cmd_i008 修改舵机偏差

参数 sock:一个网络请求对象
data =[]:32个数据
data[0]:id1
data[1]:偏差1
data[2]:id2
data[3]:偏差2
。。。
调用setDeviation函数设置偏差值

10.cmd_i009 读取舵机内部偏差

参数 sock:一个网络请求对象
data =[]:没有使用
返回一帧数据给上位机 包括舵机ID和对应的偏差值

二、对应的代码

# 舵机控制命令
#!/usr/bin/env python3
# encoding: utf-8
import os           # 导入标准库OS  os--操作系统接口模块
import LeActList    # 列出目录下的所有.d6a文件,以列表形式返回
import threading    # 导入线程     
import sys          # 导入包含了与Python解释器和它的环境有关的函数
import Serial_Servo_Running # 串口舵机运行
import time          # 导入时间模块
import config_serial_servo # 配置串口舵机


actdir = "/home/pi/Desktop/Serial_SteerEngine/ActionGroups" # 动作组文件目录
# 校准值  16个串口舵机的值
Calibration = (500, 500, 303, 500, 500, 500, 500, 725, 500, 500, 697, 500, 500, 500, 500, 275)

# 错误类 继承  Exception
class LeError(Exception):
    def __init__(self, data=(), msg="LeError"):
        self.data = data
        self.msg = msg


def cmd_i000(par):  # 指令000 空指令
    pass

# 数据格式 时间 舵机数目 id1 pos1 id2 pos2.。。
def cmd_i001(par):  # 指令001 舵机运动
    global Deviation  # 偏移量
    if par[0] > 30000:  # 时间限制
        par[0] = 30000
    if par[0] < 20:
        par[0] = 20
    # len(par) 不等于 par[1]*2+2 或者 len(par)<4
    if not par[1] * 2 + 2 == len(par) or not len(par) >= 4:
        raise LeError(tuple(par), "舵机运动指令长度错误")  # 抛出异常
    
    Servos = par[2:]  #去掉运行时间和数据指令长度
    for i in range(0, len(Servos), 2):  # 遍历16个舵机
        if Servos[i] > 16 or Servos[i] < 1 or Servos[i+1] > 1000 or Servos[i+1] < 0:
            raise LeError((Servos[i], Servos[i+1]), "舵机运动参数错误")
        # 串口舵机
        Serial_Servo_Running.serial_setServo(Servos[i], Servos[i + 1], par[0])


def cmd_i002(par):  # 指令002 停止运动
    Serial_Servo_Running.stop_action_group()  # 停止动作组


def cmd_i003(sock, data=["", ""]):  # 指令003 运行动作组
    # len(data) 不等于2  data有数据   ata[0]不为0  data[1]不为0
    if (not len(data) == 2) or (not data) or (not data[0]) or (not data[1]) :
        raise LeError(tuple(data), "运行动作组指令错误")
    par = None
    try:
        par = int(data[1])  # 转为整形 data[1] 动作组次数
    except:
        raise LeError((data[1],),"动作组运行次数错误")

#    print(data[0])
#    print(par)
    if not par is None:  # 动作组次数有数据 
        try:
            Serial_Servo_Running.runAction(data[0]) # data[0] 动作组名字
        except Exception as e:
            print(e)

def cmd_i004(sock, data=[]):  # 指令 004查询动作组
    actList = LeActList.listActions(actdir) # 列出所有的动作组的动作文件
    actList.sort()  # 排序
    #for i in actList:   # 注释1
       # print(i)
        #print('\n')
    
    if not len(actList) is 0:  # 有数据
        
        for i in range(0, len(actList), 10):  # 步进是10,隔10个执行一个动作
            str_head = "I004-" + str(len(actList))
            str_tial = "-" + str(i+1) + "-"  # -1-   -11-  -21-
            #print(str_tial)  # 注释2
            str_tial1 = ""
            t = 10
            for j in range(0, 10, 1):  # 对前面取10个的再次处理
                if i+j < len(actList):
                    #print(actList[i+j]) # 注释3
                    str_tial1 += "-" + actList[i+j][:-4]  # 去掉后缀 并将所有的后缀
                    #print(str_tial1) # 注释4
                else:
                    if t == 10:
                        t = j
            if str_tial1:
                str_head = str_head + str_tial + str(i+t) + str_tial1 + "\r\n"
                # print(str_head) # 注释5
                sock.sendall(str_head.encode()) # 10个10个的发送动作组
    else:  # 没有数据
        s = "I004-0-0-0\r\n"
        ock.sendall(s.encode())  # 通过网络发送

#    print(len(actList))
#    print(actList)


def cmd_i005(sock, data=[]):  # 指令 005 删除一个动作组
    if data: # 数据不为空
        for d in data: # 遍历这个列表
            if d: # 有数据 
                os.remove(actdir + d + ".d6a") # actdir存放动作组文件目录 d 为动作组的名字
                

def cmd_i006(sock, data=[]):  # 指令 006 删除所有动作组
    actList = LeActList.listActions(actdir)
    for d in actList:  
        os.remove(actdir + d) # d为动作组的名字

# 数据格式  time  servo_num  ID1 pos1  ID2 pos2...
def cmd_i007(sock, data=[]):    # 手柄控制
    try:
        time1 = int(data[0])  # 转为整形  时间
        servo_num = int(data[1]) # 舵机的数目
        # print(time,servo_num)
        servo_data = []
        for i in range(servo_num): # 遍历舵机
            servo_id = int(data[2 + i * 2]) # data[2]  data[4]
            servo_pos = int(data[3 + i * 2])# data[3]  data[5]
            servo_data.append((servo_id, servo_pos-10000))
        # print(servo_data)
    except:
        raise LeError(tuple(data), "参数错误")
    try:
        for d in servo_data:  # 遍历数据列表 
            Serial_Servo_Running.serial_setServo(d[0], d[1], time1) # 设置串口舵机移动的id 位置 时间
            time.sleep(0.5)
    except Exception as e:
        print(e)


def read_deviation():   # 读取舵机内部偏差
    d = []
    for i in range(1, 17, 1): # 16个总线串口舵机
        zf_d = config_serial_servo.serial_servo_read_deviation(i)
        if zf_d > 127:  # 负数
            zf_d = -(0xff - (zf_d - 1))
        d.append(zf_d)
    return d  # 返回一个偏差值列表


def cmd_i008(sock, data=[]):      # 修改偏差
    # 1、读取界面舵机P值
    if not 32 == len(data):
        raise LeError(tuple(data), "1、舵机运动指令长度错误")
    Servos = data[:] # 复制数据
    j = 0
    upper_d = []    # 界面的舵机值
    for i in range(0, len(Servos), 2): # 0-32 每隔一个执行一次
        j += 1                           # 0 2 4 6 ...  30 舵机ID
        upper_d.append(int(Servos[i+1])) # 1 3 5 7 。。。31  舵机的偏差值
    ########################################################
    if not len(Calibration) == 16 and not len(upper_d) == 16:
        print("偏差数量错误")
        s = "I008-dev-no\r\n"
        sock.sendall(s.encode()) # 发送错误信息
        sys.exit()
    else:  # 数据正确
        new_d = [] # 新的偏差值
        for i in range(0, len(upper_d), 1): #  16个ID
            if -125 > (upper_d[i] - Calibration[i]) > 125:
                print("偏差值超出范围-125~125")
                s = "I008-dev-error-range\r\n"
                sock.sendall(s.encode())
                sys.exit()
            else:
                # 界面值 - 校准值
                new_d.append(upper_d[i] - Calibration[i])
    # 配置偏差
    for i in range(0, len(new_d), 1):
        Serial_Servo_Running.setDeviation(i+1, new_d[i]) # 设置新的偏差值
        time.sleep(0.05)
    s = "I008-dev-ok\r\n"
    sock.sendall(s.encode())     # 发送修改偏差成功


def cmd_i009(sock, data=[]):  # 读取舵机内部偏差
    global Deviation
    # 1、读取舵机内部偏差值  所有舵机  返回一个列表
    Deviation = read_deviation()  
    # 2、清零舵机内部偏差
    for i in range(0, 16, 1):
        Serial_Servo_Running.setDeviation(i+1, 0)
        time.sleep(0.05)
    # 3、计算校准值 + 偏差值,生成字符串命令
    str_head = "I009-"
    str_head += str(len(Deviation))
    str_tial = ''
    for i in range(0, len(Deviation), 1):
        str_tial += "-" + str(i+1) + "-" + str(Calibration[i] + Deviation[i]) # 舵机ID和对应的偏差值
    str_head += str_tial
    #print(str_head)
    # 4、发送数据给上位机
    sock.sendall(str_head.encode())


# 命令列表
cmd_list = [cmd_i000, cmd_i001, cmd_i002, cmd_i003, cmd_i004, cmd_i005, cmd_i006,
            cmd_i007, cmd_i008, cmd_i009]

#if __name__ == '__main__':
    #cmd_i009(None)
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值