mi-task/single_test/test_custom_gait.py

399 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
自定义步态测试脚本
测试俯身步态、爬坡步态、石板路步态等特殊步态
"""
import time
import sys
import os
import toml
import copy
import math
# 添加父目录到路径以便能够导入utils
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# 添加task_3和task_4目录
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'task_3'))
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'task_4'))
from utils.log_helper import LogHelper, get_logger, section, info, debug, warning, error, success, timing
from base_move.go_straight import go_straight
from file_send_lcmt import file_send_lcmt
# 创建日志记录器
logger = get_logger("自定义步态测试")
# 机器人命令模板
robot_cmd = {
'mode':0, 'gait_id':0, 'contact':0, 'life_count':0,
'vel_des':[0.0, 0.0, 0.0],
'rpy_des':[0.0, 0.0, 0.0],
'pos_des':[0.0, 0.0, 0.0],
'acc_des':[0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
'ctrl_point':[0.0, 0.0, 0.0],
'foot_pose':[0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
'step_height':[0.0, 0.0],
'value':0, 'duration':0
}
def test_stoop_gait(ctrl, msg, observe=True):
"""测试俯身步态"""
section('测试:俯身步态', "步态测试")
info('开始测试俯身步态...', "测试")
try:
# 加载俯身步态配置
gait_config_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
'task_4', 'Gait_Params_stoop.toml')
gait_def_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
'task_4', 'Gait_Def_stoop.toml')
if not os.path.exists(gait_config_path):
error(f"俯身步态配置文件不存在: {gait_config_path}", "错误")
return
steps = toml.load(gait_config_path)
full_steps = {'step':[robot_cmd]}
k = 0
for i in steps['step']:
cmd = copy.deepcopy(robot_cmd)
cmd['duration'] = i['duration']
if i['type'] == 'usergait':
cmd['mode'] = 11 # LOCOMOTION
cmd['gait_id'] = 110 # USERGAIT
cmd['vel_des'] = i['body_vel_des']
cmd['rpy_des'] = i['body_pos_des'][0:3]
cmd['pos_des'] = i['body_pos_des'][3:6]
cmd['foot_pose'][0:2] = i['landing_pos_des'][0:2]
cmd['foot_pose'][2:4] = i['landing_pos_des'][3:5]
cmd['foot_pose'][4:6] = i['landing_pos_des'][6:8]
cmd['ctrl_point'][0:2] = i['landing_pos_des'][9:11]
cmd['step_height'][0] = math.ceil(i['step_height'][0] * 1e3) + math.ceil(i['step_height'][1] * 1e3) * 1e3
cmd['step_height'][1] = math.ceil(i['step_height'][2] * 1e3) + math.ceil(i['step_height'][3] * 1e3) * 1e3
cmd['acc_des'] = i['weight']
cmd['value'] = i['use_mpc_traj']
cmd['contact'] = math.floor(i['landing_gain'] * 1e1)
cmd['ctrl_point'][2] = i['mu']
if k == 0:
full_steps['step'] = [cmd]
else:
full_steps['step'].append(cmd)
k = k + 1
# 保存完整步态文件
full_gait_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
'task_4', 'Gait_Params_stoop_full.toml')
with open(full_gait_path, 'w') as f:
f.write("# Gait Params\n")
f.writelines(toml.dumps(full_steps))
# 发送步态文件
usergait_msg = file_send_lcmt()
# 发送步态定义
with open(gait_def_path, 'r') as f:
usergait_msg.data = f.read()
ctrl.lc_s.publish("user_gait_file", usergait_msg.encode())
time.sleep(0.5)
# 发送步态参数
with open(full_gait_path, 'r') as f:
usergait_msg.data = f.read()
ctrl.lc_s.publish("user_gait_file", usergait_msg.encode())
time.sleep(0.1)
# 记录初始位置
initial_pos = ctrl.odo_msg.xyz
info(f"初始位置: x={initial_pos[0]:.3f}, y={initial_pos[1]:.3f}", "位置")
# 执行俯身步态
msg.mode = 62
msg.value = 0
msg.contact = 15
msg.gait_id = 110
msg.duration = 1000
msg.life_count += 1
info("开始执行俯身步态持续5秒", "执行")
start_time = time.time()
while time.time() - start_time < 5.0: # 执行5秒
ctrl.Send_cmd(msg)
time.sleep(0.1)
# 记录最终位置
final_pos = ctrl.odo_msg.xyz
distance_moved = ((final_pos[0] - initial_pos[0])**2 + (final_pos[1] - initial_pos[1])**2)**0.5
info(f"最终位置: x={final_pos[0]:.3f}, y={final_pos[1]:.3f}", "位置")
info(f"移动距离: {distance_moved:.3f}", "距离")
success("俯身步态测试完成", "成功")
except Exception as e:
error(f"俯身步态测试失败: {str(e)}", "失败")
finally:
# 恢复正常模式
msg.mode = 7 # PureDamper
msg.gait_id = 0
msg.duration = 0
msg.life_count += 1
ctrl.Send_cmd(msg)
def test_climbing_gait(ctrl, msg, observe=True):
"""测试爬坡步态"""
section('测试:爬坡步态', "步态测试")
info('开始测试爬坡步态...', "测试")
try:
# 加载爬坡步态配置
gait_config_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
'task_3', 'Gait_Params_up.toml')
gait_def_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
'task_3', 'Gait_Def_up.toml')
if not os.path.exists(gait_config_path):
error(f"爬坡步态配置文件不存在: {gait_config_path}", "错误")
return
steps = toml.load(gait_config_path)
full_steps = {'step':[robot_cmd]}
k = 0
for i in steps['step']:
cmd = copy.deepcopy(robot_cmd)
cmd['duration'] = i['duration']
if i['type'] == 'usergait':
cmd['mode'] = 11 # LOCOMOTION
cmd['gait_id'] = 110 # USERGAIT
cmd['vel_des'] = i['body_vel_des']
cmd['rpy_des'] = i['body_pos_des'][0:3]
cmd['pos_des'] = i['body_pos_des'][3:6]
cmd['foot_pose'][0:2] = i['landing_pos_des'][0:2]
cmd['foot_pose'][2:4] = i['landing_pos_des'][3:5]
cmd['foot_pose'][4:6] = i['landing_pos_des'][6:8]
cmd['ctrl_point'][0:2] = i['landing_pos_des'][9:11]
cmd['step_height'][0] = math.ceil(i['step_height'][0] * 1e3) + math.ceil(i['step_height'][1] * 1e3) * 1e3
cmd['step_height'][1] = math.ceil(i['step_height'][2] * 1e3) + math.ceil(i['step_height'][3] * 1e3) * 1e3
cmd['acc_des'] = i['weight']
cmd['value'] = i['use_mpc_traj']
cmd['contact'] = math.floor(i['landing_gain'] * 1e1)
cmd['ctrl_point'][2] = i['mu']
if k == 0:
full_steps['step'] = [cmd]
else:
full_steps['step'].append(cmd)
k = k + 1
# 保存完整步态文件
full_gait_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
'task_3', 'Gait_Params_up_full.toml')
with open(full_gait_path, 'w') as f:
f.write("# Gait Params\n")
f.writelines(toml.dumps(full_steps))
# 发送步态文件
usergait_msg = file_send_lcmt()
# 发送步态定义
with open(gait_def_path, 'r') as f:
usergait_msg.data = f.read()
ctrl.lc_s.publish("user_gait_file", usergait_msg.encode())
time.sleep(0.5)
# 发送步态参数
with open(full_gait_path, 'r') as f:
usergait_msg.data = f.read()
ctrl.lc_s.publish("user_gait_file", usergait_msg.encode())
time.sleep(0.1)
# 记录初始位置
initial_pos = ctrl.odo_msg.xyz
info(f"初始位置: x={initial_pos[0]:.3f}, y={initial_pos[1]:.3f}", "位置")
# 执行爬坡步态
msg.mode = 62
msg.value = 0
msg.contact = 15
msg.gait_id = 110
msg.duration = 1000
msg.life_count += 1
info("开始执行爬坡步态持续3秒", "执行")
start_time = time.time()
while time.time() - start_time < 3.0: # 执行3秒
ctrl.Send_cmd(msg)
# 监测高度变化
current_height = ctrl.odo_msg.xyz[2]
if time.time() - start_time > 0.5: # 0.5秒后开始监测
height_change = current_height - initial_pos[2]
if observe and int((time.time() - start_time) * 10) % 10 == 0:
info(f"高度变化: {height_change:.3f}", "监测")
time.sleep(0.1)
# 记录最终位置
final_pos = ctrl.odo_msg.xyz
distance_moved = ((final_pos[0] - initial_pos[0])**2 + (final_pos[1] - initial_pos[1])**2)**0.5
height_change = final_pos[2] - initial_pos[2]
info(f"最终位置: x={final_pos[0]:.3f}, y={final_pos[1]:.3f}, z={final_pos[2]:.3f}", "位置")
info(f"水平移动距离: {distance_moved:.3f}", "距离")
info(f"高度变化: {height_change:.3f}", "高度")
success("爬坡步态测试完成", "成功")
except Exception as e:
error(f"爬坡步态测试失败: {str(e)}", "失败")
finally:
# 恢复正常模式
msg.mode = 7 # PureDamper
msg.gait_id = 0
msg.duration = 0
msg.life_count += 1
ctrl.Send_cmd(msg)
def test_stone_road_gait(ctrl, msg, observe=True):
"""测试石板路步态(快步跑)"""
section('测试:石板路步态(快步跑)', "步态测试")
info('开始测试石板路步态...', "测试")
try:
# 记录初始位置
initial_pos = ctrl.odo_msg.xyz
info(f"初始位置: x={initial_pos[0]:.3f}, y={initial_pos[1]:.3f}", "位置")
# 设置石板路步态参数
msg.mode = 11 # 运动模式
msg.gait_id = 3 # 步态ID快步跑
msg.vel_des = [0.35, 0, 0] # 期望速度
msg.pos_des = [0, 0, 0]
msg.duration = 0 # 零时长表示持续运动
msg.step_height = [0.21, 0.21] # 持续运动时摆动腿的离地高度
msg.life_count += 1
info("开始执行石板路步态持续3秒", "执行")
start_time = time.time()
while time.time() - start_time < 3.0: # 执行3秒
ctrl.Send_cmd(msg)
time.sleep(0.1)
# 停止运动
msg.vel_des = [0, 0, 0]
msg.life_count += 1
ctrl.Send_cmd(msg)
# 记录最终位置
final_pos = ctrl.odo_msg.xyz
distance_moved = ((final_pos[0] - initial_pos[0])**2 + (final_pos[1] - initial_pos[1])**2)**0.5
info(f"最终位置: x={final_pos[0]:.3f}, y={final_pos[1]:.3f}", "位置")
info(f"移动距离: {distance_moved:.3f}", "距离")
info(f"平均速度: {distance_moved/3.0:.3f}米/秒", "速度")
success("石板路步态测试完成", "成功")
except Exception as e:
error(f"石板路步态测试失败: {str(e)}", "失败")
finally:
# 恢复正常模式
msg.mode = 7 # PureDamper
msg.gait_id = 0
msg.duration = 0
msg.life_count += 1
ctrl.Send_cmd(msg)
def test_normal_walking_gait(ctrl, msg, observe=True):
"""测试正常行走步态"""
section('测试:正常行走步态', "步态测试")
info('开始测试正常行走步态...', "测试")
try:
# 记录初始位置
initial_pos = ctrl.odo_msg.xyz
info(f"初始位置: x={initial_pos[0]:.3f}, y={initial_pos[1]:.3f}", "位置")
# 使用基础直线移动函数测试正常步态
go_straight(ctrl, msg, distance=1.0, speed=0.5, observe=observe)
# 记录最终位置
final_pos = ctrl.odo_msg.xyz
distance_moved = ((final_pos[0] - initial_pos[0])**2 + (final_pos[1] - initial_pos[1])**2)**0.5
info(f"最终位置: x={final_pos[0]:.3f}, y={final_pos[1]:.3f}", "位置")
info(f"移动距离: {distance_moved:.3f}", "距离")
success("正常行走步态测试完成", "成功")
except Exception as e:
error(f"正常行走步态测试失败: {str(e)}", "失败")
def test_lie_down_stand_up(ctrl, msg, observe=True):
"""测试躺下和站起动作"""
section('测试:躺下和站起动作', "姿态测试")
info('开始测试躺下和站起动作...', "测试")
try:
# 记录初始姿态
initial_pos = ctrl.odo_msg.xyz
info(f"初始位置: x={initial_pos[0]:.3f}, y={initial_pos[1]:.3f}, z={initial_pos[2]:.3f}", "位置")
# 躺下
info("机器人躺下", "动作")
ctrl.base_msg.lie_down(wait_time=3000) # 躺下3秒
# 记录躺下后的位置
lying_pos = ctrl.odo_msg.xyz
info(f"躺下后位置: x={lying_pos[0]:.3f}, y={lying_pos[1]:.3f}, z={lying_pos[2]:.3f}", "位置")
height_change = lying_pos[2] - initial_pos[2]
info(f"高度变化: {height_change:.3f}", "高度")
# 站起来
info("机器人站起来", "动作")
ctrl.base_msg.stand_up()
# 等待站起完成
time.sleep(2)
# 记录站起后的位置
standing_pos = ctrl.odo_msg.xyz
info(f"站起后位置: x={standing_pos[0]:.3f}, y={standing_pos[1]:.3f}, z={standing_pos[2]:.3f}", "位置")
height_recovery = standing_pos[2] - lying_pos[2]
info(f"高度恢复: {height_recovery:.3f}", "高度")
success("躺下和站起动作测试完成", "成功")
except Exception as e:
error(f"躺下和站起动作测试失败: {str(e)}", "失败")
def run_custom_gait_tests(ctrl, msg):
"""运行所有自定义步态测试"""
section('自定义步态测试套件', "开始")
tests = [
("正常行走步态", test_normal_walking_gait),
("石板路步态(快步跑)", test_stone_road_gait),
("躺下和站起动作", test_lie_down_stand_up),
("俯身步态", test_stoop_gait),
("爬坡步态", test_climbing_gait),
]
for test_name, test_func in tests:
try:
info(f"开始执行测试: {test_name}", "测试")
test_func(ctrl, msg)
success(f"测试 {test_name} 成功完成", "成功")
except Exception as e:
error(f"测试 {test_name} 失败: {str(e)}", "失败")
# 每个测试之间暂停
time.sleep(3)
success("所有自定义步态测试完成", "完成")
if __name__ == "__main__":
# 这里可以添加独立运行的代码
print("自定义步态测试脚本")
print("使用方法:")
print("from single_test.test_custom_gait import run_custom_gait_tests")
print("run_custom_gait_tests(ctrl, msg)")