我正在改进用于远程控制望远镜的系统。 Raspberry Pi运行烧瓶,并为连接到望远镜的相机提供视频流。望远镜的聚焦器由一个由Arduino控制的步进电机驱动。服务器提供一个网站来显示视频流,并提供两个按钮来移动聚焦器。
单击任一按钮时,客户端将POST发送到RasPi,然后RasPi告诉Arduino移动聚焦器。但至关重要的是,我不希望页面在重新聚焦时刷新。因此,我使用jQuery和Ajax来抑制页面刷新。
相关代码段在这里:
Python / Flask代码:
@app.route('/stream/<wcam>', methods=['GET'])
def stream_get(wcam):
class FocuserForm(FlaskForm):
nsteps = IntegerField('# steps: ', default=1)
focuser_in = SubmitField('Focuser in')
focuser_out = SubmitField('Focuser out')
form = FocuserForm()
return render_template('stream.html', wcam=wcam, form=form)
@app.route('/stream/<wcam>', methods=['POST'])
def stream_post(wcam):
results = request.form
arduino_serial = SerialFocuser()
if results['caller'] == "focuser_in":
command = "MVD" + results['steps'] + "\n"
arduino_serial.send_command(command)
elif results['caller'] == "focuser_out":
command = "MVU" + results['steps'] + "\n"
arduino_serial.send_command(command)
return ''
网络(stream.html)
<html>
<head>
<title>Video Streaming</title>
<style>
...
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {});
</script>
</head>
<body>
<h1>Streaming camera {{ wcam }}</h1>
<br>
<img id="bg" src="{{ url_for('video_feed', wcam=wcam) }}", height="480" width="640">
<a href="{{ url_for('index') }}">Back</a>
<br>
<!--######################################################-->
<!--# Focuser handling -->
<!--######################################################-->
<br>
<form id="flaskform" method="POST">
<p>
{{ form.nsteps.label }} {{ form.nsteps() }}
{{ form.focuser_in() }}
{{ form.focuser_out() }}
</p>
</form>
<script>
// $(document).ready(function() { // Moved to header
var form = document.getElementById('flaskform');
function onSubmit(event) {
console.log('onSubmit function');
var objectID = event.explicitOriginalTarget.id;
var nsteps = form.nsteps.value;
var return_data = {caller: "", steps: nsteps};
if (objectID == "focuser_in") {
return_data.caller = objectID;
console.log("Focuser_in detected");
} else if (objectID == "focuser_out") {
return_data.caller = objectID;
console.log("Focuser_out detected");
} else if (objectID == "nsteps") {
console.log("nsteps detected");
event.preventDefault();
return;
} else {
console.log("No matches");
return;
}
console.log("About to run Ajax");
$.ajax({
url: "stream.html",
type: "post",
data: return_data,
success: function(response) {
console.log('It worked!');
},
error: function(xhr, status, text) {
console.log('An error occurred:', status,"; ", text);
},
timeout: 1000 // 1s
}); // Ajax
console.log("After running Ajax");
if (event) { event.preventDefault(); }
}
// prevent when a submit button is clicked
form.addEventListener('submit', onSubmit, false);
//<!--form.addEventListener('submit', onSubmit, false);-->
// prevent submit() calls by overwriting the method
form.submit = onSubmit;
//}); // Moved to header
</script>
</body>
</html>
问题如下:
如果我刷新客户端浏览器上的页面,然后单击一个按钮,则ajax会执行POST,但flask似乎无法接收到它。请求超时。
如果我现在重新启动服务器(我正在使用PyCharm开发它,因此我只单击重新运行)而没有刷新客户端中的页面,然后单击一个按钮,flask确实获得了POST,并且聚焦器正常工作像魅力一样。
如果再次刷新页面,则按钮将停止工作,直到我重置服务器为止。
为什么会这样?显然,该代码可以实现其主要目的,但是页面刷新在某种程度上破坏了某些事情。
答案 0 :(得分:1)
我曾经遇到过类似的问题,因为摄像机线程阻止了所有呼叫。当您重置服务器时,您的相机馈送是否仍在运行(在单击按钮之前)? 因为基本上您是在两次调用相机供稿-刷新页面时先使用get调用,然后再使用post调用。
为清楚起见,我建议您将提交的代码重构为其他函数:
@app.route('/stream/<wcam>', methods=['POST'])
def moveCommand:
if form.is_submitted():
# POST method
results = request.form
arduino_serial = SerialFocuser()
if results['caller'] == "focuser_in":
command = "MVD" + results['steps'] + "\n"
arduino_serial.send_command(command)
elif results['caller'] == "focuser_out":
command = "MVU" + results['steps'] + "\n"
arduino_serial.send_command(command)
因此,基本上,您只保留流式传输的get方法,并使用帖子进行移动。
答案 1 :(得分:0)
感谢@Peter van der Wal向我指出解决方案。
视频流媒体具有一个while True
循环,该循环不断从摄像机获取帧,从而锁定线程。
解决方案是在 on 上使用 threaded 选项启动应用程序:
之前:
app.run(host='0.0.0.0', debug=True)
现在:
app.run(host='0.0.0.0', debug=True, threaded=True)
这允许视频流线程自己继续运行,同时允许服务器处理其他命令。