2015-7-28 11:44:34 [显示全部楼层]
6416浏览
查看: 6416|回复: 13

[intel程序猿笔记] 【intel程序猿笔记】英特尔® Edison编程环境间的数据分享

[复制链接]

1. intel独家授权转载【intel开发人员专区】文章。
2. 定期为创客小主po上最全最细最专业的intel项目教程或另类态度。
3. DF创客社区“创客召集令”带你玩转intel,更多惊喜,颠覆你想象。

周二福利帖又来了!首先,我们来揭晓上周【intel程序猿笔记】使用英特尔® Edison探索空气质量监测 的获奖情况。
上周有奖问答题目是:下列哪个选项不是该系统函数所涉及到的功能的 ?

【intel程序猿笔记】英特尔® Edison编程环境间的数据分享图5

正确答案是c.恭喜 @hnyzcj @Cain @vcbear @大连林海 @ 凌风清羽 @Qubot @丄帝De咗臂 7位小伙伴!
奖品将在系列活动结束后统一寄出,奖品实行累积制,各位,再接再厉!没有获奖的小伙伴,今天机会又来了喔!
现在,进入科学时间:我是原文链接喔~


在许多情况下,我们希望使用多种编程环境开发(比如)物联网应用。
  • 相比于 NodeJS 或 Arduino,我们更喜欢使用 OpenCV* 以 C++ 语言进行图像处理。 主要是因为以 C++ 编写的 OpenCV 能够提供许多示例。
  • 譬如,我们用 Arduino 编写的应用需要读取摄像镜头中的面部编号。 为此,我们需要使用 OpenCV 处理摄像头图像,然后将检测到的面部编号传给 Arduino。
  • 我们喜欢使用 NodeJS 创建基于开发板的 web 服务器,因为相比于采用其他语言,这种方法更加简单。

有许多这种类似的示例。 然而,我们希望在这些示例中找到一种简单的机制实现不同编程环境的数据共享。
Han, Matthias 写了一篇关于 Arduino 与 C++ 共享内存的好文章。 这种方法可行,因为C++ 和 Arduino 的运行方式类似于 Linux 中的进程。 但是,对于 C++ 的初学者来说,这种进程相对比较复杂。 而且,如果您希望将该进程扩展至 NodeJS,需要编写 C++ 代码,并编写原生绑定,以访问 NodeJS 中的变量。
还有一种方法是创建可从所有程序读取的通用可共享文件。 所有程序均可轮询文件中的数据变化。 在这种情况下,将会有线程或循环负责查找文件中的数据变化。 读取数据时,如有数据变化,您将读取和处理该数据。  这种想法看似简单,但在软件领域,轮询并不太受欢迎。

在本文中,我将探讨发布程序-订阅程序模式,这种模式可使运行于 Linux 的不同程序之间实现数据共享。 在软件开发过程中,这种模式的适应性非常强。 但在嵌入式领域,结合使用软硬件才能实现这种模式。

架构:
消息流可分为两部分。 一部分是变化通知,另一部分是数据读取。 在软件领域,这是一种已确定的老方法。 一些数据仓储应用(硬件)运用这种方法协同数据。 在这类硬件中,首先将小型通知文件拖放至目录。 该通知文件将包含数据信息和数据变化时间,并参考实际数据文件的位置,最后通常会变成大型文件。 精灵程序将读取该通知文件,并触发 appreciate 程序读取这一大型文件。 在此,我尝试引入相同的概念。 不过在这一示例中,我将触发中断事件,而非通知文件:

通知流:
【intel程序猿笔记】英特尔® Edison编程环境间的数据分享图1
消息流:
【intel程序猿笔记】英特尔® Edison编程环境间的数据分享图2
我们来了解一下通知流和信息流:
每种编程环境都有自己的输出数据容器和针脚来触发通知。 如果需要发送数据,该环境首先将内容推送至容器文件。 然后向通知针脚发送信号 HIGH。  我们来看看下面一种奇怪的线路图。 令人惊讶的是,这些针脚都被缩短了。 我们来举例说明这种情况。

线路:
【intel程序猿笔记】英特尔® Edison编程环境间的数据分享图3
我们来看看 Arduino 程序与 NodeJS 之间如何通信。

【intel程序猿笔记】英特尔® Edison编程环境间的数据分享图4

数据和通知流从 NodeJS 前往 Arduino。
假设您有一个 Arduino 程序,用来读取距离传感器的数据。 该距离传感器数据需发送至 NodeJS 做进一步处理。
在这种情况下,Arduino 需要一个通知针脚,即 GPIO 针脚。 根据上述线路图,用于 Arduino 的针脚为 #3。 如果出现任何新数据,Arduino 把该数据写入根目录(参考消息流示意图)中的通知容器文件,即 /arduino_notification_out.txt。
成功写入内容后,Arduino 向针脚 #3 发送信号 HIGH。 现在,请看上述线路图。 #3 缩短成了 #1。 这意味着,如果针脚 #3 变成 HIGH,该信号 HIGH 将发送至针脚 #1。
Arduino 代码:
  1. int notifier_pin         = 3;
  2. int js_subscriber_pin         = 6;
  3. FILE *fromarduino, *toarduino;
  4. int i = 0;
  5. int c;
  6. // the setup routine runs once when you press reset:
  7. void setup() {               
  8.   pinMode(notifier_pin, OUTPUT); //Notification pin     
  9.   pinMode(js_subscriber_pin, INPUT_PULLUP); //interrupt pin for reading message from JS   
  10.   attachInterrupt(js_subscriber_pin, subscriberEvent, RISING); //Subscribe to interrupt notifications from JavaScript
  11.   Serial.begin(9600);
  12. }
  13. //Read message from js notification file
  14. void subscriberEvent() {
  15.   
  16.    toarduino = fopen("/js_notification_out.txt","r");  //Opening message from JS
  17.    if (toarduino)
  18.    {
  19.     while ((c = getc(toarduino)) != EOF)
  20.     {
  21.       if(c != 10)//new line
  22.       {
  23.            Serial.print((char)c);
  24.       }
  25.     }
  26.     Serial.println("");
  27.     Serial.println("----------------");
  28.     fclose(toarduino);
  29.    }  
  30. }
  31. // the loop routine runs over and over again forever:
  32. void loop() {
  33.   if(i < 50)
  34.   {
  35.     i = i + 1;
  36.   }
  37.   else
  38.   {
  39.     i = 0;   
  40.   }
  41.   
  42.   publishData();
  43.   notifyWorld();  
  44.   delay(1000);               // wait for a second
  45. }
  46. void publishData()
  47. {
  48.   fromarduino = fopen ("/arduino_notification_out.txt", "w+");
  49.   fprintf(fromarduino, "[%d]", i);
  50.   fclose(fromarduino);  
  51. }
  52. //Nofity any body connected to this interrupt  (C++ program and NodeJS) program
  53. void notifyWorld()
  54. {
  55.     digitalWrite(notifier_pin, HIGH);
  56.     delay(200);
  57.     digitalWrite(notifier_pin, LOW);
  58. }
复制代码

在 NodeJS 程序中,我们为针脚 #1 附加一个中断事件。 如果针脚升高,说明 Arduino 通知容器文件中出现新数据。 现在,NodeJS 读取该文件并处理数据。 请参考 “数据和事件流从 Arduino 前往 NodeJS” 示意图,以更加清晰地了解这一过程。
NodeJS 代码:
  1. var mraa = require("mraa");
  2. var fs = require('fs');
  3. /**********Read notification from arduino*************/
  4. var subscriber_pin = new mraa.Gpio(1);
  5.     subscriber_pin.dir(mraa.DIR_IN);
  6.     subscriber_pin.isr(mraa.EDGE_RISING, subscriberEvent); //Subscribe to interrupt notifications from Arduino
  7.    
  8. function subscriberEvent() {
  9.     var contents = fs.readFileSync('/arduino_notification_out.txt').toString();
  10.     console.log("Message from Arduino:" + contents);        
  11. }
  12. /********** Trigger message sending interrupt every 20 seconds *************/
  13. var counter = 0;
  14. var notifier_pin = new mraa.Gpio(5);
  15. notifier_pin.dir(mraa.DIR_OUT);
  16. setInterval(function(){
  17.     counter++;
  18.         fs.writeFileSync("/js_notification_out.txt", "NodeJS: [" + counter + "]\n");
  19.         notifyWorld();
  20.         counter = 0;
  21. },20000);
  22. function notifyWorld()
  23. {
  24.     notifier_pin.write(1);
  25.     setTimeout(function(){
  26.         notifier_pin.write(0);
  27.     },200);
  28. }
复制代码
您可以通过类似的方法将数据从 NodeJS 发送至 Arduino。 请参考 “数据和事件流从 NodeJS 前往 Arduino” 示意图,以更加清晰地了解这一过程。
我们可将该方法扩展至任何支持中断事件的编程环境。

这种方法的优势:
运用这种方法,可以避免不必要的文件变化轮询,也无需开发 C++ 绑定以与 NodeJS 共享数据。 其编程也非常简单。
这种方法的劣势:
这种方法存在一种劣势, 即所有方向的数据流都需要一对 GPIO 针脚。 如果需要与多种编程环境交换数据,可能会耗尽 GPIO。  不过,我们可采用类似的架构达到相同的效果,而且只需消耗一对 GPIO。 但这之后您需要用带有 eventsource、事件数据等相应属性的单一 JSON 文件管理逻辑。 还需注意文件锁定情况。 尽管如此,这种方法依然可行。


                                                                        更多Edison信息请点击右边链接直接登录 >>>> 英特尔开发人员专区
广告,请广而告知——

每周二【intel 程序猿笔记】帖子下会设计一个与帖子内容相关的问答投票,你只要在留言区参与投票,选出正确的答案,社区小管家会挑选每周前10名回答正确的幸运互动者随机赠送小礼品,礼品可以实行累积制喔。也奏是说——只要你脑洞够大、热情够给力,你就可以横扫所有奖品实现大满贯喔!当然,对于大满贯获得者,我们还有神秘大礼包让你喜上加喜、锦上添花。奏这么任性,没办法!

现在,抢福利时间又到——
下面哪个选是消息流内容所包含的选项()?(答案单选)


单选投票, 共有 12 人参与投票
0.00% (0)
100.00% (12)
0.00% (0)
0.00% (0)
您所在的用户组没有投票权限

hnyzcj  版主

发表于 2015-7-28 12:30:02

我第一个投的。
回复

使用道具 举报

hnyzcj  版主

发表于 2015-7-28 12:30:16

不过我第一次没有参加,我是从第二次参加的。
回复

使用道具 举报

Juice  高级技师
 楼主|

发表于 2015-7-28 12:43:16

hnyzcj 发表于 2015-7-28 12:30
不过我第一次没有参加,我是从第二次参加的。

重在参与和娱乐~
回复

使用道具 举报

丄帝De咗臂  高级技匠

发表于 2015-7-28 12:54:23

我第一次好像也没参加:lol
回复

使用道具 举报

LeoSunshine  见习技师

发表于 2015-7-28 13:40:07

路过路过
回复

使用道具 举报

Juice  高级技师
 楼主|

发表于 2015-7-28 14:08:00


哈哈~~~欢迎~~~
回复

使用道具 举报

Qubot  初级技师

发表于 2015-7-28 19:01:14

错别字=,=问题里写的是“消息留”
回复

使用道具 举报

Juice  高级技师
 楼主|

发表于 2015-7-29 09:30:15

Qubot 发表于 2015-7-28 19:01
错别字=,=问题里写的是“消息留”

{:3_46:}感谢纠正!!!么么哒
回复

使用道具 举报

lianuo  初级技师

发表于 2015-9-1 13:22:37

好文章啊,好思路,我也现在就有这样的需求。
不过还有些疑问
1.多个程序见访问相同资源的冲突要如何避免,比如我在arduino里面初始化某个端口,可能不小心在js里面也初始化了。这种冲突是程序设计时候自己去避免吗?
2.c++和js的数据共享是不是可以达到更快的传输速度?不过看原文貌似非常麻烦。
回复

使用道具 举报

Juice  高级技师
 楼主|

发表于 2015-9-1 15:06:36

lianuo 发表于 2015-9-1 13:22
好文章啊,好思路,我也现在就有这样的需求。
不过还有些疑问
1.多个程序见访问相同资源的冲突要如何避免, ...

@孙毅 来来来~~版主 显神通的时候到了
回复

使用道具 举报

孙毅  初级技匠

发表于 2015-9-1 22:37:22

lianuo 发表于 2015-9-1 13:22
好文章啊,好思路,我也现在就有这样的需求。
不过还有些疑问
1.多个程序见访问相同资源的冲突要如何避免, ...

问题2, 文中不是说了另外两种间通信的方式吗?一种是Linux操作系统所支持的所有进程间通信,比如消息相应、队列等;还有就是利用一个公共文件,让两个程序轮询。如果还没有入手Edison的话,可以先找个玩玩看啊。其实说到底Edison上面就是跑了一个完完整整的Linux,只是没有桌面程序而已,所以一切能在Linux上干的事情,在Edison上都可以。
这个文章强调的是,在Edison上,跟PC相比,有先天的硬件接口优势,所以就多了一种进程间交互的方式——硬件中断。仅此而已啊,不要想太复杂。
问题1是什么来……,哦,对于多个进程访问同一个GPIO口的问题。每一个外设在Linux kernel里面都对应的module来操作,就是所谓的“驱动”。当多个进程同时访问同一个GPIO的时候,这个时候就看code是如何实现的了。有些资源允许共享,比如磁盘等,但有些资源就只能够独占比如显示器等资源。抱歉,没有去看过Edison上的driver的实现,但我的经验中,至少板载的那个LED灯是可以同时被多个进程控制的。
实践出真知,一切真理都在code中!
@Juice 感谢小秘书提醒,我总也记不住看下回复的帖子。。。吼吼
回复

使用道具 举报

Juice  高级技师
 楼主|

发表于 2015-9-2 13:27:47

孙毅 发表于 2015-9-1 22:37
问题2, 文中不是说了另外两种间通信的方式吗?一种是Linux操作系统所支持的所有进程间通信,比如消息相 ...

看在认真回复的份上,无良老板拖欠工资的事情就暂且不提了。
回复

使用道具 举报

孙毅  初级技匠

发表于 2015-9-2 16:02:33

Juice 发表于 2015-9-2 13:27
看在认真回复的份上,无良老板拖欠工资的事情就暂且不提了。

o( ̄ヘ ̄o#)
作良心老板——3D打印在向我招手~~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail