如何使用Raspberry Pi测量室内温度和湿度并绘制曲线

硬件准备

需要以下硬件:

  1. 可以工作的树莓派一个
  2. 面包板公对母杜邦线
  3. 10K 电位器一个
  4. DHT11温度和湿度传感器一个或DHT22

传感器电路及原理

DHT11传感器外观

参数

  1. 湿度测量范围:20%~90%RH(0-50℃温度补偿);
  2. 温度测量范围:0~+50℃;
  3. 湿度测量精度:±5.0%RH
  4. 温度测量精度:±2.0℃
  5. 响应时间:<5s;

电路图

DHT11一共4根引脚,左边第一根接电源5V (Pin 1),第二根为数据接口,接 Pin 7,第三根不接,第四根接地;在Pin 1和Pin7 之间还需要并联10K的电阻,以保持读数稳定。

安装好的样子:

读取温度和湿度的代码

数据读取流图:

#include <wiringPi.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <stdint.h>  
#define MAX_TIME 85  
#define DHT11PIN 7  

int dht11_val[5]={0,0,0,0,0};  
int errors=0;

  
void dht11_read_val()  
{  
  uint8_t lststate=HIGH;  
  uint8_t counter=0;  
  uint8_t j=0,i;  
  float farenheit;  
  for(i=0;i<5;i++)  
     dht11_val[i]=0;  
  pinMode(DHT11PIN,OUTPUT);  
  digitalWrite(DHT11PIN,LOW);  
  delay(18);  
  digitalWrite(DHT11PIN,HIGH);  
  delayMicroseconds(40);  
  pinMode(DHT11PIN,INPUT);  
  for(i=0;i<MAX_TIME;i++)  
  {  
    counter=0;  
    while(digitalRead(DHT11PIN)==lststate){  
      counter++;  
      delayMicroseconds(1);  
      if(counter==255)  
        break;  
    }  
    lststate=digitalRead(DHT11PIN);  
    if(counter==255)  
       break;  
    // top 3 transistions are ignored  
    if((i>=4)&&(i%2==0)){  
      dht11_val[j/8]<<=1;  
      if(counter>16)  
        dht11_val[j/8]|=1;  
      j++;  
    }  
  }  
  // verify cheksum and print the verified data  
  if((j>=40)&&(dht11_val[4]==((dht11_val[0]+dht11_val[1]+dht11_val[2]+dht11_val[3])& 0xFF)))  
  {  
    //farenheit=dht11_val[2]*9./5.+32;  
    printf("%d.%d\t%d.%d\n", dht11_val[0],dht11_val[1],dht11_val[2],dht11_val[3]);    
    exit(1);
  }  
  else { 
    errors = errors + 1;
    if (errors > 5) {
      printf("0.0\t0.0");
      exit(2);
    }
  }
}  
  
int main(void)  
{  
  if(wiringPiSetup()==-1)  
    exit(1);  
  while(1)  
  {  
     dht11_read_val();  
     delay(3000);  
  }  
  return 0;  
}  

执行gcc sensor.c -o sensor -lwiringPi ,运行sensor后输出:

[Read More]

如何使用Raspberry Pi控制步进电机旋转高清摄像头并拍照

硬件准备

需要以下硬件:

  1. 可以工作的树莓派一个
  2. 母对母1P杜邦线6根
  3. DC 5V4相28YBJ-48步进电机一个
  4. UL2003芯片步进电机驱动板一块

安装

按下图将步进电机接到驱动板上,也就是白色的接口

步进电机电源

步进电机需要5V电压驱动,而树莓派的GPIO接口中已有5V输出,将图中的Pin 2(最右上角那个)5V,接到驱动板的5V正极,Pin 6接到5V负级,电源部分则搞定。

步进电机驱动线路

驱动板上有IN1, IN2, IN3, IN4四个接口,根据资料得知这四个接口依次设置为低电平就可以驱动,我们分别用杜邦线将GPIO 17(Pin 11),GPIO 18(Pin 12), GPIO 21(Pin 13), GPIO 22(Pin 15)和IN1,IN2,IN3,IN4一一相连。 注意不同的GPIO驱动程序对端口的编号不一定一样(至少有三种叫法:Board,Broadcom,GPIO)

驱动原理:(每次将四个GPIO端口按下表依次设置好电平后,可以sleep几十毫秒来控制转速)

序列GPIO 17GPIO 18GPIO 21GPIO 22
0LOWHIGHHIGHHIGH
1HIGHLOWHIGHHIGH
2HIGHHIGHLOWHIGH
3HIGHHIGHHIGHLOW
4LOWHIGHHIGHHIGH

安装摄像头

本来是希望用3D打印机来制作齿轮和支架来完成这部分工作的,但因为打印机还没到货,所以先用乐高积木来做了, 刚好乐高积木可以插在步进电机中轴上,而且很牢靠,还不用密封带了。

[Read More]

如何在Raspberry Pi上用LED闪烁提示网站首页新访客

本方法只适合小网站,主要是好玩。Raspberry Pi不是很合适需要实时控制的系统(比如,飞行器,遥控小车),因为Linux内核要多任务,应用程序的优先级不能保持最高,会带来延时,但做些实时性要求不高的系统还是可以的。

硬件安装

需要以下硬件:

  1. 可以工作的树莓派一个
  2. 1P杜邦线2条
  3. 面包板一个
  4. 面包板跳线单排针 两根
  5. 发光二极管一个
  6. 300欧姆的电阻一个

GPIO接口

用杜邦线将上图的3.3V输出和GPIO 23引出(板子正面朝上,GPIO引脚在左上角),将电阻和LED串联起来(电阻防止LED电流过大烧掉),注意二极管的两根脚不一样长,长脚的接正级,这样GPIO 23如果输出高电平,二极管就不发光了,输出低电平就亮啦!

都接好了后的样子如下:

GPIO接口编程

WiringPi

An implementation of most of the Arduino Wiring functions for the Raspberry Pi。 代码地址在: https://github.com/wiringPi

安装:

git clone https://github.com/WiringPi/WiringPi
cd WiringPi/wiringPi
sudo make install	

让二极管闪一下的示例代码:

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char* argv[])
{
	int pinNumber = 4;
	if (-1 == wiringPiSetup()) {
		printf("failed to setup wiringPi");
		return 1;
	}	
	pinMode(pinNumber, OUTPUT);
	digitalWrite(pinNumber, 1);
	delay(200);
	digitalWrite(pinNumber, 0);
	delay(200);
	return 0;	
}

WiringPi也有Python, Perl, PHP, Ruby的接口包装,按这里,怎么没有Go的呢。。。

RPi.GPIO

这是GPIO的Python库,地址在:https://pypi.python.org/pypi/RPi.GPIO 这里建议用python2,原因是web.py还不支持python 3 …

[Read More]

在Raspberry Pi上安装ArchLinux

介绍

之前买的Raspberry Pi因为要跑这个网站,不能经常拔下来玩别的,所以又买了一个,这次安装的是Arch Linux。这个发行版安装好后非常基础,占用的空间也只有600M不到,比较合适已有Linux基础的同学玩。初学者可以玩官方推荐的Raspbian

Arch Linux特点:

  1. 启动快,上电后只要3s完成启动
  2. 安装完没有图形界面,干净
  3. 面向开发者的系统
  4. 包管理系统pacman很好用,一个命令就可以完成各种操作
  5. ArchLinux缺省账号和密码是root/root,弄好了后要记得修改root密码
  6. 从中国用下载包很快,比Raspbian的源快多了

增加sudo用户

   useradd hugo
   passwd hugo
   mkdir /home/hugo
   chown hugo:hugo /home/hugo   
   pacman -S sudo
   visudo   
   

执行visudo把新用户设置成管理员(增加sudo权限),最后面增加下面一行:

    hugo ALL=(ALL) NOPASSWD: ALL

USB盘

插上USB盘后,ArchLinux并不会自动mount,手动mount的过程如下: 插上USB前后执行两次 lsblk -o name,kname,uuid,那么输出上多出的那行就是该USB的设备名,或UUID,找到该行后就可以执行mount命令了(注意sda这个符号不同机器可能不一样)

    [root@raspberrypi2 ~]# lsblk -o name,kname,uuid   
    NAME        KNAME     UUID
    sda         sda       001B-9622
    mmcblk0     mmcblk0   
    ├─mmcblk0p1 mmcblk0p1 44C8-CEF1
    └─mmcblk0p2 mmcblk0p2 fcee8534-f5f0-42ee-83ac-f943f878ee67
    
    mkdir /mnt/usb
    mount /dev/sda /mnt/usb 
    mount -U 001B-9622 /mnt/usb

格式化整个USB盘可以用mkfs.ext4 /dev/sda 然后在/etc/fstab里增加一行,以后重启就会自动mount了:

[Read More]

如何封杀尝试Raspberry Pi SSH密码的来源IP

Raspberry Pi整天开着,如果用缺省SSH端口对外开放,就会经常遇到扫描SSH密码的肉鸡。虽然密码不是很简单,但还是感觉很不安全的。

系统的ssh登录日志文件在:/var/log/auth.log,登录失败时会记录以下格式的日志:

Mar  7 10:31:51 raspberrypi sshd[24510]: Failed password for root from 221.8.19.129 port 4066 ssh2
Mar  7 10:31:55 raspberrypi sshd[24514]: Failed password for root from 221.8.19.129 port 4079 ssh2
Mar  7 10:31:56 raspberrypi sshd[24518]: Failed password for sshd from 221.8.19.129 port 4080 ssh2
Mar  7 10:32:26 raspberrypi sshd[24522]: Failed password for sshd from 221.8.19.129 port 4149 ssh2

用最简单的Shell脚本来解决这个问题:

guard.sh

#!/bin/bash

last_ip=""
tail -f /var/log/auth | while read LINE; do
{
    if [[ "${LINE}" =~ "Failed" ]]; then            
        ip="$(echo ${LINE} | awk '{print $(NF-3)}')"
        if [[ "$last_ip" == "$ip" ]]; then
             echo "block $ip"
             #curl -s --data-ascii "uuid=<my iphone's uuid>" --data "body=${LINE}" http://raspberrypi/pushme                 
             iptables -A INPUT -s "$ip" -j DROP
        fi
        last_ip=$ip
        echo $LINE
    fi
}
done

用root用户执行以下命令,也可以放到启动脚本里:/etc/rc.local

[Read More]

Raspberry Pi做BT下载机+高清播放器

介绍

首先高清播放器功能只是Raspberry Pi的一个小功能,如果你只需要高清播放功能又不想折腾,那还是买个山寨的的更简单。。。

Raspberry Pi的图形处理器规格:Broadcom VideoCore IV, OpenGL ES 2.0, 1080p 30 h.264/MPEG-4 AVC 高清解码器,内存和CPU共享(可设置成256M),性能还是很强劲的。HDMI支持640x350和1920×1200(1080P)的分辨率。安装了XBMC,基本上可以实现包括Airplay在内的Apple TV上的大部分功能,但价格只有其一半不到,可以播放下载的视频或观看在线视频,如一搜,优酷,搜狐视频,奇艺等。

外设

除了Pi单片机外,你还需要以下外设附件:

  1. 5V-1A左右的电源,可以用iPhone或iPad的充电电源,或手机的充电器,电流最少要800毫安
  2. micro USB线一根,和Kindle以及大多数android手机充电USB线一样
  3. HDMI线一根,接电视机
  4. SD卡一张,最少2G

Raspbmc

Raspbmc 是专为在Raspberry Pi上运行XBMC的定制Linux。最小化的安装,减少了不必要的软件和资源占用,简化了安装和配置,没有Linux知识也可以上手。这个版本的维护者是一个19岁的小朋友Sam Nazarko。有时间折腾的同学可以自己编译XMBC安装。

特点:

  1. 免费,开源
  2. 支持多语言
  3. 支持1080P回放
  4. 支持直接播放NFS,SMB,FTP,HTTP或USB硬盘的有视频文件,支持大多数格式
  5. 支持AirPlay或AirTune功能,可以把iPhone/iPad上的视频或音乐通过Pi投放到电视上,这点和Apple TV功能一样
  6. 支持GPIO
  7. 基于Debian,可以从Debian的软件源安装其它软件
  8. 支持1080P DTS软解,这个不少播放器是不支持的,需要额外License
  9. 内置了以下服务:
    1. Samba
    2. TVHeadend Server
    3. FTP Server
    4. SSH Server

安装

  1. Windows下载安装程序,运行即可。

    image

  2. Linux/Mac:

    curl -O http://svn.stmlabs.com/svn/raspbmc/testing/installers/python/install.py
    chmod +x install.py
    sudo python install.py
    

    image

  3. 或直接下载安装包安装

下载

你可以在Pi上外接一个USB移动硬盘,但要注意硬盘要有自己电源,也可以mount网络上的硬盘分区。然后运行transmission软件下载视频。

Transmission

  1. 安装

    sudo apt-get install transmission-daemon
    sudo /etc/init.d/transmission-daemon stop
    sudo nano /etc/transmission-daemon/settings.json
    
  2. 配置

    [Read More]

Java并发包中的同步队列SynchronousQueue实现原理

介绍

Java 6的并发编程包中的SynchronousQueue是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移除操作take,反过来也一样。

不像ArrayBlockingQueue或LinkedListBlockingQueue,SynchronousQueue内部并没有数据缓存空间,你不能调用peek()方法来看队列中是否有数据元素,因为数据元素只有当你试着取走的时候才可能存在,不取走而只想偷窥一下是不行的,当然遍历这个队列的操作也是不允许的。队列头元素是第一个排队要插入数据的线程,而不是要交换的数据。数据是在配对的生产者和消费者线程之间直接传递的,并不会将数据缓冲数据到队列中。可以这样来理解:生产者和消费者互相等待对方,握手,然后一起离开。

SynchronousQueue的一个使用场景是在线程池里。Executors.newCachedThreadPool()就使用了SynchronousQueue,这个线程池根据需要(新任务到来时)创建新的线程,如果有空闲线程则会重复使用,线程空闲了60秒后会被回收。

实现原理

同步队列的实现方法有许多:

阻塞算法实现

阻塞算法实现通常在内部采用一个锁来保证多个线程中的put()和take()方法是串行执行的。采用锁的开销是比较大的,还会存在一种情况是线程A持有线程B需要的锁,B必须一直等待A释放锁,即使A可能一段时间内因为B的优先级比较高而得不到时间片运行。所以在高性能的应用中我们常常希望规避锁的使用。

public class NativeSynchronousQueue<E> {
    boolean putting = false;
    E item = null;

    public synchronized E take() throws InterruptedException {
        while (item == null)
            wait();
        E e = item;
        item = null;
        notifyAll();
        return e;
    }

    public synchronized void put(E e) throws InterruptedException {
        if (e==null) return;
        while (putting)
            wait();
        putting = true;
        item = e;
        notifyAll();
        while (item!=null)
            wait();
        putting = false;
        notifyAll();
    }
}

信号量实现

经典同步队列实现采用了三个信号量,代码很简单,比较容易理解:

[Read More]

OpenVPN使用多个端口

Openvpn本身不能设置多个端口,使用iptables可以解决这个问题 (假设openvpn本来56788端口):

for port in {56780..56787}
do 
    iptables -t nat -A PREROUTING -p tcp -d <your_external_ip> --dport $port -j REDIRECT --to-port 56788
done

Java的资源管理

Overview

Java程序中的常见的资源有:文件,Socket,数据库连接。在使用这些资源时候要分外小心,因为操作系统可同时操作的资源是有限的,比如默认情况下系统允许同时打开的文件数为1024个,Mysql服务器默认允许的最大连接数是100,所以操作这些资源时候要注意即使在遇到错误时也要让系统能正确回收资源。如果发生错误时候,打开的文件描述符没关闭或数据库连接没关闭,积累到一定程度后,应用将会变得不可用,只能重启。

try-catch-finally

Java提供了try-catch-finally来保证程序遇到异常时总是有机会可以处理资源的关闭 – 调用资源对象的close()方法。但经验不足的Java程序员还是会错误的管理资源,而造成资源的泄露,静态代码分析工具,如FindBugs可以帮助发现此类问题。

首先我们来看一段文件操作代码:

private void copy(String from, String to) throws IOException {
    FileInputStream in = null;  
    FileOutputStream out = null;  
    in = new FileInputStream(from);  
    out = new FileOutputStream(to);  
    int c;  
    while ((c = in.read()) != -1)
        out.write(c);  
    in.close();
    out.close();
}

一眼看上去,代码挺整齐的,逻辑也容易理解。但其中有一个很大的问题是,如果out.write调用失败(比如磁盘空间满了)方法异常退出,in.close()和out.close()就不会被调用,而in和out对象内部都引用了系统资源-文件描述符,这样会导致文件描述符没有关闭,不能被重新使用而直到整个Java进程退出。

File descriptor

Linux的每个进程(如:Java进程)都有一个文件描述符表管理当前进程访问的所有的文件,文件描述符关联了系统文件表中的file entry,系统能容纳多少file entry是有限制的,如果超过限制系统会拒绝访问,抛出Too many opened files错误。

较为正确的代码应该是:

private void copy(String src, String dest) throws IOException {
    FileInputStream in = null;  
    FileOutputStream out = null;  
    try {
        in = new FileInputStream(src);  
        out = new FileOutputStream(dest);  
        int c;  
        while ((c = in.read()) != -1)
            out.write(c);
    } finally {
         try {
             if (in!=null) {
                in.close();
             }
         } finally {
             if (out!=null) {
                out.close();
             }
         }
    }
}

但是这样的代码写起来是不是让人有点沮丧?这样写代码犯错的可能性确实比较大。 改良过后的代码阅读性好一些:

[Read More]

在Ubuntu上配置L2TP,PPTP和OpenVPN服务

Overview

MacOS, Windows, iOS都内置支持PPTP,L2TP;OpenVPN需要安装客户端,手机上一般不支持。

先打开内核的IP转发,修改 /etc/sysctl.conf

net.ipv4.ip_forward=1

执行下面命令以生效

sudo sysctl -p

PPTP

安装pptpd

apt-get install pptpd

编辑 /etc/pptpd.conf,下面两行取消注释

localip 192.168.0.1
remoteip 192.168.0.234-238,192.168.0.245

这行注释掉

#logwtmp 

从文件 /etc/pptpd.conf 中找到配置选项文件,如下为:/etc/ppp/pptpd-options

grep options /etc/pptpd.conf
#       Specifies the location of the PPP options file.
#       By default PPP looks in '/etc/ppp/options'
option /etc/ppp/pptpd-options
#       option in the pppd options file, or run bcrelay.

编辑 /etc/ppp/pptpd-options,增加以下内容,最后两项为推给VPN客户端的DNS服务器IP

mtu 1492
name pptpd
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2
require-mppe-128
proxyarp
lock
nobsdcomp
novj
novjccomp
nologfd 
ms-dns 8.8.8.8
ms-dns 8.8.4.4

修改 /etc/ppp/chap-secrets, 增加一个VPN用户: foo ,密码设置为: bar

[Read More]
VPN