修改步进电机接口、通讯方式和EMV的接口

This commit is contained in:
2026-02-06 15:16:17 +08:00
parent 17df13c08e
commit 5c9946dfc7
7 changed files with 432 additions and 1111 deletions

View File

@ -4,15 +4,17 @@
# @Time : 2026/1/9 10:45
# @Author : reenrr
# @File : RK1106_server.py
# @Desc : RK1106服务端等待工控机调用
# @Desc : RK1106服务端等待工控机调用 通信为JSON格式
'''
import socket
import logging
import sys
from test import motor_demo
import json
from stepper_motor import motor_start, align_wire, cleanup, motor_stop
# --------日志配置(终端+文件双输出)--------------
# ------------日志配置(终端+文件双输出)--------------
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
@ -30,88 +32,177 @@ logging.basicConfig(
)
# --------配置TCP服务端----------
HOST = "127.0.0.1"
HOST = "192.168.0.100"
PORT = 8888
# 程序映射表(指令表示 -> 执行函数)
PROG_MAP = {
# "STEPPER_TEST": motor_test_demo,
"test": motor_demo
# 全局参数缓存
MOTOR_CONFIG = {
"speed": 2500, # 默认速度
"cycle": 10.0, # 默认旋转圈数
}
def parse_command(cmd_str: str) ->tuple[str, dict]:
def handle_setting(para_type: str, para_value: str) ->dict:
"""
解析工控机发送的指令字符串
:param cmd_str: 指令字符串
:return: 指令名称,参数字典
处理客户端发送的参数设置指令cmd:"setting"),更新全局电机配置
:param para_type: 要设置的参数类型,仅支持"speed""cycle"
:param para_value: 参数值字符串将尝试转换为int(speed)或float(cycle)
:return: 标准化相应字典dict,如:
{
"Result": "1"表示成功,"0"表示失败,
"ErrMsg": str # 成功提示或错误详情
}
"""
# 空指令处理
if not cmd_str or cmd_str.strip() == "":
return "", {}
try:
if para_type == "speed":
MOTOR_CONFIG["speed"] = int(para_value)
elif para_type == "cycle":
MOTOR_CONFIG["cycle"] = float(para_value)
else:
return {"Result": "0", "ErrMsg": f"不支持的参数类型: {para_type}"}
return {"Result": "1", "ErrMsg": "设置成功"}
except ValueError as e:
return {"Result": "0", "ErrMsg": f"参数值格式错误: {str(e)}"}
# 分割指令标识和参数
cmd_parts = cmd_str.strip().split("|", 1)
prog_id = cmd_parts[0].strip()
params = {}
def handle_start(para_type: str, para_value: str) -> dict:
"""
处理启动电机指令cmd: "start"),使用当前MOTOR_CONFIG配置运行电机
:param para_type:为"direction"时,使用"para_value"作为临时方向
:param para_value:为0或1
:return: 标准化相应字典dict,如:
{
"Result": "1"表示成功,"0"表示失败,
"ErrMsg": str #执行结果或异常信息
}
"""
try:
if para_type == "direction":
direction = int(para_value)
if direction not in (0,1):
return {"Result": "0", "ErrMsg": "方向必须为0或1"}
# 解析参数格式param1=val1&param2=val2
if len(cmd_parts) > 1 and cmd_parts[1].strip() != "":
param_str = cmd_parts[1].strip()
param_pairs = param_str.split("&")
for pair in param_pairs:
if "=" in pair:
key, value = pair.split("=", 1) # 处理值中含=的情况
# 类型自动转换(数字/字符串)
try:
params[key.strip()] = int(value.strip())
except ValueError:
try:
params[key.strip()] = float(value.strip())
except ValueError:
params[key.strip()] = value.strip()
motor_start(speed=MOTOR_CONFIG["speed"],
cycle=MOTOR_CONFIG["cycle"],
direction=direction)
dir_str = "正向" if direction == 1 else "负向"
return {"Result": "1", "ErrMsg": f"电机启动成功({dir_str}"}
else:
return {"Result": "0", "ErrMsg": "start 指令仅支持'direction'"}
except Exception as e:
return {"Result": "0", "ErrMsg": f"电机启动失败:{str(e)}"}
def handle_stop() -> dict:
"""
处理停止电机指令cmd: "stop")
:return: 标准化相应字典dict,如:
{
"Result": "1"表示成功,"0"表示失败,
"ErrMsg": str #执行结果或异常信息
}
"""
try:
motor_stop()
return {"Result": "1", "ErrMsg": "电机已停止"}
except Exception as e:
return {"Result": "0", "ErrMsg": f"电机停止失败:{str(e)}"}
def handle_align() -> dict:
"""
处理线条对齐(挡板一来一回)
:return: dict
"""
try:
align_wire(MOTOR_CONFIG['speed'], MOTOR_CONFIG['cycle'])
return {"Result": "1", "ErrMsg": "处理线条对齐"}
except Exception as e:
return {"Result": "0", "ErrMsg": "线条对齐失败"}
def parse_json_command(data: str) -> dict:
"""
解析客户端发送的原始JSON字符串指令并分发至对应处理函数
:param data: 客户端发送的原始JSON字符串
:return dict:标准化响应字典
"""
try:
cmd_obj = json.loads(data.strip())
except json.JSONDecodeError as e:
return {"Result": "0", "ErrMsg": f"JSON 格式错误: {str(e)}"}
cmd = cmd_obj.get("cmd", "").strip()
para_type = cmd_obj.get("para_type", "").strip()
para_value = cmd_obj.get("para_value", "").strip()
if cmd == "setting":
return handle_setting(para_type, para_value)
elif cmd == "start":
return handle_start(para_type, para_value)
elif cmd == "stop":
if para_type == "none" and para_value == "none":
return handle_stop()
else:
return {"Result": "0", "ErrMsg": "stop指令参数必须为none"}
elif cmd == "alignment":
if para_type == "none" and para_value == "none":
return handle_align()
else:
return {"Result": "0", "ErrMsg": "alignment指令参数必须为none"}
else:
return {"Result": "0", "ErrMsg": f"未知指令:{cmd}"}
return prog_id, params
# ----------对外接口----------
def server():
"""启动TCP服务端监听指定端口接收工控机连接并循环处理JSON指令"""
# 创建TCP socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
# 允许端口复用
server_socket = None
conn = None
try:
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(1) # 只允许1个工控机连接
logging.info(f"[1106] 服务已启动,监听端口:{PORT},等待工控机连接...")
# 等待工控机连接
conn, addr = server_socket.accept()
with conn:
logging.info(f"[1106] 工控机已连接:{addr}")
# 循环接收指令
while True:
# 接收指令最大1024字节
data = conn.recv(1024).decode()
logging.info(f"\n[1106] 收到工控机指令:{data}")
# 解析指令
prog_id, params = parse_command(data)
logging.info(f"[1106] 解析结果 - 指令:{prog_id},参数:{params}")
while True: # 持续接受新连接
try:
# 等待工控机连接
conn, addr = server_socket.accept()
logging.info(f"[1106] 工控机已连接:{addr}")
# 执行对应程序
responses = ""
if prog_id in PROG_MAP:
try:
result = PROG_MAP[prog_id](**params)
response = f"SUCCESS|步进电机测试执行完成,结果:{result}"
logging.info(f"[1106] {response}")
except Exception as e:
response = f"FAIL|步进电机测试执行失败:{str(e)}"
logging.error(f"[1106] {response}", exc_info=True)
else:
response = f"FAIL|未知指令:{prog_id},支持指令:{list(PROG_MAP.keys())}"
logging.warning(f"[1106] {response}")
# 循环接收指令
while True:
# 接收指令最大1024字节
data = conn.recv(1024).decode()
if not data:
logging.warning("客户端断开连接")
break
# 发送响应给工控机
conn.sendall(response.encode("utf-8"))
logging.info(f"[1106] 已发送响应:{response}")
logging.info(f"\n[1106] 收到工控机指令:{data}")
# 解析指令
response_dict = parse_json_command(data)
response_json = json.dumps(response_dict, ensure_ascii=False) + "\n" # 看需不需要加换行符\n
# 发送响应给工控机
conn.sendall(response_json.encode("utf-8"))
logging.info(f"[1106] 已发送响应:{response_json}")
except ConnectionError:
logging.info("客户端异常断开")
except Exception as e:
logging.info(f"处理连接时发生错误: {e}")
finally:
if conn is not None:
conn.close()
conn = None # 重置,避免重复关闭
logging.info("客户端连接已关闭,等待新连接...")
except KeyboardInterrupt:
logging.info("\n收到 Ctrl+C正在关闭服务...")
finally:
if server_socket:
server_socket.close()
logging.info("服务已停止,监听 socket 已释放")
# ----------测试接口----------
if __name__ == "__main__":