天天看点

串口总线舵机之舵机运行前提:一、舵机运行代码二、测试

我们总是需要让舵机去转动一定的角度,执行对应的动作。

文章目录

  • 前提:
    • 1.动作文件
    • 2.支持文件
  • 一、舵机运行代码
  • 二、测试

这一部分在Serial_Servo_Running文件里

前提:

因为这一部分需要运行动作组,所以需要动作文件和支持文件

1.动作文件

串口总线舵机之舵机运行前提:一、舵机运行代码二、测试

2.支持文件

需要将下面的文件拷贝到当前目录

串口总线舵机之舵机运行前提:一、舵机运行代码二、测试

一、舵机运行代码

# 串口舵机运行 动作组调用

#!/usr/bin/env python3
# encoding: utf-8
import time # 时间模块
import os  # 系统OS
import sqlite3 as sql  # 数据库
import SerialServoCmd as ssc # 串口舵机命令
import config_serial_servo # 配置串口舵机
import threading  # 线程
from hwax import HWAX # 未知 驱动动作组的 不可缺少,文件夹有一个HWAX.so文件

runningAction = False   # 运行动作组不成立
stopRunning = False  # 停止运行不成立
online_action_num = None   # 动作组编号为空
online_action_times = -1 # 执行时间为空载
update_ok = False # 更新动作组不成立
action_group_finish = True # 动作组完成成立


# 设置串口舵机的位置和时间  
# 时间参数意义:舵机在参数时间内从当前角度匀速转动到参数角度
# s_id:要设置的舵机  pos:0-1000 对应角度 0-240度 s_time:时间0-30000ms  0-30s
def serial_setServo(s_id, pos, s_time):
    if pos > 1000:  # 最大位置是1000 对应角度0-240
        pos = 1000
    elif pos < 0:
        pos = 0
    else:
        pass
    if s_time > 30000:  # 最大时间是30000ms = 30s
        s_time = 30000
    elif s_time < 10:  # 最小时间是10ms
        s_time = 10
    ssc.serial_serro_wirte_cmd(s_id, ssc.LOBOT_SERVO_MOVE_TIME_WRITE, pos, s_time)
    
# 设置舵机偏差值
# servoId:要设置的舵机  d:偏差值
def setDeviation(servoId, d):
    global runningAction  # 全局变量
    if servoId < 1 or servoId > 16:  # 舵机号的范围 1-16个舵机
        return
    if d < -200 or d > 200: # 偏差值的范围
        return
    if runningAction is False: # 如果当前不在运行状态就设置偏差值
        config_serial_servo.serial_servo_set_deviation(servoId, d)

# 停止全部舵机
def stop_servo():
    for i in range(16): 
        config_serial_servo.serial_servo_stop(i+1)  # 依次让每一个舵机都停止
        
# 停止动作组
def stop_action_group():
    global stopRunning, online_action_num, online_action_times, update_ok
    update_ok = False  # 更新ok不成立
    stopRunning = True  # 停止运行成立
    online_action_num = None # 动作组的编号为空
    online_action_times = -1 # 动作组的次数为空载状态
    time.sleep(0.1) # 延时100ms
    
# 获取动作完成标志
def action_finish():
    global action_group_finish 
    return action_group_finish #获取动作组完成标志

# 运行动作组,无法发送停止信号
# actNum:动作组的名字,字符串类型
def runAction(actNum):
    global runningAction  # 运行动作组
    global stopRunning  # 停止运行
    global online_action_times # 运行动作组次数
    if actNum is None: # 动作名字为空
        return
    # 判断动作组的类型
    hwaxNum = "/home/pi/Desktop/Serial_SteerEngine/ActionGroups/" + actNum + ".hwax" # 获取动作组的路径
    actNum = "/home/pi/Desktop/Serial_SteerEngine/ActionGroups/" + actNum + ".d6a"

    if os.path.exists(hwaxNum) is True:  # hwax路径存在
        if runningAction is False: # 如果当前舵机不在运行状态 
            runningAction = True  # 设置舵机正在运行
            ssc.portWrite()  # 端口复位
            hwax = HWAX(hwaxNum, ssc.serialHandle)
            hwax.reset()
            while True:
                if stopRunning is True: # 如果是停止运行
                    stopRunning = False
                    print('stop')    # 输入提示信息               
                    break
                ret = hwax.next()
                if ret is None:
                    hwax.reset()
                    break
            hwax.close() # 关闭这个文件
            runningAction = False

    elif os.path.exists(actNum) is True: # d6a路径存在
        if runningAction is False:
            runningAction = True
            ag = sql.connect(actNum) # 连接数据库
            # 游标就像您打开文件所得到的文件句柄一样,只要文件打开成功, 
            #该文件句柄就可代表该文件
            cu = ag.cursor() # 获取数据库可操作对象
            '''
            使用Cursor对象执行insert,update,delete语句时,执行结果由rowcount返回影响的行数,就可以拿到执行结果
            使用Cursor对象执行select语句时,通过featchall()返回select的全部数据结果集。结果集是一个list,
            每个元素都是一个tuple,对应一行记录,按建表的字段顺序排列。
            fetchone()返回一条结果,是一个tuple,每个元素是一个字段值。
            '''
            cu.execute("select * from ActionGroup") # 从ActionGroup查找全部数据
            while True:
                act = cu.fetchone() # 获取一条查询的结果
                if stopRunning is True: # 如果是停止运行
                    stopRunning = False 
                    print('stop')      # 输入提示信息               
                    break
                if act is not None: # 查询到数据
                    # 设置每一个舵机的act[2 + i]位置act[1]运行时间
                    for i in range(0, len(act)-2, 1): # len(act)-2 : 第一个是 第二个是运行时间
                        serial_setServo(i+1, act[2 + i], act[1]) # ID 位置 时间
                    time.sleep(float(act[1])/1000.0) # 转换为秒
                else:   #  没有查找到数据
                    break
            runningAction = False  # 运行状态停止
            
            cu.close() # 关闭游标
            ag.close() # 关闭数据库连接
    else: # 路径不存在
        runningAction = False
        print("未能找到动作组文件")
        
# 线程运行动作
def online_thread_run_acting():
    global online_action_times, online_action_num, update_ok, action_group_finish
    while True:  # 在线程里  死循环
        if update_ok: # 更新ok 就是说动作组有变化
            if online_action_times == 0: # 如果在线动作次数等于0,执行无限次
                # 无限次运行
                if action_group_finish: # 动作还在执行中,不允许动作发生改变
                    action_group_finish = False
                runAction(online_action_num)   # 运行  online_action_num 动作            
            elif online_action_times > 0: # 如果在线动作次数大于0,执行online_action_times次
                # 有次数运行
                if action_group_finish: # 动作还在执行中,不允许动作发生改变
                    action_group_finish = False
                runAction(online_action_num) # 运行  online_action_num 动作  
                online_action_times -= 1     # 运行次数减一次             
                if online_action_times == 0:
                    online_action_times = -1  # 运行完成后,进入空载 
            else:
                # 空载
                if not action_group_finish: # 如果动作组没有完成
                    action_group_finish = True # 动作组完成
                time.sleep(0.001) # 延时1ms
        else: # 更新不ok 没有动作发生变化
        # 查看上一次动作是否完成
            if not action_group_finish:  # 如果动作组没有完成
                action_group_finish = True # 动作组完成
            time.sleep(0.001) # 延时1ms

# 开始动作线程            
def start_action_thread():
    th1 = threading.Thread(target=online_thread_run_acting) # 运行动作组
    th1.setDaemon(True)  # 设置为后台线程,这里默认是True
    th1.start()
    
# 改变动作组的值
# actNum:动作名 actTimes:运行次数
def change_action_value(actNum, actTimes):
    global online_action_times, online_action_num, update_ok, stopRunning, action_group_finish
    # 动作组都完成了之后才能允许动作发生改变
    if action_group_finish: # 如果动作组完成了
        online_action_times = actTimes # 动作执行的次数 
        online_action_num = actNum # 执行动作组的编号
        stopRunning = False  # 停止运行不成立
        update_ok = True # 更新ok成立

# 单独执行的时候运行
if __name__ == '__main__':
    # 开启动作组线程,update_ok =True 就运行动作
    start_action_thread() # 开启一个动作组的线程
    # 动作一改变 update_ok =True 就会运行动作
    change_action_value('1', 0) # 改变动作   运行动作1,执行无限次
    time.sleep(2) # 延时2s
    stop_action_group() # 停止动作组
           

二、测试

串口总线舵机之舵机运行前提:一、舵机运行代码二、测试

舵机会执行动作,2s后停止。