feat: 增加云台功能控制
This commit is contained in:
67
app.py
67
app.py
@@ -11,7 +11,8 @@ logger = logging.getLogger(__name__)
|
||||
# Flask 应用初始化
|
||||
app = Flask(__name__)
|
||||
app.config['SECRET_KEY'] = 'h2Ms4pw9GzvwiFHyNPhH' # 请更换为安全的密钥
|
||||
socketio = SocketIO(app, cors_allowed_origins="*")
|
||||
# socketio = SocketIO(app, cors_allowed_origins="*")
|
||||
socketio = SocketIO(app)
|
||||
|
||||
# 全局变量存储摇杆数据
|
||||
joystick_data = {}
|
||||
@@ -38,7 +39,7 @@ def handle_joystick_data(data):
|
||||
|
||||
# print(f"force: {force} x: {x}, y: {y}")
|
||||
ptz.set_pitch_speed(int(y * 100))
|
||||
ptz.set_yaw_speed(int(x * 100))
|
||||
ptz.set_yaw_speed(int(x * -100))
|
||||
|
||||
# direction = data.get('direction', '')
|
||||
# logger.info(f"收到摇杆数据:{direction}")
|
||||
@@ -85,27 +86,49 @@ def handle_ping():
|
||||
"""处理心跳检测"""
|
||||
emit('pong')
|
||||
|
||||
@app.route('/get_joystick_data')
|
||||
def get_joystick_data():
|
||||
"""API 端点:获取当前摇杆数据"""
|
||||
from flask import jsonify
|
||||
return jsonify(joystick_data)
|
||||
@socketio.on('gimbal_center')
|
||||
def handle_gimbal_center():
|
||||
"""处理云台中心"""
|
||||
ptz.center()
|
||||
logger.info(f"云台回中")
|
||||
|
||||
@app.route('/control/<action>')
|
||||
def robot_control(action):
|
||||
"""
|
||||
示例控制端点
|
||||
可用于直接控制机器人动作
|
||||
"""
|
||||
from flask import jsonify
|
||||
valid_actions = ['forward', 'backward', 'left', 'right', 'stop']
|
||||
@socketio.on('gimbal_pip')
|
||||
def handle_gimbal_pip(data):
|
||||
"""处理云台PIP"""
|
||||
mode = int(data)
|
||||
if mode >= 0 and mode <= 3:
|
||||
ptz.set_pip_mode(mode)
|
||||
logger.info(f"云台PIP {mode}")
|
||||
|
||||
if action in valid_actions:
|
||||
logger.info(f"执行机器人控制:{action}")
|
||||
# 在这里添加实际的机器人控制逻辑
|
||||
return jsonify({'status': 'success', 'action': action})
|
||||
else:
|
||||
return jsonify({'status': 'error', 'message': '无效的动作'}), 400
|
||||
@socketio.on('gimbal_ir_mode')
|
||||
def handle_gimbal_ir_mode(data):
|
||||
"""处理云台IR"""
|
||||
mode = int(data)
|
||||
if mode >= 0 and mode <= 9:
|
||||
ptz.set_ir_mode(mode)
|
||||
logger.info(f"云台IR {mode}")
|
||||
|
||||
# @app.route('/get_joystick_data')
|
||||
# def get_joystick_data():
|
||||
# """API 端点:获取当前摇杆数据"""
|
||||
# from flask import jsonify
|
||||
# return jsonify(joystick_data)
|
||||
|
||||
# @app.route('/control/<action>')
|
||||
# def robot_control(action):
|
||||
# """
|
||||
# 示例控制端点
|
||||
# 可用于直接控制机器人动作
|
||||
# """
|
||||
# from flask import jsonify
|
||||
# valid_actions = ['forward', 'backward', 'left', 'right', 'stop']
|
||||
|
||||
# if action in valid_actions:
|
||||
# logger.info(f"执行机器人控制:{action}")
|
||||
# # 在这里添加实际的机器人控制逻辑
|
||||
# return jsonify({'status': 'success', 'action': action})
|
||||
# else:
|
||||
# return jsonify({'status': 'error', 'message': '无效的动作'}), 400
|
||||
|
||||
if __name__ == '__main__':
|
||||
socketio.run(app, host='0.0.0.0', port=5000, debug=True)
|
||||
socketio.run(app, host='10.21.31.250', port=5000, debug=True)
|
||||
24
gimbal.py
24
gimbal.py
@@ -185,20 +185,20 @@ if __name__ == "__main__":
|
||||
ptz.center()
|
||||
time.sleep(1)
|
||||
|
||||
ptz.set_pitch_speed(99)
|
||||
time.sleep(1)
|
||||
ptz.set_pitch_speed(0)
|
||||
time.sleep(1)
|
||||
# ptz.set_pitch_speed(99)
|
||||
# time.sleep(1)
|
||||
# ptz.set_pitch_speed(0)
|
||||
# time.sleep(1)
|
||||
|
||||
ptz.set_yaw_speed(-99)
|
||||
time.sleep(1)
|
||||
ptz.set_yaw_speed(0)
|
||||
time.sleep(1)
|
||||
# ptz.set_yaw_speed(-99)
|
||||
# time.sleep(1)
|
||||
# ptz.set_yaw_speed(0)
|
||||
# time.sleep(1)
|
||||
|
||||
ptz.set_roll_speed(-99)
|
||||
time.sleep(1)
|
||||
ptz.set_roll_speed(0)
|
||||
time.sleep(1)
|
||||
# ptz.set_roll_speed(-99)
|
||||
# time.sleep(1)
|
||||
# ptz.set_roll_speed(0)
|
||||
# time.sleep(1)
|
||||
|
||||
print("All commands sent.")
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -12,6 +13,7 @@
|
||||
background-color: #f0f0f0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
@@ -21,42 +23,50 @@
|
||||
margin: 0 auto;
|
||||
height: calc(100vh - 40px);
|
||||
}
|
||||
|
||||
.camera-frame {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.camera-frame.main-view {
|
||||
grid-column: 1 / span 2;
|
||||
grid-row: 1 / span 2;
|
||||
z-index: 10;
|
||||
border: 3px solid #4a90e2;
|
||||
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.camera-frame.main-view .camera-title {
|
||||
background-color: #2c5aa0;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.camera-frame.front-view {
|
||||
grid-column: 3 / span 1;
|
||||
grid-row: 1 / span 1;
|
||||
}
|
||||
|
||||
.camera-frame.back-view {
|
||||
grid-column: 3 / span 1;
|
||||
grid-row: 2 / span 1;
|
||||
}
|
||||
|
||||
.camera-frame.left-view {
|
||||
grid-column: 1 / span 1;
|
||||
grid-row: 3 / span 1;
|
||||
}
|
||||
|
||||
.camera-frame.right-view {
|
||||
grid-column: 2 / span 1;
|
||||
grid-row: 3 / span 1;
|
||||
}
|
||||
|
||||
.joystick-container {
|
||||
grid-column: 3 / span 1;
|
||||
grid-row: 3 / span 1;
|
||||
@@ -65,8 +75,9 @@
|
||||
align-items: center;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.camera-title {
|
||||
background-color: #4a90e2;
|
||||
color: white;
|
||||
@@ -76,14 +87,17 @@
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.camera-title:hover {
|
||||
background-color: #3a7bc8;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
@@ -93,20 +107,25 @@
|
||||
border-radius: 50%;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
virtual-joystick {
|
||||
--radius: 100px;
|
||||
}
|
||||
|
||||
virtual-joystick::part(joystick) {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border: 2px solid rgba(74, 144, 226, 0.5);
|
||||
}
|
||||
|
||||
virtual-joystick::part(joystick):before {
|
||||
background-color: rgba(74, 144, 226, 0.2);
|
||||
}
|
||||
|
||||
virtual-joystick::part(joystick):after {
|
||||
background-color: #4a90e2;
|
||||
border: 1px solid #2c5aa0;
|
||||
}
|
||||
|
||||
#connection-status {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
@@ -116,16 +135,42 @@
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.connected {
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
.disconnected {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="connection-status" class="disconnected">未连接</div>
|
||||
<div class="gimbal">
|
||||
<button id="gimbal_center">云台回中</button>
|
||||
<!-- <button id="gimbal_pip">画中画</button> -->
|
||||
<!-- 下拉选框 -->
|
||||
<select id="gimbal_pip">
|
||||
<option value="0">RGB主</option>
|
||||
<option value="1">仅RGB</option>
|
||||
<option value="2">仅IR</option>
|
||||
<option value="3">IR主</option>
|
||||
</select>
|
||||
<select id="ir_mode">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">7</option>
|
||||
<option value="8">8</option>
|
||||
<option value="9">9</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="camera-frame main-view" data-camera="cam_gimbal">
|
||||
@@ -169,31 +214,54 @@
|
||||
// 连接状态管理
|
||||
const connectionStatus = document.getElementById('connection-status');
|
||||
|
||||
socket.on('connect', function() {
|
||||
socket.on('connect', function () {
|
||||
console.log('WebSocket 连接已建立');
|
||||
connectionStatus.textContent = '已连接';
|
||||
connectionStatus.className = 'connected';
|
||||
});
|
||||
|
||||
socket.on('disconnect', function() {
|
||||
socket.on('disconnect', function () {
|
||||
console.log('WebSocket 连接已断开');
|
||||
connectionStatus.textContent = '已断开';
|
||||
connectionStatus.className = 'disconnected';
|
||||
});
|
||||
|
||||
socket.on('connection_response', function(data) {
|
||||
console.log('服务器响应:', data);
|
||||
// socket.on('connection_response', function (data) {
|
||||
// console.log('服务器响应:', data);
|
||||
// });
|
||||
|
||||
// socket.on('data_received', function (data) {
|
||||
// console.log('数据确认:', data);
|
||||
// });
|
||||
|
||||
const button_gimbal_center = document.getElementById('gimbal_center');
|
||||
// const button_gimbal_pip = document.getElementById('gimbal_pip');
|
||||
const select_gimbal_pip = document.getElementById('gimbal_pip');
|
||||
const select_ir_mode = document.getElementById('ir_mode');
|
||||
|
||||
button_gimbal_center.addEventListener('click', function () {
|
||||
socket.emit('gimbal_center');
|
||||
});
|
||||
|
||||
socket.on('data_received', function(data) {
|
||||
console.log('数据确认:', data);
|
||||
});
|
||||
// button_gimbal_pip.addEventListener('click', function () {
|
||||
// socket.emit('gimbal_pip');
|
||||
// });
|
||||
|
||||
select_gimbal_pip.addEventListener('change', function () {
|
||||
const selectedValue = select_gimbal_pip.value;
|
||||
socket.emit('gimbal_pip', selectedValue);
|
||||
})
|
||||
|
||||
select_ir_mode.addEventListener('change', function () {
|
||||
const selectedValue = select_ir_mode.value;
|
||||
socket.emit('gimbal_ir_mode', selectedValue);
|
||||
})
|
||||
|
||||
// 获取摇杆元素
|
||||
const joystick = document.querySelector('virtual-joystick');
|
||||
|
||||
// 监听摇杆移动事件
|
||||
joystick.addEventListener('joystickmove', function(e) {
|
||||
joystick.addEventListener('joystickmove', function (e) {
|
||||
const data = {
|
||||
x: parseFloat(joystick.dataset.x),
|
||||
y: parseFloat(joystick.dataset.y),
|
||||
@@ -209,7 +277,7 @@
|
||||
});
|
||||
|
||||
// 监听摇杆抬起事件
|
||||
joystick.addEventListener('joystickup', function(e) {
|
||||
joystick.addEventListener('joystickup', function (e) {
|
||||
// 发送停止信号
|
||||
const stopData = {
|
||||
x: 0,
|
||||
@@ -233,4 +301,5 @@
|
||||
}, 30000); // 每 30 秒发送一次心跳
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user