树莓派轻松上手

非常适合新手的树莓派上手指南

NONGFAH 写于 2018-12-14

演示的树莓派型号是 3B ,其他版本仅供参考。

论坛

树莓派实验室 树莓派中文站

上手指南

安装系统

下载系统

官方推荐系统 将下载好的系统(ZIP格式)解压,得到IMG映像文件(此处IMG文件路径不允许中文)
SD卡格式化工具 下载后解压安装
镜像写入工具 下载后解压安装

格式化SD卡

初次使用

将内存卡插入电脑,打开格式化工具(SD Card Formatter);
确定系统自动选择的SD卡是你要格式化的之后,点击Format。格式化完成。  

对于安装系统后已经分区的SD卡,可以使用windows自带的分区工具,将两个区再次合并。

右键点击此电脑(or 我的电脑),点击管理;  
在新窗口(管理工具)中选择磁盘管理,右键点击你的SD卡,依次删除SD卡上的卷,然后新建卷;
此时,你的SD卡已经被合并成一个分区。  

镜像写入

打开下载的镜像写入工具(balenaEtcher),选择解压后得到的IMG镜像文件(IMG文件路径不允许中文),选择SD卡,点击Flashing。
在写入镜像过程中,系统提醒需要格式化SD卡,一律拒绝。等待写入完成。

配置初始WIFI及SSH

有些同学只入手了树莓派主板,并没有任何显示外设。如果你有,你可以跳过这步。
在没有显示设备的情况下,我们可以通过配置初始WIFI及SSH 使用另一台主机远程到树莓派。
首先,确保你的电脑能够找到boot分区,如果找不到,请将SD卡重新插入;

配置初始WIFI

在boot分区新建文件

wpa_supplicant.conf  

在该文件中写入以下内容(修改成你自己的WIFI账号密码)

country=CN
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
 
network={
    ssid="WiFi-A"
    psk="12345678"
    key_mgmt=WPA-PSK
    priority=1
}
 
network={
    ssid="WiFi-B"
    psk="12345678"
    key_mgmt=WPA-PSK
    priority=2
    scan_ssid=1
}  

这是该文件的说明

#ssid:网络的ssid
#psk:密码
#priority:连接优先级,数字越大优先级越高(不可以是负数)
#scan_ssid:连接隐藏WiFi时需要指定该值为1  

配置初始WIFI完成,在你启动树莓派时,树莓派就会自动连接配置的WIFI

配置ssh

同样,在boot分区下,新建文件 ssh ,不带任何扩展名,全部小写
配置ssh完成

开机

将SD卡插入树莓派,连接电源,等待系统启动。

在此阶段观察树莓派的指示灯
红灯代表设备通电;
黄灯常亮代表系统正在启动;
黄灯闪烁或不亮代表开机完成;

配置远程

安装xrdp

如果你没有购置显示器,并且仍不打算购入。
那我建议你使用键盘连接树莓派,在开机后使用 Ctrl + Alt + t 组合键调起树莓派的命令行。
然后 键入

sudo apt-get install xrdp  

来安装 xdrp服务 ,该服务能够允许你使用windows自带的远程桌面(mstsc.exe)连接树莓派。

查看树莓派IP

如果你没有购置显示器,我们无法直接查看树莓派IP,在此我提供两种方法。

通过路由器查看

你可以轻易通过访问路由器的管理页面查看新加入网络的设备IP。
如果你做不到,我建议你将树莓派关机,然后刷新管理页面,
待树莓派开机后,新加入网络的设备IP就是树莓派IP,记住这个IP。

通过另一台电脑查看

在一些特殊情况下,你没有权限去访问路由器管理页面。
此时,我提供一些工具来帮助你扫描网络下的IP(你也可以尝试自己去找ip扫描工具,并尝试使用。我们要做的只是得到树莓派的IP),确保你的电脑有java环境。
如果没有,你可以尝试去百度如何让你的电脑支持java。

你也可以直接使用下面的代码来扫描局域网内的IP

import java.net.*;
import java.io.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) {
        PingTester tester = new PingTester();
        tester.startPing();
    }
}

class PingTester {
    private Queue<String> allIp;
    private int fetchedNum = 0; // 已经取得的任务数量,每次从队列中取一个ip就加1

    public PingTester() {
        // 首先创建一个队列用于存储所有ip地址
        allIp = new LinkedList<String>();
        for (int i = 0; i < 256; i++) {
            //allIp.offer("192.168.9." + i);
            for (int j = 0; j < 256; j++) {
                allIp.offer("192.168."+i+"."+j);
            }
        }
    }

    public void startPing() {
        // 创建一个线程池,多个线程同时跑
        int threadNum = 1000;
        ExecutorService executor = Executors.newFixedThreadPool(threadNum);
        for (int i = 0; i < threadNum; i++) {
            executor.execute(new PingRunner());
        }
        executor.shutdown();
        try {
            while (!executor.isTerminated()) {
                Thread.sleep(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("Fetched num is "+fetchedNum);
    }

    private class PingRunner implements Runnable {
        private String taskIp = null;
        @Override
        public void run() {
            try {
                while ((taskIp = getIp()) != null) {
                    InetAddress addr = InetAddress.getByName(taskIp);
                    if (addr.isReachable(5000)) {
                        //System.out.println("host ["+taskIp+"] is reachable");
                        System.out.println(taskIp);
                    } else {
                        //System.out.println("host ["+taskIp+"] is not reachable");
                    }
                }
            } catch (SocketException e) {
                //System.out.println("host ["+taskIp+"] permission denied");
            } catch (Exception e) {
                System.out.println("---------------------------------------------"+taskIp);
                e.printStackTrace();
            }
        }

        public String getIp() {
            String ip = null;
            synchronized (allIp) {
                ip = allIp.poll();
            }
            if (ip != null) {
                fetchedNum++;
            }
            return ip;
        }
    }
}  

该代码转载自起一个好听的名字并进行了部分修改。
将该代码复制后粘贴到 Main.java 并使用

javac Main.java  

编译代码
使用

java Main >IP.txt  

将输出结果保存到本地的IP.txt文件中。等待程序运行完毕。
打开IP.txt和windows自带的mstsc.exe,尝试使用得到的IP进行远程连接,直到连接成功。
需要注意的是,如果该地址是树莓派的地址,它会立即给你反馈,所以你不需要等待系统提醒你连接超时。
点一下,没反应关了试试下一个才是正解。

远程连接

如果你成功找到了树莓派的地址。那你可以使用

账号: pi
密码: raspberry

来进行登陆。

后记

最后,我们来说一下过程中我遇到的坑。

Etcher

系统镜像写入工具

0.在正常格式化SD卡,完全正常写入镜像,在写入完成的提示信息中:提醒 A device failed
但是此时已经写入成功。  
1.千万注意写入镜像时,无论系统如何提醒,也不要格式化SD卡

网络

WIFI

0.公司使用的路由器支持双频 2.4G 和 5G ,但入手的树莓派只支持2.4G
    使用笔记本扫描时,笔记本默认连接的是5G网络
    网关不同,根本扫描不到,即使拿到树莓派的地址,不同网关也不能直接连接。
    根源在于公司把2.4G 和5G的SSID设置成一个,这太傻了。  

百度经验能帮助你选择不同频率的网络

键盘输入

数字键

0.使用远程桌面连接树莓派后,在输入数字时,如果使用小键盘输入,NumLock键盘锁状态在两台设备上可能不一样。
    举例来说,本机上,你开启小键盘,正常输入。  
    但是连接树莓派后,树莓派上的数字锁是关闭的,你以为自己输入了,其实没有。
    一般在远程之前我会关闭小键盘,在树莓派连接后再打开,这样能使树莓派和本机的小键盘状态一致。