返回教程正文

配套源码

gateway_client.py

can-gateway/gateway_client.py
zdt-x57s-can-test:封装单电机 Brick 并组合验证四台电机can-gateway/gateway_client.py
Python126 行
  1. #!/usr/bin/env python3
  2. """
  3. @description : 从Linux主机手动调用ZDT X57S CAN网关用于诊断
  4. @param : 无
  5. @return : 无
  6. """
  7. import argparse
  8. import json
  9. import os
  10. import socket
  11. import uuid
  12. MOTION_CONFIRMATION = "RUN_ZDT_X57S_V1_0"
  13. def parse_args():
  14. """
  15. @description : 解析网关状态、探测或单电机限时测试参数
  16. @param : 无
  17. @return : argparse.Namespace参数对象
  18. """
  19. parser = argparse.ArgumentParser(description="Call the local CAN gateway.")
  20. action = parser.add_mutually_exclusive_group(required=True)
  21. action.add_argument("--status", action="store_true")
  22. action.add_argument("--probe", action="store_true")
  23. action.add_argument("--motor-test", action="store_true")
  24. parser.add_argument("--host", default="172.17.0.1")
  25. parser.add_argument("--port", type=int, default=8766)
  26. parser.add_argument("--motor-id", type=int, default=1)
  27. parser.add_argument("--rpm", type=int, default=20)
  28. parser.add_argument("--acceleration-level", type=int, default=10)
  29. parser.add_argument("--duration", type=float, default=3.0)
  30. parser.add_argument("--confirm", default="")
  31. parser.add_argument(
  32. "--token-file",
  33. default=os.path.join(os.path.dirname(__file__), ".gateway-token"),
  34. )
  35. return parser.parse_args()
  36. def load_token(path):
  37. """
  38. @description : 读取Linux网关共享鉴权令牌
  39. @param path : 令牌文件路径
  40. @return : 非空令牌字符串
  41. """
  42. with open(path, "r", encoding="utf-8") as token_stream:
  43. token = token_stream.read().strip()
  44. if not token:
  45. raise RuntimeError("gateway token file is empty")
  46. return token
  47. def call_gateway(host, port, token, method, params, timeout_s):
  48. """
  49. @description : 发送一条换行分隔JSON请求并读取响应
  50. @param host : 网关地址
  51. @param port : 网关端口
  52. @param token : 共享鉴权令牌
  53. @param method : 网关方法名称
  54. @param params : 方法参数字典
  55. @param timeout_s : 连接和响应超时时间
  56. @return : 解码后的响应字典
  57. """
  58. request = {
  59. "version": 1,
  60. "request_id": uuid.uuid4().hex,
  61. "token": token,
  62. "method": method,
  63. "params": params,
  64. }
  65. with socket.create_connection((host, port), timeout=timeout_s) as connection:
  66. connection.settimeout(timeout_s)
  67. connection.sendall((json.dumps(request) + "\n").encode("utf-8"))
  68. with connection.makefile("rb") as response_stream:
  69. response_line = response_stream.readline(65537)
  70. if not response_line:
  71. raise RuntimeError("gateway closed without a response")
  72. return json.loads(response_line.decode("utf-8"))
  73. def main():
  74. """
  75. @description : 根据命令行参数调用网关并打印格式化JSON结果
  76. @param : 无
  77. @return : 网关成功返回0; 网关失败返回1; 确认失败返回2
  78. """
  79. args = parse_args()
  80. token = load_token(args.token_file)
  81. if args.status:
  82. method = "status"
  83. params = {}
  84. timeout_s = 2.0
  85. elif args.probe:
  86. method = "read_speed"
  87. params = {"motor_id": args.motor_id}
  88. timeout_s = 2.0
  89. else:
  90. if args.confirm != MOTION_CONFIRMATION:
  91. print(
  92. "拒绝运行:请确认电机已架空并添加 "
  93. f"--confirm {MOTION_CONFIRMATION}"
  94. )
  95. return 2
  96. method = "timed_speed_test"
  97. params = {
  98. "motor_id": args.motor_id,
  99. "rpm": args.rpm,
  100. "acceleration_level": args.acceleration_level,
  101. "duration_s": args.duration,
  102. "confirmation": args.confirm,
  103. }
  104. timeout_s = args.duration + 5.0
  105. response = call_gateway(
  106. args.host, args.port, token, method, params, timeout_s
  107. )
  108. print(json.dumps(response, ensure_ascii=False, indent=2))
  109. return 0 if response.get("ok") is True else 1
  110. if __name__ == "__main__":
  111. raise SystemExit(main())