文档章节

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

arbue
 arbue
发布于 2016/05/11 16:20
字数 1272
阅读 1.6K
收藏 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没发布之前,一直用的是微...

行者武松
2018/03/01
0
0
对话童欣:VR/AR里的手势交互到底难在哪儿?

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

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

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

田苗
2017/11/29
0
0
手势识别

手势识别是计算机科学和语言技术中的一个主题,其目标是通过数学算法解释人类手势。手势可以源自任何身体运动或状态,但通常源自面部或手部。该领域的当前焦点包括来自面部的情绪识别和手势识...

osc_rlzm0f6h
2019/05/18
5
0
如何在虚拟世界里灵活运用你的双手?手势交互方案、算法和场景全解析

早在语言出现之前,人类就习惯使用肢体和手势,这种近乎本能的沟通方式,来互相交流。 在机器被发明之后,手势因具备键盘、鼠标、触屏等交互方式所无法替代的天然优势,仍然有诸多应用场景。...

张兆辉
2019/09/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

十年饮冰,难凉热血.高考失利的同学们应该怎么学习

今天练车的时候跟几个朋友聊了会天,朋友考的学校都比较好,一个山大,一个山师大,一个上师大,让我个人夹杂在他们当中作为一个高考失败者实属自卑,虽然一直在尽力准备专升本,但是难免现阶...

osc_n3mzii7x
14分钟前
12
0
阿里巴巴矢量图标库的使用

在参考小米官网写页面你时,会发现小米中有很多的矢量图标,小米的图标或许是自己的,但是我们写页面时要用到矢量图标时怎么办,可以使用阿里提供的图标库 阿里矢量图标库网址:https://www...

osc_r9wwwi0j
15分钟前
13
0
JS数据结构与算法 - 排序(冒泡、选择、插入、归并、快排)

🌸本文主要内容: 各排序算法时间复杂度 js默认sort算法于各浏览器中的实现 1.冒泡排序 2.选择排序 3.插入排序 4.归并排序(含小动画) 5.快速排序(含小动画) 时间复杂度 O(1) < O(logn)...

osc_ccy4urvn
16分钟前
12
0
使用before和after属性选择器

最近仿造了小米官网写了一遍,可以说是完全把官网给写完了。 官网中有一个log切换的动态效果,有点把我卡住了找方法找了许久,然后用一个简单的方法实现了: 先了解一下before和after两个属性...

osc_k1o54uky
17分钟前
18
0
健身以及未来科技如何解绑教育,医疗,养老依赖于地段(房产)

疫情后,谁来颠覆套路满满的健身房?硬核解析异军突起的家庭健身——鲜榨财经_哔哩哔 目前的keep,或者 其他在线教育 存在的痛点 就是 可交互性 不强。 未来 通过 5G,各种完善的传感器,以及...

osc_bvzab11e
19分钟前
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部