文档章节

利用Arduino+Nodejs做一个手势识别的交互系统【seeedstudio】

arbue
 arbue
发布于 2016/05/11 16:20
字数 1272
阅读 101
收藏 0

 接触Arduino也有些日子了,就想着做一个小玩意儿检验一下哈。不恰当的地方欢迎交流一下。。。

本次接到命令要做一个智能手势识别交互的系统产品。主要用到的硬件模块有SeeedStudio也就是矽递科技公司开发一款Arduino Uno开发板图1、一款PAJ传感器图2。软件方面就主要是Arduino IDE和Nodejs架设的Web服务器。目标产品的预想是通过手势动作控制Web界面的滚动与切换。

图1:

图2:

介绍完所需材料模块,那就开始进行积木搭建咯。。

因为模块比较少,就省去了扩展板

下面是Arduino IDE程序:

代码在这里:

//调用两个库函数
#include <Wire.h>
#include "paj7620.h"

#define GES_REACTION_TIME    800
#define GES_QUIT_TIME     1000



//定义一个LED输出引脚,用来进行握手测试
const int ledPin = 13;

//定义一个初始状态字符
String ledStatus = "off";

// 用来从Nodejs客户端获取信息
String inputString = "";

boolean stringComplete = false;

/**
 *
 * arduino board setup
 *
 */

void setup()
{

  
  // 设置波特率
  Serial.begin(115200);
//定义LED引脚
  pinMode(ledPin, OUTPUT);

  
//PAJ
  uint8_t error = 0;

  Serial.println("\nPAJ7620U2 TEST DEMO: Recognize 15 gestures.");

  error = paj7620Init();      // initialize Paj7620 registers
  if (error) 
  {
    Serial.print("INIT ERROR,CODE:");
    Serial.println(error);
  }
  else
  {
    Serial.println("INIT OK");
  }
  Serial.println("Please input your gestures:");
}

/**
 *
 * Default arduino loop function
 * it runs over and over again
 *
 */

void loop()
{
  uint8_t data = 0, data1 = 0, error; 

  error = paj7620ReadReg(0x43, 1, &data);       // Read Bank_0_Reg_0x43/0x44 for gesture result.
  if (!error) 
  {
    switch (data)                   
    {
      case GES_RIGHT_FLAG:
        delay(GES_REACTION_TIME);
        paj7620ReadReg(0x43, 1, &data);
        if(data == GES_LEFT_FLAG) 
        {
          Serial.println("<section class=\"Right-Left\">");
          Serial.println("</section>");
        }
        else if(data == GES_FORWARD_FLAG) 
        {
          Serial.println("<section class=\"Forward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else if(data == GES_BACKWARD_FLAG) 
        {
          Serial.println("<section class=\"Backward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else
        {
          Serial.println("<section class=\"Right\">");
          Serial.println("</section>");
        }          
        break;
      case GES_LEFT_FLAG:
        delay(GES_REACTION_TIME);
        paj7620ReadReg(0x43, 1, &data);
        if(data == GES_RIGHT_FLAG) 
        {
          Serial.println("<section class=\"Left-Right\">");
          Serial.println("</section>");
        }
        else if(data == GES_FORWARD_FLAG) 
        {
          Serial.println("<section class=\"Forward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else if(data == GES_BACKWARD_FLAG) 
        {
          Serial.println("<section class=\"Backward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else
        {
          Serial.println("<section class=\"Left\">");
          Serial.println("</section>");
        }          
        break;
        break;
      case GES_UP_FLAG:
        delay(GES_REACTION_TIME);
        paj7620ReadReg(0x43, 1, &data);
        if(data == GES_DOWN_FLAG) 
        {
          Serial.println("<section class=\"Up-Down\">");
          Serial.println("</section>");
        }
        else if(data == GES_FORWARD_FLAG) 
        {
          Serial.println("<section class=\"Forward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else if(data == GES_BACKWARD_FLAG) 
        {
          Serial.println("<section class=\"Backward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else
        {
          Serial.println("<section class=\"Up\">");
          Serial.println("</section>");
        }
        break;
      case GES_DOWN_FLAG:
        delay(GES_REACTION_TIME);
        paj7620ReadReg(0x43, 1, &data);
        if(data == GES_UP_FLAG) 
        {
          Serial.println("<section class=\"Down-Up\">");
          Serial.println("</section>");
        }
        else if(data == GES_FORWARD_FLAG) 
        {
          Serial.println("<section class=\"Forward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else if(data == GES_BACKWARD_FLAG) 
        {
          Serial.println("<section class=\"Backward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else
        {
          Serial.println("<section class=\"Down\">");
          Serial.println("</section>");
        }
        break;
      case GES_FORWARD_FLAG:
        delay(GES_REACTION_TIME);
        paj7620ReadReg(0x43, 1, &data);
        if(data == GES_BACKWARD_FLAG) 
        {
          Serial.println("<section class=\"Forward-Backward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else
        {
          Serial.println("<section class=\"Forward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        break;
      case GES_BACKWARD_FLAG:     
        delay(GES_REACTION_TIME);
        paj7620ReadReg(0x43, 1, &data);
        if(data == GES_FORWARD_FLAG) 
        {
          Serial.println("<section class=\"Backward-Forward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        else
        {
          Serial.println("<section class=\"Backward\">");
          Serial.println("</section>");
          delay(GES_QUIT_TIME);
        }
        break;
      case GES_CLOCKWISE_FLAG:
        Serial.println("<section class=\"Clockwise\">");
          Serial.println("</section>");
        break;
      case GES_COUNT_CLOCKWISE_FLAG:
        Serial.println("<section class=\"anti-clockwise\">");
          Serial.println("</section>");
        break;  
      default:
        paj7620ReadReg(0x44, 1, &data1);
        if (data1 == GES_WAVE_FLAG) 
        {
          Serial.println("<section class=\"wave\">");
          Serial.println("</section>");
        }
        break;
    }
  }
  delay(100);
  
  updateLedStatus();
}





void updateLedStatus() {
 //检测LED状态是否被完整接收
  if (stringComplete) {
        if (inputString == "on\r") {
      ledStatus = "on";
    }
    if (inputString == "off\r") {
      ledStatus = "off";
    }
    //把LED状态发送到服务器
    Serial.println(ledStatus);
        inputString = "";
    stringComplete = false;
  }
  // 通过当时状态判断行为动作状态
  digitalWrite(ledPin, ledStatus == "on" ? HIGH : LOW);
}


 void serialEvent() {
  while (Serial.available()) {
    // 接收新字节
    char inChar = (char)Serial.read();
    
    inputString += inChar;
    // 如果接收到换行符则中断
    if (inChar == '\r') {
      stringComplete = true;
    }
  }
}

接着是Web服务器的搭建,使用的是Nodejs。

其中server.js文件:

var app = require('http').createServer(handler),
  io = require('socket.io').listen(app),
  fs = require('fs'),
  url = require('url'),
  SerialPort = require('serialport').SerialPort,
  // initialize serialport using the COM5 serial port
  // remember to change this string if your arduino is using a different serial port
  sp = new SerialPort('COM5', {
    baudRate: 115200
  }),
  // this var will contain the message string dispatched by arduino
  arduinoMessage = '',
  /**
   * helper function to load any app file required by client.html
   * @param  { String } pathname: path of the file requested to the nodejs server
   * @param  { Object } res: http://nodejs.org/api/http.html#http_class_http_serverresponse
   */
  readFile = function(pathname, res) {
    // an empty path returns client.html
    if (pathname === '/')
      pathname = 'client.html';

    fs.readFile('htmlarduino/client/' + pathname, function(err, data) {
      if (err) {
        console.log(err);
        res.writeHead(500);
        return res.end('Error loading client.html');
      }
      res.writeHead(200);
      res.end(data);
    });
  },
  /**
   *
   * This function is used as proxy to print the arduino messages into the nodejs console and on the page
   * @param  { Buffer } buffer: buffer data sent via serialport
   * @param  { Object } socket: it's the socket.io instance managing the connections with the client.html page
   *
   */
  sendMessage = function(buffer, socket) {
    // concatenating the string buffers sent via usb port
    arduinoMessage += buffer.toString();

    // detecting the end of the string
    if (arduinoMessage.indexOf('\r') >= 0) {
      // log the message into the terminal
      // console.log(arduinoMessage);
      // send the message to the client
      socket.volatile.emit('notification', arduinoMessage);
      // reset the output string to an empty value
      arduinoMessage = '';
    }
  };

// creating a new websocket
io.sockets.on('connection', function(socket) {
  // listen all the serial port messages sent from arduino and passing them to the proxy function sendMessage
  sp.on('data', function(data) {
    sendMessage(data, socket);
  });
  // listen all the websocket "lightStatus" messages coming from the client.html page
  socket.on('lightStatus', function(lightStatus) {
    sp.write(lightStatus + '\r', function() {
      // log the light status into the terminal
      console.log('the light should be: ' + lightStatus);
    });
  });
});

// just some debug listeners
sp.on('close', function(err) {
  console.log('Port closed!');
});

sp.on('error', function(err) {
  console.error('error', err);
});

sp.on('open', function() {
  console.log('Port opened!');
});

// L3T'S R0CK!!!
// creating the server ( localhost:8000 )
app.listen(8000);
// server handler
function handler(req, res) {
  readFile(url.parse(req.url).pathname, res);
}

其中还有用到Nodejs的socket.io模块进行前后台数据调用。serialport模块进行跟Arduino串口匹配通信。通过npm命令就可以安装

Web页面就比较简单了:

<html>
<head>
    <title>手势识别控制Web</title>
    <style>
    center {
        font-size: 100px;
        font-family:arial;
		background:rgba(20,20,20,0.5);
		width:500px;
		margin:auto;
    }
	
	section{background:#333;margin:10px;width:100px;height:100px;}
    </style>
</head>
<body>
    <button>
        Turn the light
        <span>on</span>
    </button>
	
    <script src="socket.io/socket.io.js"></script>
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
    <script src="js/app.js"></script>
</body>
</html>

代码还有些粗糙,有待整理,有很多都是Arduino现成的示例库,只不过进行了适当的修改。这也就是Arduino流行的一个原因吧。

© 著作权归作者所有

共有 人打赏支持
arbue
粉丝 0
博文 1
码字总数 1272
作品 0
郑州
解读手势识别,或许不是VR交互的万能工具

摆脱外设的VR体验需要手势识别作为基础,那么手势识别技术发展情况是如何呢? 现在主流的VR硬件设备,主要的输入输出设备还是类似传统游戏手柄的外设:Oculus在Touch没发布之前,一直用的是微...

行者武松
03/01
0
0
EZ430 Chronos 开发设想 :广义手势语言

EZ430 Chronos 开发设想 :广义手势语言 终于收到了代购的开发套件,这几天都在思考究竟用它来开发一款什么样的有趣应用呢? 终于在昨天确定了开发设想:手势语言,充分利用套件的3轴加速度感...

FreeBlues
2012/07/01
0
0
对话童欣:VR/AR里的手势交互到底难在哪儿?

     编者按:VR(Virtual Reality)技术的应用给人们搭建了一个精彩的虚拟世界,进阶版的AR(Augument Reality)技术将真实世界信息和虚拟世界信息“无缝”集成,微软早前发布的HoloLen...

微软亚洲研究院
2017/12/01
0
0
专访微软亚洲研究院童欣:VR/AR 里的手势交互到底难在哪儿?

今天,电影已成为我们日常生活娱乐的一部分。从无声到有声,从黑白到彩色,从朴实的实景到炫目的特效,无疑,今天的电影画面越来越好看,这背后自然离不开技术的发展。 11 月 16 日,ICEVE 2...

田苗
2017/11/29
0
0
The Core iOS CookBook 第一章节学习笔记 - 手势和触控

手势和触控基础知识 触摸控制 是 iOS 系统交互的核心方式。 触控 Cocoa Touch 以尽可能简单地方式实现了直接的操控。它会把触控事件发送给你正在进行交互的视图。 每一次触控都会转达很多的信...

Herbert77
2015/09/02
7
0

没有更多内容

加载失败,请刷新页面

加载更多

区块链教程以太坊源码分析core-state源码分析(一)

兄弟连区块链教程以太坊源码分析core-state源码分析,core/state 包主要为以太坊的state trie提供了一层缓存层(cache) database主要提供了trie树的抽象,提供trie树的缓存和合约代码长度的缓...

兄弟连区块链入门教程
26分钟前
0
0
使用putty上传文件

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: 使用putty上传文件 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::linux 用户名 set linux_us......

shzwork
27分钟前
1
0
摹客首家发布Adobe XD插件

10月19日,摹客iDoc发布了支持Adobe XD的插件,这是中国国内首款基于Adobe XD 正式API的插件。 设计师在Adobe XD 中安装并使用此插件,可以将设计稿上传到摹客iDoc,并使用iDoc的全部协作设计...

mo311
28分钟前
0
0
MetInfo最新网站漏洞如何修复以及网站安全防护

metinfo漏洞于2018年10月20号被爆出存在sql注入漏洞,可以直接拿到网站管理员的权限,网站漏洞影响范围较广,包括目前最新的metinfo版本都会受到该漏洞的攻击,该metinfo漏洞产生的主要原因是...

网站安全
28分钟前
1
0
git统计代码行数

$ npm install -g cloc$ cloc . 2193 text files. 1533 unique files. 760 files ignored.github.com/AlDanial/cloc v 1.78 ......

moon888
28分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部