我有一个以简单方式设置的arduino,它读取电位计并将输出写入串行连接。
void setup() {
// initialize serial communication
Serial.begin(9600);
}
void loop() {
// read the value of A0, divide by 4 and
// send it as a byte over the serial connection
Serial.write(analogRead(A0) / 4);
delay(20);
}
我想要一个 prolog 程序在后台监视此流。我希望它记录某些事件,但也希望我可以随时查询流。
我真的不知道从哪里开始设置。我如何实际读取流,然后如何拥有两个进程/线程(不知道如何调用它们)。其中一个进程监视流,第二个进程运行顶层,以便我可以查询动态数据库?
我想象的是这样的:
:-dynamic currentvalue/1.
startthread1 :-
loop.
loop :- read_serial(X),
check(X),
retractall(currentvalue(_)),
assertz(currentvalue(X)),
loop.
check(X):-
X>100,
get_time(Time),
write_file(Time,X).
check(_).
*我省略了write_file的def
我想我会查询:
?- thread_create(startthread1, Id, [alias(serial_mon)]).
然后我应该仍然可以在我想要的时候查询“currentvalue/1”的顶层?
这行得通吗?如何定义read_serial/1
。 ?另外,我将如何停止我命名为 serial_mon
的线程?
更新
我已将循环代码更改为以下内容:
void loop() {
// read the value of A0, divide by 4 and
// send it as a byte over the serial connection
Serial.print(analogRead(A0) / 4);
Serial.print('.');
delay(100);
}
如果我查看串行监视器,我现在会得到如下输出:
205.205.205.205。等等
我认为我应该能够使用 read/2 来阅读?
如果我的序言代码很简单:
go(File):-
open(File,read,Stream,[]),
read(Stream,X),
writeln(X),
close(Stream).
我查询:
?-go('/dev/ttyACM0').
我没有得到任何输出。我做错了什么?
最佳答案
你的基本想法是好的。但是,您需要考虑一些非常重要的点。
从流中读取
这是更简单的部分:关于“我如何实际读取流”,有几个选项,它们是您从单线程应用程序中已经知道的选项。最简洁的方法是使用 Ulrich Neumerkel 的library(pio)
,并简单地编写一个从流中透明读取的 DCG。另一个不错的选择是简单地使用 read/1
或 read/2
从流中读取 Prolog 术语。当然,后一个选项要求传感器实际发出可由这些谓词自动处理的 Prolog 术语,而前一个选项则更加灵活。
您还可以使用网络套接字并设置一个简单的基于网络的通信界面。例如,查看 JSON libraries以获得简单且便携的格式。总之,处理这个问题并不缺乏选择。
就我个人而言,我建议在此类交换中保留 Prolog 语法,因为您可以更方便地处理用 Prolog 编写的数据。例如,如果您将日志文件编写为一系列 Prolog事实,则您可以轻松查阅它们并对它们运行查询以生成报告。任何其他格式只会使事情变得更加复杂。
同步
第二个问题更加微妙,涉及线程之间的竞争条件。例如,在您显示的代码中,有一个关键时间点根本没有可用数据:
loop :- read_serial(X), check(X), retractall(currentvalue(_)), currentvalue/1 is not available at this point in time! assertz(currentvalue(X)), loop.
如果获取线程在未定义的关键时刻查询 currentvalue/1
,则可能意外失败。
对于 SWI-Prolog,请仔细阅读有关 thread synchronization 的章节。以避免此类问题。
例如,我们可以将其实现为:
loop :- read_serial(X), check(X), with_mutex(synch, (retractall(currentvalue(_)), assertz(currentvalue(X)))), loop.
在查询线程中,您可以使用with_mutex(synch, currentvalue(X))
来获取当前值。这可以确保在旧值已被删除但新值尚未断言的关键时间点不会发生这种情况。
请注意,顶层线程和任何其他线程都可以查询这些谓词。要生成更多线程,只需再次使用 thread_create/3
来实现不同的目标。
关于arduino - 查询流、串行输入 Swi prolog,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43844938/