from snap7 import client, util
import fastapi
import uvicorn
import serial
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse
from pydantic import BaseModel
from typing_extensions import Literal
from pathlib import Path
from Modbus import ModbusMaster
from ScannerInfo import ScannerInfo
# from PLC_Siemens import UserControlReadWriteOp
from Siemens_PLC import Device_SIEMENS_PLC_S1500
import json
import os
import glob
from pydantic import BaseModel
import threading
import time
# DB 块地址配置
import Config
import struct
import time
import sys
import asyncio
import signal # 新增导入
from contextlib import asynccontextmanager
from snap7 import util
import uvicorn
from fastapi import FastAPI
from Siemens_PLC import Device_SIEMENS_PLC_S1500
import os
import threading
import time
# DB 块地址配置
import Config
import configparser
import struct
import sys
import asyncio
import signal # 新增导入
from contextlib import asynccontextmanager
import json
from typing import Dict, Any
import logging
from typing import Dict, Any
import Modbus
from pydantic import BaseModel
# 单轴伺服运动日志
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[
logging.StreamHandler(), # 输出到控制台
logging.FileHandler("configfiles/move.log") # 同时输出到文件
]
)
speed = 10
# 创建 logger 对象
logger = logging.getLogger(__name__)
# 新增全局退出控制
exit_flag = threading.Event()
lock_Barcode = threading.Lock()
# 临时在代码开头添加测试断点
# import pdb; pdb.set_trace() # 传统调试
# print("DEBUG CHECK") # 在此行设断点
# 创建一个锁对象
lock = threading.Lock()
# 指定本地图片文件夹的路径
# IMAGE_FOLDER = "C:\\Program Files\\VisionMaster4.3.0\\Applications\\RawPicture\\" # 替换为你的图片文件夹路径
# IMAGE_FOLDER = "D:\\RawPicture\\"
PLC = Device_SIEMENS_PLC_S1500.CDevice_SIEMENS()
#初始化钉枪实例
ModbusMaster= ModbusMaster("COM5",115200,1)
ModbusMaster.open()
ModbusMaster.write_register(61506,0x3BBB)
# App Startup
#根据路径下的json文件,创建螺钉机实例
base_dir = os.path.dirname(os.path.abspath(__file__))
# 使用Path对象处理路径
root_path = Path(base_dir)
# 递归遍历所有.json文件
#构造空的扫码枪机字典
ScannerDeviceList ={}
#遍历路径下 json文件
for json_file in root_path.rglob("*.json"):
with open(json_file, 'r', encoding='utf-8') as file:
data = json.load(file)
# 获取配置文件中的IP和Port
DeviceType = data["DeviceType"]
if DeviceType == "Scanner":
#根据json配置内容,创建扫码枪对象实例
info = {json_file.stem: ScannerInfo(json_file.stem,data["Port"],data["Baudrate"])}
ScannerDeviceList.update(info)
# 定义扫码过程
def ScanBarcode():
try:
while not exit_flag.is_set():
try:
for key, scanner in ScannerDeviceList.items():
if not scanner.connected:
continue
try:
waiting = scanner.Device.in_waiting
if waiting > 0:
#time.sleep(0.1)
raw_data = scanner.Device.read(scanner.Device.in_waiting)
try:
decoded_data = raw_data.decode('utf-8').strip()
if decoded_data:
with lock_Barcode:
scanner.Data = decoded_data
print(decoded_data)
#扫到码后调用HZG 服务端指令 HZG完成业务逻辑处理
# logging.info("扫码调用活字格文件")
# print(hzg.BarcodeProcess(key,decoded_data))
# logging.info("扫码调用活字格文件完成")
print(f"[扫码数据] {scanner.Data}")
except UnicodeDecodeError as e:
print(f"解码失败 @ {scanner.Port}: {raw_data.hex()}")
raise RuntimeError("连续解码错误") from e
except (serial.SerialException, OSError) as e:
print(f"硬件错误 @ {scanner.Port}: {str(e)}")
# hzg.SendMessageToHZG(f"硬件错误 @ {scanner.Port}: {str(e)}")
raise # 向上抛出致命错误
except RuntimeError as e:
print(f"扫码系统关键错误: {str(e)}")
exit_flag.set() # 设置全局退出标志
break
time.sleep(0.1)
except Exception as e:
#print(f"扫码线程崩溃: {str(e)}")
exit_flag.set()
os.kill(main_pid, signal.SIGINT) # 直接发送终止信号
@asynccontextmanager
async def lifespan(app: FastAPI):
try:
# 启动时执行的代码
global db_ranges, positions
db_ranges = calculate_db_ranges(Config.db_variables)
positions = read_position_config(file_path)
print("DB读取范围:", db_ranges) # 应输出如 {3: 112}
print("加载的配置变量:", Config.db_variables)
PLC.Connect("192.168.1.1", 0, 0)
print("PLC connected and FastAPI started.")
# 启动线程
threadCheckConnect = threading.Thread(target=CheckConnect, daemon=True)
threadread_plc_data = threading.Thread(target=read_plc_data, daemon=True)
threadCheckConnect.start()
threadread_plc_data.start()
yield # 应用运行期间保持
finally:
# 关闭时执行的代码
print("关闭线程和PLC连接...")
# 停止线程(如果需要)
# 注意:这里假设线程会自动停止,否则需要显式停止
PLC.DisConnect()
print("PLC连接已释放")
app = FastAPI(lifespan=lifespan)
# 读取配置文件
# 假设 BaseResponse 已定义如下
class BaseResponse:
def __init__(self, ErrCode: int, Message: str, data=None):
self.ErrCode = ErrCode
self.Message = Message
self.data = data
def read_position_config(file_path: str) -> Dict[str, Any]:
"""
读取JSON格式的配置文件
:param file_path: JSON文件路径
:return: 包含所有位置数据的字典
"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
config = json.load(f)
print(f"成功读取配置文件: {file_path}") # 调试信息:打印文件路径
print(f"配置内容: {json.dumps(config, indent=4)}") # 调试信息:打印配置内容
return config
except FileNotFoundError:
print(f"错误: 文件未找到 - {file_path}")
return {}
except json.JSONDecodeError as e:
print(f"错误: 配置文件格式错误 - {e}")
return {}
except Exception as e:
print(f"未知错误: {str(e)}")
return {}
# 全局定义文件路径
file_path = "configfiles\\position.json"
# 在程序启动时加载配置文件
positions_config = read_position_config(file_path)
data_store = {}
db_ranges = None
@app.get("/GetBarcode")
async def GetBarcode (Device:str):
try:
if Device in ScannerDeviceList:
device = ScannerDeviceList[Device]
with lock_Barcode:
barcode = device.Data
device.Data = ""
return {"status": 0, "msg": "success", "data": barcode}
else:
return {"status": -1, "msg": "该设备不存在", "data": None}
except Exception as ex:
return {"status": -1, "msg": str(ex), "data": None}
@app.post("/Screw_Gun_Run")
def Screw_Gun():
#设置扭力
set_screw_register(4002,1000)
#设置速度
set_screw_register(4061, 200)
#停止拧螺丝
ModbusMaster.write_register(61500, 0x2BBB)
#开始拧螺丝
ModbusMaster.write_register(61500, 0x2AAA)
time.sleep(3)
value=hex((ModbusMaster.read_register(60630, 30))[0])
if(value==("0x4bbb")):
return 0
return -1
# 设置寄存器值
@app.post("/set_screw_register")
def set_screw_register(register_address: int, value: int):
try:
# 写入寄存器
ModbusMaster.write_register(register_address, value)
return {"status": "success", "message": f"Successfully set register {register_address} to {value}"}
except Exception as e:
return {"status": "error", "message": str(e)}
# 获取寄存器值
@app.get("/get_screw_register")
def get_screw_register(register_address: int, length: int):
try:
# 读取寄存器
result = ModbusMaster.read_register(register_address, length)
return {"status": "success", "data": str(result)}
except Exception as e:
return {"status": "error", "message": str(e)}
@app.post("/Screw_Gun_Close")
def Screw_Gun_Close():
ModbusMaster.close()
def CheckConnect():
while 1:
time.sleep(60)
with lock:
Rlt = PLC.GetCpuState()
print(Rlt)
if Rlt != "S7CpuStatusRun":
PLC.Connect("192.168.1.1", 0, 0)
print("PLC connected and FastAPI started.")
# 计算每个DB块需要读取的字节范围
def calculate_db_ranges(db_vars):
db_info = {}
for group in db_vars:
db = group['db']
max_length = 0
for var in group['vars']:
offset = var['offset']
if var['type'] == 'Int':
length = 2
elif var['type'] == 'Double':
length = 8
elif var['type'] == 'Bool':
length = 1 # 读取整个字节
else:
length = 0
end = offset + length
if end > max_length:
max_length = end
db_info[db] = max_length
return db_info
# 数据读取线程(整体读取DB块)
def read_plc_data():
while True:
try:
global db_ranges
global data_store
# if not plc.get_connected():
# plc.connect(PLC_IP, RACK, SLOT)
# 读取所有DB块数据
start_time = time.time() # 记录开始时间
db_data = {}
for db, length in db_ranges.items():
if length > 0:
# time.sleep(0.01)
with lock:
data = PLC.SiemensPLC.db_read(db, 0, length)
db_data[db] = data
end_time = time.time() # 记录结束时间
elapsed = (end_time - start_time) * 1000
print(f"耗时: {elapsed:.4f} ms") # 输出格式化为4位小数
# 解析变量
temp_data = {}
for group in Config.db_variables:
db = group['db']
data = db_data.get(db, b'')
for var in group['vars']:
offset = var['offset']
var_type = var['type']
try:
if var_type == 'Int':
value = util.get_int(data[offset:offset + 2], 0) if len(data) >= offset + 2 else None
elif var_type == 'Float': # 新增对PLC Real类型的支持
if len(data) >= offset + 4:
try:
value = struct.unpack('>f', data[offset:offset + 4])[0]
except struct.error as e:
print(f"解析Real类型错误: {e}")
value = None
elif var_type == 'Double':
if len(data) >= offset + 8:
reversed_bytes = data[offset:(offset + 8)]
# reversed_bytes.reverse()
# value = util.get_lreal(reversed_bytes,0)
# 转换为Double
value = struct.unpack('>d', reversed_bytes)[0]
# print("转换后的Double值:", value)
elif var_type == 'Bool':
byte = data[offset] if len(data) > offset else 0
bit = var.get('bit', 0)
value = bool((byte >> bit) & 1)
temp_data[var['name']] = value
with lock:
data_store[var['name']] = value
print(data_store)
# 更新全局存储
except Exception as e:
raise "解析错误"
print(f"解析错误 {var['name']}: {e}")
# sys.exit()
end_time = time.time() # 记录结束时间
elapsed = (end_time - start_time) * 1000
print(f"耗时: {elapsed:.4f} ms") # 输出格式化为4位小数
# time.sleep(0.01) # 可根据实际调整采样率
except Exception as e:
print(f"PLC通信异常: {e}")
os.kill(os.getpid(), signal.SIGINT)
def find_plc_parameter(param_name):
"""
在PLC配置中查找指定参数
:param param_name: 要查找的参数名称(如 "RightSafetyLightCurtainBypass")
:param db_config: PLC配置数据
:return: 包含参数信息的字典,若不存在返回None
"""
for db_group in Config.db_variables:
for var in db_group['vars']:
if var['name'] == param_name:
return {
'exists': True,
'db_block': db_group['db'],
'offset': var['offset'],
'type': var['type'],
'bit': var.get('bit', None) # 仅Bool类型有bit位
}
return None
def SetDB(DB: str, Data: str):
# 使用 DB 获取参数
rlt = find_plc_parameter(DB)
# 检查 rlt 是否为 None
if rlt is None:
return -1
# 如果参数存在,则解析相关字段
if rlt["exists"]:
DBNumber = rlt["db_block"]
nType = rlt["type"]
nPort = rlt["offset"]
nBit = rlt["bit"]
try:
# 假设 lock 是一个全局变量或外部定义的对象
with lock:
if nType == "Bool":
if PLC.WriteDBBit(DBNumber, nPort, nBit, int(Data)):
return True
else:
return False
elif nType == "Float":
if PLC.WriteDBFloat(DBNumber, nPort, float(Data)):
return True
else:
return False
elif nType == "Int":
if PLC.WriteDBInt(DBNumber, nPort, int(Data)):
return True
else:
return False
elif nType == "Double":
if PLC.WriteDBDouble(DBNumber, nPort, float(Data)):
return True
else:
return False
elif nType == "String":
if PLC.WriteDBString(DBNumber, nPort, Data):
return True
else:
return False
except Exception as ex:
# 打印异常信息以便调试
print(f"Exception occurred: {ex}")
return -1
def GetDB(DB: str):
value = data_store.get(DB, "未找到变量")
# 如果是布尔值,转换为1/0
if isinstance(value, bool):
return 1 if value else 0
return value
class ModeSwitchRequest(BaseModel):
mode: str
@app.post("/Mode_Switch")
async def Mode_Switch(request: ModeSwitchRequest):
try:
mode = request.mode
if mode not in ["1", "2", "3"]:
raise HTTPException(status_code=400, detail="Invalid mode")
# 设置模式
value = SetDB("mode_switch", int(mode))
await asyncio.sleep(0.1) # 使用异步等待代替 time.sleep
if mode == "1":
if value and GetDB("Production_mode_1") == 1:
return 0
else:
return -1
elif mode == "2":
if value and GetDB("Debugging_Mode_2") == 1:
return 0
else:
return -1
elif mode == "3":
if value and GetDB("Test_run_mode_3") == 1:
return 0
else:
return -1
except Exception as ex:
return -1
@app.post("/LeftReset")
def LeftReset():
try:
SetDB("axis_x_ready", 0)
SetDB("axis_y_ready", 0)
SetDB("axis_z_ready", 0)
SetDB("left_reset", 1)
time.sleep(1)
SetDB("left_reset", 0)
SetDB("axis_x_ready", 1)
SetDB("axis_y_ready", 1)
SetDB("axis_z_ready", 1)
except Exception as ex:
print(f"Exception occurred: {ex}")
return 0
@app.post("/RightReset")
def RightReset():
try:
SetDB("axis_x2_ready", 0)
SetDB("axis_y2_ready", 0)
SetDB("axis_z2_ready", 0)
SetDB("right_reset", 1)
time.sleep(1)
SetDB("right_reset", 0)
SetDB("axis_x2_ready", 1)
SetDB("axis_y2_ready", 1)
SetDB("axis_z2_ready", 1)
except Exception as ex:
print(f"Exception occurred: {ex}")
return 0
#
# @app.get("/variable/{name}")
# async def get_variable(name: str):
# return data_store.get(name, "未找到变量")
class SetSpeedRequest(BaseModel):
x_speed: int
y_speed: int
z_speed: int
@app.post("/Left_SetSpeed")
async def LeftSetSpeed(request: SetSpeedRequest):
# 设置成功返回 0,任意失败返回 -1
try:
# 内部逻辑不变,仅修改传参方式
if not SetDB("actual_act_velocity_x1", request.x_speed):
return -1
if not SetDB("actual_act_velocity_y1", request.y_speed):
return -1
if not SetDB("actual_act_velocity_z1", request.z_speed):
return -1
return 0 # 全部设置成功
except Exception as ex:
# 实际生产环境应记录日志
# logger.error(f"LeftSetSpeed error: {str(ex)}")
return -1
@app.post("/Right_SetSpeed")
async def RightSetSpeed(request: SetSpeedRequest):
# 设置成功返回 0,任意失败返回 -1
try:
# 内部逻辑不变,仅修改传参方式
if not SetDB("actual_act_velocity_x2", request.x_speed):
return -1
if not SetDB("actual_act_velocity_y2", request.y_speed):
return -1
if not SetDB("actual_act_velocity_z2", request.z_speed):
return -1
return 0 # 全部设置成功
except Exception as ex:
# 实际生产环境应记录日志
# logger.error(f"LeftSetSpeed error: {str(ex)}")
return -1
class GetDataRequest(BaseModel):
name: str # The variable name to retrieve
@app.post("/GetData") # Changed from GET to POST to match SetData style
async def GetData(request: GetDataRequest):
with lock:
value = data_store.get(request.name, "未找到变量")
# Convert boolean to 1/0
if isinstance(value, bool):
return 1 if value else 0
return value
@app.get("/all")
async def get_all():
with lock:
return data_store
class SetDataRequest(BaseModel):
DB: str
Data: str
@app.post("/SetData")
async def SetData(request: SetDataRequest):
# 设置成功返回0 反之返回-1
try:
rlt = find_plc_parameter(request.DB) # 使用 request.DB 获取参数
# 检查 rlt 是否为 None
if rlt is None:
return BaseResponse(ErrCode=-1, Message="未找到 PLC 参数", data=None)
if rlt["exists"]:
DBNumber = rlt["db_block"]
nType = rlt["type"]
nPort = rlt["offset"]
nBit = rlt["bit"]
with lock:
if nType == "Bool":
if PLC.WriteDBBit(DBNumber, nPort, nBit, int(request.Data)):
return 0
else:
return -1
elif nType == "Float":
if PLC.WriteDBFloat(DBNumber, nPort, float(request.Data)):
return 0
else:
return -1
elif nType == "Int":
if PLC.WriteDBInt(DBNumber, nPort, int(request.Data)):
return 0
else:
return -1
elif nType == "Double":
if PLC.WriteDBDouble(DBNumber, nPort, float(request.Data)):
return 0
else:
return -1
elif nType == "String":
if PLC.WriteDBString(DBNumber, nPort, request.Data):
return 0
else:
return -1
return None
else:
return BaseResponse(ErrCode=-1, Message="DB 不存在", data=None)
except Exception as ex:
return BaseResponse(ErrCode=-1, Message=str(ex), data="NG")
# def LeftMovePos(XPos: str, YPos: str, ZPos: str):
# try:
#
# # LeftModePos DB13.0 int
# # L_X_ExecuteMode DB13.2.0 bool
# # L_Y_ExecuteMode DB13.20.0 bool
# # L_Z_ExecuteMode DB13.38.0 bool
#
# # L_X_Position DB13.4 Double
# # L_Y_Position DB13.22 Double
# # L_Z_Position DB13.40 Double
#
# # 清除运动信号
# # L_X_ExecuteMode DB13.2.0 bool
# with lock:
# if not PLC.WriteDBBit(13, 2, 0, 0):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
# time.sleep(0.1)
# # L_Y_ExecuteMode DB13.20.0 bool
# with lock:
# if not PLC.WriteDBBit(13, 20, 0, 0):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Z_ExecuteMode DB13.38.0 bool
# with lock:
# if not PLC.WriteDBBit(13, 38, 0, 0):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
# # 写入运动模式
# # LeftModePos DB13.0 int
# with lock:
# if not PLC.WriteDBInt(13, 0, 2):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
# # 写入坐标数值
# # L_X_Position DB13.4 Double
# with lock:
# if not PLC.WriteDBDouble(13, 4, float(XPos)):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Y_Position DB13.22 Double
#
# with lock:
# if not PLC.WriteDBDouble(13, 22, float(YPos)):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Z_Position DB13.40 Double
# with lock:
# if not PLC.WriteDBDouble(13, 40, float(ZPos)):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
# # 写入开始运动信号
# # L_X_ExecuteMode DB13.2.0 bool
# with lock:
# if not PLC.WriteDBBit(13, 2, 0, 1):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Y_ExecuteMode DB13.20.0 bool
#
# with lock:
# if not PLC.WriteDBBit(13, 20, 0, 1):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Z_ExecuteMode DB13.38.0 bool
#
# with lock:
# if not PLC.WriteDBBit(13, 38, 0, 1):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # 执行成功后返回
# return {"ErrCode": 0, "Message": "", "data": "OK"}
#
# except Exception as ex:
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
#
# def RightMovePos(XPos: str, YPos: str, ZPos: str):
# try:
#
# # LeftModePos DB13.0 int
# # L_X_ExecuteMode DB13.2.0 bool
# # L_Y_ExecuteMode DB13.20.0 bool
# # L_Z_ExecuteMode DB13.38.0 bool
#
# # L_X_Position DB13.4 Double
# # L_Y_Position DB13.22 Double
# # L_Z_Position DB13.40 Double
#
# # 清除运动信号
# # L_X_ExecuteMode DB13.2.0 bool
# with lock:
# if not PLC.WriteDBBit(13, 2, 0, 0):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
# time.sleep(0.1)
# # L_Y_ExecuteMode DB13.20.0 bool
# with lock:
# if not PLC.WriteDBBit(13, 20, 0, 0):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Z_ExecuteMode DB13.38.0 bool
# with lock:
# if not PLC.WriteDBBit(13, 38, 0, 0):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
# # 写入运动模式
# # LeftModePos DB13.0 int
# with lock:
# if not PLC.WriteDBInt(13, 0, 2):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
# # 写入坐标数值
# # L_X_Position DB13.4 Double
# with lock:
# if not PLC.WriteDBDouble(13, 4, float(XPos)):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Y_Position DB13.22 Double
#
# with lock:
# if not PLC.WriteDBDouble(13, 22, float(YPos)):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Z_Position DB13.40 Double
# with lock:
# if not PLC.WriteDBDouble(13, 40, float(ZPos)):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
# # 写入开始运动信号
# # L_X_ExecuteMode DB13.2.0 bool
# with lock:
# if not PLC.WriteDBBit(13, 2, 0, 1):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Y_ExecuteMode DB13.20.0 bool
#
# with lock:
# if not PLC.WriteDBBit(13, 20, 0, 1):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # L_Z_ExecuteMode DB13.38.0 bool
#
# with lock:
# if not PLC.WriteDBBit(13, 38, 0, 1):
# return {"ErrCode": -1, "Message": "", "data": "NG"}
# # 执行成功后返回
# return {"ErrCode": 0, "Message": "", "data": "OK"}
#
# except Exception as ex:
# return {"ErrCode": -1, "Message": "", "data": "NG"}
#
#
@app.get("/LeftMoveX")
def LeftMoveX(pos: str) -> int:
"""左工位X轴运动"""
try:
# 1. 停止当前运动
if not SetDB("x1_executes_the_movement", 0):
return -1
# 2. 开启使能
if not SetDB("axis_x_ready", 1):
return -1
# 3.启动信号)
if not SetDB("left_start", 1):
return -1
if not SetDB("actual_pos_x1", pos):
return -1
# 4.执行运动
if not SetDB("x1_executes_the_movement", 1):
return -1
return 0 # 成功
except Exception as ex:
logger.error(f"LeftMoveX error: {str(ex)}")
return -1
@app.get("/LeftMoveY")
def LeftMoveY(pos: str) -> int:
"""左工位X轴运动"""
try:
# 1. 停止当前运动
if not SetDB("y1_executes_the_movement", 0):
return -1
if not SetDB("axis_y_ready", 1):
return -1
if not SetDB("left_start", 1):
return -1
if not SetDB("actual_pos_y1", pos):
return -1
if not SetDB("y1_executes_the_movement", 1):
return -1
return 0 # 成功
except Exception as ex:
logger.error(f"LeftMoveY error: {str(ex)}")
return -1
class RightMoveZRequest(BaseModel):
pos: str # 保持原参数类型为str
@app.post("/LeftMoveZ")
def LeftMoveZ(request: RightMoveZRequest) :
"""左工位Z轴运动"""
try:
# 1. 停止当前运动
if not SetDB("z1_executes_the_movement", 0):
return -1
if not SetDB("axis_z_ready", 1):
return -1
if not SetDB("left_start", 1):
return -1
if not SetDB("actual_pos_z1", request.pos):
return -1
if not SetDB("z1_executes_the_movement", 1):
return -1
return 0 # 成功
except Exception as ex:
logger.error(f"LeftMoveZ error: {str(ex)}")
return -1
async def LeftMovePos(XPos: str, YPos: str, ZPos: str) -> Dict[str, Any]:
"""左工位全轴运动"""
results = []
# 按顺序移动各轴
if XPos:
results.append(LeftMoveX(XPos))
if YPos:
results.append(LeftMoveY(YPos))
if ZPos:
results.append(LeftMoveZ(ZPos))
# 检查所有轴是否都成功
if all(res == 0 for res in results):
return {"ErrCode": 0, "Message": "", "data": "OK"}
else:
return {"ErrCode": -1, "Message": "部分轴运动失败", "data": "NG"}
@app.post("/Move")
def Move(pos_X: int, pos_Y: int, pos_Z: int, ready: int, start: int, ready2: int):
SetDB("x1_executes_the_movement", 0)
SetDB("y1_executes_the_movement", 0)
SetDB("z1_executes_the_movement", 0)
SetDB("axis_x_ready", ready)
SetDB("axis_y_ready", ready)
SetDB("axis_z_ready", ready)
SetDB("left_start", start)
SetDB("actual_act_velocity_x1", 10)
SetDB("actual_act_velocity_y1", 10)
SetDB("actual_act_velocity_z1", 10)
SetDB("actual_pos_x1", pos_X)
SetDB("actual_pos_y1", pos_Y)
SetDB("actual_pos_z1", pos_Z)
SetDB("x1_executes_the_movement", ready2)
SetDB("x1_executes_the_movement", ready2)
SetDB("x1_executes_the_movement", ready2)
def _right_move_x(pos: str) -> int:
"""右工位 X 轴运动的核心逻辑"""
try:
if not SetDB("x2_executes_the_movement", 0):
return -1
if not SetDB("axis_x2_ready", 1):
return -1
if not SetDB("start_right", 1):
return -1
if not SetDB("actual_pos_x2", pos):
return -1
if not SetDB("x2_executes_the_movement", 1):
return -1
return 0
except Exception as ex:
logger.error(f"RightMoveX error: {str(ex)}")
return -1
@app.get("/RightMoveX")
def RightMoveX(pos: str) -> int:
"""左工位X轴运动"""
try:
# 1. 停止当前运动
if not SetDB("x2_executes_the_movement", 0):
return -1
# 2. 开启使能
if not SetDB("axis_x2_ready", 1):
return -1
# 3.启动信号)
if not SetDB("right_start", 1):
return -1
if not SetDB("actual_pos_x2", pos):
return -1
# 4.执行运动
if not SetDB("x2_executes_the_movement", 1):
return -1
return 0 # 成功
except Exception as ex:
logger.error(f"LeftMoveX error: {str(ex)}")
return -1
#
#
@app.get("/RightMoveY")
def RightMoveY(pos: str) -> int:
"""右工位Y轴运动"""
try:
# 1. 停止当前运动
if not SetDB("y2_executes_the_movement", 0):
return -1
# 2. 开启使能
if not SetDB("axis_y2_ready", 1):
return -1
# 3.启动信号
if not SetDB("start_right", 1):
return -1
if not SetDB("actual_pos_y2", pos):
return -1
# 4.执行运动
if not SetDB("y2_executes_the_movement", 1):
return -1
return 0 # 成功
except Exception as ex:
logger.error(f"RightMoveY error: {str(ex)}")
return -1
@app.post("/RightMoveZ")
async def RightMoveZ(request: RightMoveZRequest) -> int:
"""右工位Z轴运动"""
try:
# 1. 停止当前运动
if not SetDB("z2_executes_the_movement", 0):
return -1
# 2. 开启使能
if not SetDB("axis_z2_ready", 1):
return -1
# 3.启动信号
if not SetDB("start_right", 1):
return -1
if not SetDB("actual_pos_z2", request.pos): # 使用request.pos获取参数
return -1
# 4.执行运动
if not SetDB("z2_executes_the_movement", 1):
return -1
return 0 # 成功
except Exception as ex:
logger.error(f"RightMoveZ error: {str(ex)}")
return -1
async def RightMovePos(XPos: str, YPos: str, ZPos: str) -> Dict[str, Any]:
"""右工位全轴运动"""
results = []
if XPos:
results.append(RightMoveX(XPos))
if YPos:
results.append(RightMoveY(YPos))
if ZPos:
results.append(RightMoveZ(ZPos))
if all(res == 0 for res in results):
return {"ErrCode": 0, "Message": "", "data": "OK"}
else:
return {"ErrCode": -1, "Message": "部分轴运动失败", "data": "NG"}
def _SetData_(DB: str, Data: str):
try:
rlt = find_plc_parameter(DB)
if rlt["exists"]:
DBNumber = rlt["db_block"]
nType = rlt["type"]
nPort = rlt["offset"]
nBit = rlt["bit"]
if nType == "Bool":
with lock:
if PLC.WriteDBBit(DBNumber, nPort, nBit, int(Data)):
return {"ErrCode": 0, "Message": "success", "data": "OK"}
else:
return {"ErrCode": -1, "Message": "success", "data": "NG"}
elif nType == "Float":
with lock:
if PLC.WriteDBFloat(DBNumber, nPort, float(Data)):
return {"ErrCode": 0, "Message": "success", "data": "OK"}
else:
return {"ErrCode": -1, "Message": "success", "data": "NG"}
elif nType == "Int":
with lock:
if PLC.WriteDBInt(DBNumber, nPort, int(Data)):
return {"ErrCode": 0, "Message": "success", "data": "OK"}
else:
return {"ErrCode": -1, "Message": "success", "data": "NG"}
elif nType == "Double":
with lock:
if PLC.WriteDBDouble(DBNumber, nPort, float(Data)):
return {"ErrCode": 0, "Message": "success", "data": "OK"}
else:
return {"ErrCode": -1, "Message": "success", "data": "NG"}
elif nType == "String":
with lock:
data = PLC.WriteDBString(DBNumber, nPort, Data)
return {"ErrCode": 0, "Message": "success", "data": "OK"}
return None
else:
return {"ErrCode": -1, "Message": "DB 不存在", "data": None}
except Exception as ex:
return {"ErrCode": -1, "Message": str(ex), "data": None}
@app.post("/RightMoveZero")
def RightMoveZero(Axis: str):
try:
if Axis.upper() == "X":
Rlt1 = SetDB("x2_executes_the_movement", "0")
Rlt2 = SetDB("axis_x2_ready", "1")
Rlt3 = SetDB("start_right", "1")
Rlt4 = SetDB("actual_pos_x2", "0")
Rlt5 = SetDB("x2_executes_the_movement", "1")
if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True:
return 0
else:
return -1
elif Axis.upper() == "Y":
Rlt1 = SetDB("y2_executes_the_movement", "0")
Rlt2 = SetDB("axis_y2_ready", "1")
Rlt3 = SetDB("start_right", "1")
Rlt4 = SetDB("actual_pos_y2", "0")
Rlt5 = SetDB("y2_executes_the_movement", "1")
if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True:
return 0
else:
return -1
elif Axis.upper() == "Z":
Rlt1 = SetDB("z2_executes_the_movement", "0")
Rlt2 = SetDB("axis_z2_ready", "1")
Rlt3 = SetDB("start_right", "1")
Rlt4 = SetDB("actual_pos_z2", "0")
Rlt5 = SetDB("z2_executes_the_movement", "1")
if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True:
return 0
else:
return -1
else:
return -1
except Exception as ex:
return -1
@app.post("/LeftMoveZero")
def LeftMoveZero(Axis: str):
try:
if Axis.upper() == "X":
Rlt1 = SetDB("x1_executes_the_movement", "0")
Rlt2 = SetDB("axis_x_ready", "1")
Rlt3 = SetDB("left_start", "1")
Rlt4 = SetDB("actual_pos_x1", "0")
Rlt5 = SetDB("x1_executes_the_movement", "1")
if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True:
return 0
else:
return -1
elif Axis.upper() == "Y":
Rlt1 = SetDB("y1_executes_the_movement", "0")
Rlt2 = SetDB("axis_y_ready", "1")
Rlt3 = SetDB("left_start", "1")
Rlt4 = SetDB("actual_pos_y1", "0")
Rlt5 = SetDB("y1_executes_the_movement", "1")
if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True:
return 0
else:
return -1
elif Axis.upper() == "Z":
Rlt1 = SetDB("z1_executes_the_movement", "0")
Rlt2 = SetDB("axis_z_ready", "1")
Rlt3 = SetDB("left_start", "1")
Rlt4 = SetDB("actual_pos_z1", "0")
Rlt5 = SetDB("z1_executes_the_movement", "1")
if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True:
return 0
else:
return -1
else:
return -1
except Exception as ex:
return -1
class AxisArriveRequest(BaseModel):
Axis: Literal['X', 'Y', 'Z','x','y','z'] # 限定只能传X,Y,Z
@app.post("/Left_AxisArrive")
async def Left_AxisArrive(request: AxisArriveRequest):
try:
axis = request.Axis
if axis == "X":
db_value = GetDB("x1_completed")
if(db_value==1):
return 0
else:return -1
elif axis == "Y":
db_value = GetDB("y1_completed")
if (db_value == 1):
return 0
else:
return -1
elif axis == "Z":
db_value = GetDB("z1_completed")
if (db_value == 1):
return 0
else:
return -1
except Exception as ex:
return -1
@app.post("/Right_AxisArrive")
async def Right_AxisArrive(request: AxisArriveRequest):
try:
axis = request.Axis.upper()
if axis == "X":
db_value = GetDB("x2_completed")
if (db_value == 1):
return 0
else:
return -1
elif axis == "Y":
db_value = GetDB("y2_completed")
if (db_value == 1):
return 0
else:
return -1
elif axis == "Z":
db_value = GetDB("z2_completed")
if (db_value == 1):
return 0
else:
return -1
except Exception as ex:
return -1
@app.get("/MoveToZero")
async def MoveToZero(Station: str, Axis: str):
try:
if Station.upper() == "LEFT":
return LeftMoveZero(Axis)
elif Station.upper() == "RIGHT":
return RightMoveZero(Axis)
else:
return -1
except Exception as ex:
return -1
# @app.get("/MovePos")
# async def MovePos(Station: str, XPos: str, YPos: str, ZPos: str):
# try:
# if Station == "0":
# return LeftMovePos(XPos, YPos, ZPos)
# elif Station == "1":
# pass
# # return RightMovePos(XPos, YPos, ZPos)
# else:
# return {"ErrCode": -1, "Message": "Station 错误", "data": "NG"}
#
# except Exception as ex:
# return {"ErrCode": -1, "Message": "", "data": "NG"}
class MoveAxisRequest(BaseModel):
station: str
position_name: str
mode: str
type_name: str
@app.post("/MoveAxis")
async def MoveAxis(request: MoveAxisRequest):
"""
根据型号和位置名称调用运动控制函数
:param request: 包含以下字段的请求体:
station: 工位号 "LEFT" 或 "RIGHT"
position_name: 位置名称(如 "PO1")
mode: 运动模式 "X"/"Y"/"Z"/"ALL"
type_name: 型号名称(如 "Type1")
:return: 运动控制结果
"""
try:
station = request.station.upper()
mode = request.mode.upper()
position_name = request.position_name
type_name = request.type_name
# 检查配置文件
if not positions_config:
raise HTTPException(
status_code=500,
detail=f"无法读取配置文件: {file_path}"
)
# 参数校验
if station not in ("LEFT", "RIGHT"):
raise HTTPException(
status_code=400,
detail="工位参数错误,只能是LEFT或RIGHT"
)
if mode not in ("X", "Y", "Z", "ALL"):
raise HTTPException(
status_code=400,
detail="运动模式错误,只能是X/Y/Z/ALL"
)
# 验证型号存在
if type_name not in positions_config:
available_types = ", ".join(positions_config.keys())
raise HTTPException(
status_code=404,
detail=f"型号 {type_name} 不存在,可用型号: {available_types}"
)
type_positions = positions_config[type_name]
# 验证位置存在
if position_name not in type_positions:
available_positions = ", ".join(type_positions.keys())
raise HTTPException(
status_code=404,
detail=f"位置 {position_name} 在型号 {type_name} 中不存在,可用位置: {available_positions}"
)
pos = type_positions[position_name]
# 异步运动控制封装
async def execute_motion(func, *args):
result = await asyncio.to_thread(func, *args)
if result != 0:
return -1
return 0
# 根据模式和工位执行运动
if mode == "X":
func = LeftMoveX if station == "LEFT" else RightMoveX # ✅ 直接调用核心函数
result = await execute_motion(func, pos["X"])
elif mode == "Y":
func = LeftMoveY if station == "LEFT" else RightMoveY
result = await execute_motion(func, pos["Y"])
elif mode == "Z":
func = LeftMoveZ if station == "LEFT" else RightMoveZ
result = await execute_motion(func, pos["Z"])
else: # ALL模式
func = LeftMovePos if station == "LEFT" else RightMovePos
result = await execute_motion(func, pos["X"], pos["Y"], pos["Z"])
return 0
except HTTPException as he:
# 传递已抛出的HTTP异常
raise he
except Exception as ex:
raise HTTPException(
status_code=500,
detail=f"运动控制执行错误: {str(ex)}"
)
if __name__ == "__main__":
# 创建 FastAPI 实例时传入 lifespan
uvicorn.run(app, host="0.0.0.0", port=39000, log_level="info")
以上代码中遍历路径下的json文件,是哪个路径
最新发布