feat: 初始化项目,添加电机控制、CAN通信、QT界面等模块

This commit is contained in:
琉璃月光
2025-08-13 12:36:04 +08:00
commit 9477f25a51
60 changed files with 5816 additions and 0 deletions

View File

@ -0,0 +1,93 @@
#!/usr/bin/env python 主程序
# -*- coding: utf-8 -*-
'''
# @Time : 2025/7/21
# @Author : hx
# @File : can_main.py
'''
import can
import time
# 导入你写的 generate_position_command 函数
from motor_control_can_all import generate_position_command
# ========================================
# 发送CAN帧函数
# ========================================
def send_can_frame(data, can_id=0x01, channel='vcan0', interface='socketcan'):
"""
发送CAN帧
:param data: 7字节的列表
:param can_id: CAN ID
:param channel: CAN 通道
:param interface: 总线类型
"""
try:
bus = can.interface.Bus(channel=channel, interface=interface)
msg = can.Message(arbitration_id=can_id, data=data, is_extended_id=False)
bus.send(msg)
print(f"[发送CAN帧] ID={can_id:02X} 数据=[{', '.join(f'0x{x:02X}' for x in data)}]")
bus.shutdown()
except Exception as e:
print(f"[发送失败] {e}")
# ========================================
# 监听CAN反馈函数
# ========================================
def listen_can_feedback(channel='vcan0', interface='socketcan', timeout=2.0):
"""
监听是否有CAN反馈数据
:param channel: CAN 通道
:param interface: 总线类型
:param timeout: 等待反馈的超时时间(秒)
"""
try:
bus = can.interface.Bus(channel=channel, interface=interface)
print(f"[监听反馈] 等待来自 {channel} 的反馈({timeout}秒超时)...")
msg = bus.recv(timeout=timeout)
if msg:
print(f"[收到反馈] ID={msg.arbitration_id:02X} 数据=[{', '.join(f'0x{x:02X}' for x in msg.data)}]")
else:
print("[未收到反馈]")
bus.shutdown()
except Exception as e:
print(f"[监听失败] {e}")
# ========================================
# 主函数:发送位置控制指令并监听反馈
# ========================================
def can_motor_contral(direction=0, angle=100, microstep=32, can_id=0x01, channel='vcan0', listen_feedback=False):
print("=== 开始发送CAN位置控制指令 ===")
print(f"参数:方向={direction}0=逆时针1=顺时针),角度={angle}°,细分={microstep}")
# 生成CAN数据帧
can_data = generate_position_command(direction=direction, microstep=microstep, angle=angle)
print(f"生成的CAN数据帧: [{', '.join(f'0x{x:02X}' for x in can_data)}]")
# 发送CAN帧
send_can_frame(can_data, can_id=can_id, channel=channel)
# 如果启用监听,等待反馈
if listen_feedback:
listen_can_feedback(channel=channel)
print("=== 电机控制流程完成 ===")
# ========================================
# 程序入口(直接运行时使用)
# ========================================
if __name__ == "__main__":
# 这里写死参数,方便调试
can_motor_contral(
direction=1, # 顺时针
angle=180, # 180度
microstep=16, # 细分值16
can_id=0x02, # CAN ID 0x02
channel='vcan0', # 使用虚拟CAN
listen_feedback=True # 是否监听反馈
)

View File

@ -0,0 +1,15 @@
# can_run_demo.py 调用程序demo
from can_main import can_motor_contral
if __name__ == "__main__":
can_motor_contral(
direction=1,
angle=90,
microstep=32,
can_id=0x03,
channel='vcan0',
listen_feedback=True
)

View File

@ -0,0 +1,174 @@
#!/usr/bin/env python
# 不同模式can发送指令集成
# -*- coding: utf-8 -*-
'''
# @Time : 2025/7/21
# @Author : hx
# @File : motor_control_can_all.py
'''
import can
import time
import argparse
# 细分值映射表
MICROSTEP_MAP = {
2: 0x01,
4: 0x02,
8: 0x04,
16: 0x10,
32: 0x20
}
# ========================================
# CAN 发送函数(使用 socketcan
# ========================================
def send_can_frame(data, can_id=0x01, channel='can0', bustype='socketcan'):
"""
发送CAN帧
:param data: 7字节的列表
:param can_id: CAN ID
:param channel: CAN 通道
:param bustype: 总线类型
"""
try:
bus = can.interface.Bus(channel=channel, bustype=bustype)
msg = can.Message(arbitration_id=can_id, data=data, is_extended_id=False)
bus.send(msg)
print(f"[发送CAN帧] ID={can_id:02X} 数据=[{', '.join(f'0x{x:02X}' for x in data)}]")
bus.shutdown()
except Exception as e:
print(f"[发送失败] {e}")
# ========================================
# 模式1速度控制模式 (0x01)
# ========================================
def generate_speed_command(direction, microstep, speed):
"""
生成速度控制指令
:param direction: 方向 (0:逆时针, 1:顺时针)
:param microstep: 细分值 (2, 4, 8, 16, 32)
:param speed: 速度值 (单位: rad/s)
"""
direction_byte = 0x01 if direction == 1 else 0x00
microstep_byte = MICROSTEP_MAP.get(microstep, 0x20)
raw_speed = int(speed * 10)
speed_high = (raw_speed >> 8) & 0xFF
speed_low = raw_speed & 0xFF
return [0x01, direction_byte, microstep_byte, 0x00, 0x00, speed_high, speed_low]
# ========================================
# 模式2位置控制模式 (0x02)
# ========================================
def generate_position_command(direction, microstep, angle):
"""
生成位置控制指令
:param direction: 方向 (0:逆时针, 1:顺时针)
:param microstep: 细分值 (2, 4, 8, 16, 32)
:param angle: 角度值 (单位: 度)
"""
direction_byte = 0x01 if direction == 1 else 0x00
microstep_byte = MICROSTEP_MAP.get(microstep, 0x20)
raw_angle = int(angle * 10)
pos_high = (raw_angle >> 8) & 0xFF
pos_low = raw_angle & 0xFF
return [0x02, direction_byte, microstep_byte, pos_high, pos_low, 0x00, 0x64]
# ========================================
# 模式3力矩控制模式 (0x03)
# ========================================
def generate_torque_command(direction, microstep, current):
"""
生成力矩控制指令
:param direction: 方向 (0:逆时针, 1:顺时针)
:param microstep: 细分值 (2, 4, 8, 16, 32)
:param current: 电流值 (单位: mA)
"""
direction_byte = 0x01 if direction == 1 else 0x00
microstep_byte = MICROSTEP_MAP.get(microstep, 0x20)
raw_current = int(current)
current_high = (raw_current >> 8) & 0xFF
current_low = raw_current & 0xFF
return [0x03, direction_byte, microstep_byte, current_high, current_low, 0x00, 0x64]
# ========================================
# 模式4单圈绝对角度控制模式 (0x04)
# ========================================
def generate_absolute_angle_command(direction, microstep, angle, speed):
"""
生成单圈绝对角度控制指令
:param direction: 方向 (0:逆时针, 1:顺时针)
:param microstep: 细分值 (2, 4, 8, 16, 32)
:param angle: 目标角度 (单位: 度)
:param speed: 速度值 (单位: rad/s)
"""
direction_byte = 0x01 if direction == 1 else 0x00
microstep_byte = MICROSTEP_MAP.get(microstep, 0x20)
raw_angle = int(angle * 10)
pos_high = (raw_angle >> 8) & 0xFF
pos_low = raw_angle & 0xFF
raw_speed = int(speed * 10)
speed_high = (raw_speed >> 8) & 0xFF
speed_low = raw_speed & 0xFF
return [0x04, direction_byte, microstep_byte, pos_high, pos_low, speed_high, speed_low]
# ========================================
# 主函数(命令行调用)
# ========================================
def main():
parser = argparse.ArgumentParser(description="CAN电机控制程序支持4种模式")
parser.add_argument("--mode", type=int, choices=[1, 2, 3, 4],
help="控制模式: 1=速度, 2=位置, 3=力矩, 4=绝对角度")
parser.add_argument("--direction", type=int, choices=[0, 1], default=1,
help="方向: 0=逆时针, 1=顺时针")
parser.add_argument("--microstep", type=int, choices=[2, 4, 8, 16, 32], default=32,
help="细分值: 2, 4, 8, 16, 32")
parser.add_argument("--value", type=float, required=True,
help="控制值(速度: rad/s, 位置/角度: 度, 力矩: mA")
parser.add_argument("--speed_rad_per_sec", type=float,
help="速度值(仅用于绝对角度模式)")
args = parser.parse_args()
try:
if args.mode == 1:
cmd = generate_speed_command(args.direction, args.microstep, args.value)
elif args.mode == 2:
cmd = generate_position_command(args.direction, args.microstep, args.value)
elif args.mode == 3:
cmd = generate_torque_command(args.direction, args.microstep, args.value)
elif args.mode == 4:
if args.speed_rad_per_sec is None:
raise ValueError("绝对角度模式需要提供速度参数 (--speed_rad_per_sec)")
cmd = generate_absolute_angle_command(args.direction, args.microstep, args.value, args.speed_rad_per_sec)
print(f"生成CAN指令: [{', '.join(f'0x{x:02X}' for x in cmd)}]")
send_can_frame(cmd)
except Exception as e:
print(f"错误: {e}")
# ========================================
# 程序入口
# ========================================
if __name__ == "__main__":
main()
#python motor_control_can_all.py --mode 1 --direction 1 --microstep 32 --value 10
#python motor_control_can_all.py --mode 2 --direction 1 --microstep 32 --value 1000
#python motor_control_can_all.py --mode 3 --direction 1 --microstep 32 --value 1000