File size: 6,136 Bytes
f52a1d4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/env python3
"""
Kuavo机器人控制指令发送器
用于向正在运行的script.py进程发送控制指令

使用示例:
  python controller.py pause    # 暂停机械臂运动
  python controller.py resume   # 恢复机械臂运动
  python controller.py stop     # 停止机械臂运动
  python controller.py status   # 查看进程状态
"""

import os
import sys
import signal
import psutil
import argparse
from pathlib import Path

def find_example_process():
    """
    查找正在运行的script.py进程
    
    Returns:
        psutil.Process: 找到的进程对象,如果没找到返回None
    """
    target_processes = []
    
    for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
        try:
            # 检查进程名或命令行参数
            if (proc.info['name'] == 'python' or proc.info['name'] == 'python3') and proc.info['cmdline']:
                cmdline = ' '.join(proc.info['cmdline'])
                
                # 精确匹配 kuavo_deploy/src/scripts/script.py 路径
                if 'kuavo_deploy/src/scripts/script.py' in cmdline:
                    target_processes.append((proc, 'exact'))
                    
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
            continue

    if len(target_processes) != 1:
        print(f"❌ 找到 {len(target_processes)} 个匹配的进程,请使用 --pid 参数指定进程ID")
        sys.exit(1)
    else:
        return target_processes[0][0]

def send_signal_to_process(proc, signal_type):
    """
    向指定进程发送信号
    
    Args:
        proc: psutil.Process对象
        signal_type: 信号类型 ('pause', 'resume', 'stop')
    """
    try:
        if signal_type == 'pause':
            proc.send_signal(signal.SIGUSR1)
            print(f"✅ 已发送暂停信号到进程 {proc.pid}")
        elif signal_type == 'resume':
            proc.send_signal(signal.SIGUSR1)
            print(f"✅ 已发送恢复信号到进程 {proc.pid}")
        elif signal_type == 'stop':
            proc.send_signal(signal.SIGUSR2)
            print(f"✅ 已发送停止信号到进程 {proc.pid}")
        else:
            print(f"❌ 未知的信号类型: {signal_type}")
            return False
        return True
    except psutil.NoSuchProcess:
        print(f"❌ 进程 {proc.pid} 不存在")
        return False
    except psutil.AccessDenied:
        print(f"❌ 没有权限向进程 {proc.pid} 发送信号")
        return False
    except Exception as e:
        print(f"❌ 发送信号时发生错误: {e}")
        return False

def show_process_status(proc):
    """
    显示进程状态信息
    
    Args:
        proc: psutil.Process对象
    """
    try:
        print(f"📊 进程信息:")
        print(f"  PID: {proc.pid}")
        print(f"  状态: {proc.status()}")
        print(f"  创建时间: {proc.create_time()}")
        print(f"  CPU使用率: {proc.cpu_percent()}%")
        print(f"  内存使用: {proc.memory_info().rss / 1024 / 1024:.1f} MB")
        print(f"  命令行: {' '.join(proc.cmdline())}")
    except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
        print(f"❌ 无法获取进程信息: {e}")

def main():
    """主函数"""
    parser = argparse.ArgumentParser(
        description="Kuavo机器人控制指令发送器",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
使用示例:
  python controller.py pause    # 暂停机械臂运动
  python controller.py resume   # 恢复机械臂运动
  python controller.py stop     # 停止机械臂运动
  python controller.py status   # 查看进程状态

控制指令说明:
  pause   - 暂停机械臂运动 (发送SIGUSR1信号)
  resume  - 恢复机械臂运动 (发送SIGUSR1信号)
  stop    - 停止机械臂运动 (发送SIGUSR2信号)
  status  - 显示当前运行的script.py进程状态
        """
    )
    
    parser.add_argument(
        "command",
        type=str,
        choices=["pause", "resume", "stop", "status"],
        help="控制指令"
    )
    
    parser.add_argument(
        "--pid",
        type=int,
        help="指定进程PID (如果不指定,将自动查找script.py进程)"
    )
    
    args = parser.parse_args()
    
    # 查找目标进程
    target_proc = None
    
    if args.pid:
        # 使用指定的PID
        try:
            target_proc = psutil.Process(args.pid)
            # 验证进程是否运行script.py
            cmdline = ' '.join(target_proc.cmdline())
            if 'script.py' not in cmdline:
                print(f"❌ 进程 {args.pid} 不是script.py进程")
                print(f"   命令行: {cmdline}")
                sys.exit(1)
        except psutil.NoSuchProcess:
            print(f"❌ 进程 {args.pid} 不存在")
            sys.exit(1)
        except psutil.AccessDenied:
            print(f"❌ 没有权限访问进程 {args.pid}")
            sys.exit(1)
    else:
        # 自动查找script.py进程
        print("🔍 正在查找运行中的script.py进程...")
        target_proc = find_example_process()
        
        if not target_proc:
            print("❌ 未找到运行中的script.py进程")
            print("💡 请确保script.py正在运行,或使用 --pid 参数指定进程ID")
            print("💡 预期的进程路径: kuavo_deploy/src/scripts/script.py")
            sys.exit(1)
        
        # 显示找到的进程信息
        cmdline = ' '.join(target_proc.cmdline())
        if 'kuavo_deploy/src/scripts/script.py' in cmdline:
            print(f"✅ 找到精确匹配的进程: {target_proc.pid}")
        else:
            print(f"⚠️  找到部分匹配的进程: {target_proc.pid}")
            print(f"   命令行: {cmdline}")
    
    # 执行命令
    if args.command == "status":
        show_process_status(target_proc)
    else:
        print(f"🎯 目标进程: {target_proc.pid}")
        success = send_signal_to_process(target_proc, args.command)
        if not success:
            sys.exit(1)

if __name__ == "__main__":
    main()