树莓派配置

Wifi认证及静态IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#### Raspbian
$ cat /etc/network/interfaces
# ...
source-directory /etc/network/interfaces.d

auto wlan0
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.8.160
netmask 255.255.255.0
network 192.168.8.1
gateway 192.168.8.1
broadcast 192.168.8.255
wpa-essid "..."
wpa-psk "..."

# wpa-essid: wifi名称
# wpa-psk: wifi 密码,psk认证

树莓派连接游戏手柄

驱动

xpadneo

依赖

1
2
# Raspbian
$ sudo apt install dkms raspberrypi-kernel-headers

安装

1
2
3
4
5
6
7
8
9
$ git clone https://github.com/atar-axis/xpadneo.git
$ cd xpadneo
$ sudo ./install.sh

# 如遇如下报错
# Your kernel headers for kernel 4.19.97-v7l+ cannot be found at
# /lib/modules/4.19.97-v7l+/build or /lib/modules/4.19.97-v7l+/source.
# 将 /lib/modules 下拷贝一份至缺失版本,如:
# sudo cp -r /lib/modules/5.4.79-v7l+ /lib/modules/4.19.97-v7l+

连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ bluetoothctl
$ [bluetooth]# scan on
...
# 长按xbox前侧配对键,至指示灯快速闪烁,出下如下新设备,记录其mac地址
[NEW] Device <MAC> Xbox Wireless Controller
...
[bluetooth]# pairable on
[bluetooth]# power on
[bluetooth]# pair <MAC>
[bluetooth]# trust <MAC>
[bluetooth]# connect <MAC>

# 如若报 Failed to connect: org.bluez.Error.Failed 错误,执行如下命令并重启系统
$ echo 'options bluetooth disable_ertm=Y' | sudo tee -a /etc/modprobe.d/bluetooth.conf

其他

1
2
# 查看设备
$ bluetoothctl devices

使用

Python

安装依赖

1
$ sudo pip3 install evdev asyncio

测试

1
2
3
4
5
6
$ cd xpadneo/misc/examples # 克隆下来的Git仓库
$ python3 python_asyncio_evdev/gamepad.py
press x to stop, Y to rumble light, B to rumble once, trigger and joystick right to see analog value
trigger_right = 32.98 joystick_right_x = 0

# 如果一切顺利,按手柄Y会感受到长震动;按B会感受到短震动;按X退出程序

按键

按键 code type 值类型
LT 10 03 区间,0~1023
RT 09 03 区间,0~1023
LB 310 01 单值,00,01
RB 311 01 单值,00,01
左摇杆 Y轴 01 03 区间,0~65535
左摇杆 X轴 00 03 区间,0~65535
右摇杆 Y轴 05 03 区间,0~65535
右摇杆 X轴 02 03 区间,0~65535
视图 158 01 单值,00,01
菜单 315 01 单值,00,01
十字键 上 17 03 单值,00,-1
十字键 下 17 03 单值,00,01
十字键 左 16 03 单值,00,-1
十字键 右 16 03 单值,00,01
Y 308 01 单值,00,01
X 307 01 单值,00,01
A 304 01 单值,00,01
B 305 01 单值,00,01

  • 摇杆X轴左侧为0,Y轴上侧为0

树莓派连接硬件

Speaker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# play audio
$ sudo apt-get install sox libsox-fmt-all
$ play file-name.mp3

# turn volume
$ amixer set Master 50%
$ amixer set Master 10%+

# slelect speaker
$ alsamixer
## F6 to select device

# set volume over 100%
$ sudo apt install pulseaudio
$ pulseaudio --start -D
$ pulseaudio --check -v # check
$ sudo apt-get install pulseaudio-utils
$ pactl set-sink-volume 0 300%

Camera

Web Stream

1
2
# install
$ sudo apt-get install libjpeg8-dev imagemagick

Reference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# setup and test
https://www.raspberrypi.org/documentation/configuration/camera.md

# official documents
https://www.raspberrypi.org/documentation/raspbian/applications/camera.md

# web stream
https://blog.miguelgrinberg.com/post/stream-video-from-the-raspberry-pi-camera-to-web-browsers-even-on-ios-and-android
https://blog.miguelgrinberg.com/post/how-to-build-and-run-mjpg-streamer-on-the-raspberry-pi
## 注释 mjpg-streamer/util.c stats.h
# // #include <linux/stat.h>
# // #include <sys/stat.h>

# generate stream
$ raspistill --nopreview -w 640 -h 480 -q 5 -o /home/pi/test.jpg -tl 100 -t 9999999 -th 0:0:0

# serve stream
$ LD_LIBRARY_PATH=/usr/local/lib mjpg_streamer -i "input_file.so -f /home/pi -n test.jpg" -o "output_http.so -w /usr/local/www"

# watch
http://rpi-ip:8080

L298N

参考

Linux之查看设备

CPU

1
$ lscpu

PCI 设备

1
$ lspci

块设备信息

1
2
3
4
5
6
7
$ lsblk

# 查看挂载的节点和对应的分区 UUID
$ ls -lha /dev/disk/by-uuid

# 查看块设备的信息,包含 UUID
$ blkid /dev/sda1

参数

  • -f 显示文件系统信息
  • -a 显示所有设备

硬盘

初始化步骤

  • 创建分区表
  • 创建分区
  • 格式化分区
  • 挂载分区
  • 配置启动时挂载

列出设备及分区信息

1
2
3
$ parted -l
#
$ fdisk -l

初始化设备

格式化

1
$ mkfs [options] [-t type fs-options] device [size]

示例

1
$ sudo mkfs -t ext4 /dev/sda

类型

  • ext4
  • FAT32
  • NTFS

使用中无法格式化

1
2
3
$ dmsetup status
$ dmsetup remove <>
$ dmsetup remove_all # 清楚所有, 谨慎使用, 最好挨个删除

创建主分区

打开存储盘

1
2
3
4
5
6
$ sudo parted -a optimal /dev/sda
GNU Parted 3.1
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) select /dev/sdb # 切换至 /dev/sdb
Using /dev/sdb

创建分区表

1
(parted) mklabel [partition_table_type]

分区表类型

  • aix
  • amiga
  • bsd
  • dvh
  • gpt
  • mac
  • ms-dos
  • pc98
  • sun
  • loop

示例

1
(parted) mklabel gpt

检查

1
(parted) print

创建分区

1
2
3
4
5
6
7
# 主分区
(parted) print free
(parted) mkpart primary [start] [end] # 主分区模式

# lvm 分区
(parted) unit s
(parted) mkpart LVM ext4 0% 100%

示例

1
2
(parted) mkpart primary 0.00B 100GB   # 按容量 
(parted) mkpart primary 0 100% # 按比例

格式化分区

1
$ sudo mkfs.ext4 /dev/sda1

自动挂载分区

1
2
$ sudo mkdir data
$ sudo mount -t auto /dev/sda1 /data
1
$ echo -e "UUID=$(sudo blkid -o value -s UUID /dev/sdb1)\t/data\text4\tdefaults\t0 0" | sudo tee -a /etc/fstab

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
$ sudo parted /dev/sda
GNU Parted 3.1
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print
Model: ATA Hitachi HUS72404 (scsi)
Disk /dev/sda: 4001GB
Sector size (logical/physical): 512B/4096B
Partition Table: loop
Disk Flags:

Number Start End Size File system Flags
1 0.00B 4001GB 4001GB ext4

(parted) mklabel gpt
Warning: The existing disk label on /dev/sda will be destroyed and all data on this disk will be lost. Do you want to continue?
Yes/No? yes
(parted) print
Model: ATA Hitachi HUS72404 (scsi)
Disk /dev/sda: 4001GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number Start End Size File system Name Flags
(parted) mkpart primary 4096s 100% # 创建分区表
(parted) print
Model: ATA Hitachi HUS72404 (scsi)
Disk /dev/sda: 4001GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number Start End Size File system Name Flags
1 2097kB 4001GB 4001GB primary
$ sudo mkfs.ext4 /dev/sda1
...
$ sudo mount -t auto /dev/sda1 /data
$ df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 32G 0 32G 0% /dev
tmpfs 32G 0 32G 0% /dev/shm
tmpfs 32G 2.0G 30G 7% /run
tmpfs 32G 0 32G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 4.2G 46G 9% /
/dev/nvme0n1p2 1014M 233M 782M 23% /boot
/dev/nvme0n1p1 200M 12M 189M 6% /boot/efi
/dev/mapper/centos-home 395G 332M 394G 1% /home
tmpfs 6.3G 12K 6.3G 1% /run/user/42
tmpfs 6.3G 0 6.3G 0% /run/user/1000
/dev/sda1 3.6T 89M 3.4T 1% /data

创建分区表时 4096s 的取值,可以参考 这里这里

脚本创建分区 & 格式化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 分区
parted --script /dev/vdb \
mklabel gpt \
mkpart primary 4096s 100%

# 格式化
mkfs.ext4 /dev/vdb1

# 挂载
mount -t auto /dev/vdb1 /data

# 写入 /etc/fstab, root 用户运行
echo -e "UUID=$(blkid -o value -s UUID /dev/sdb1)\t/data\text4\tdefaults\t0 0" >> /etc/
fstab
echo -e "UUID=$(sudo blkid -o value -s UUID /dev/sdb1)\t/data\text4\tdefaults\t0 0" | sudo tee -a /etc/fstab

echo -e "UUID=$(blkid -o value -s UUID /dev/sdb1)\t/downloads\text4\tdefaults\t0 0" >> /etc/fstab

创建 LVM 分区

概念

  • 物理卷(Physical Volumes)
  • 卷组(Volume Groups)
  • 逻辑卷(Logical Volumes)

查看信息

查看所有 LVM 可以管理的块设备

1
sudo lvmdiskscan

查看物理卷信息

1
2
3
4
5
6
7
8
9
sudo lvmdiskscan -l
#
sudo pvscan

# 如果需要展示更多信息
sudo pvs
#
sudo pvdisplay
sudo pvdisplay -m # 查看映射到每个卷的逻辑扩展名

查看 Volumn Group 的信息

1
sudo vgscan

查看 Logical Volumn 信息

1
2
3
sudo lvscan
#
sudo lvs

创建 LVM 卷

从 Raw Storage Device 创建 Physical Volumes

1
2
# 列出所有可用的设备
sudo lvmdiskscan

如果没有列出目标设备,可能是设备使用了不支持的分区表。重新设置设备的分区表为兼容的 BIOS 表。

1
2
3
sudo parted /dev/sda
(parted) mktable msdos
(parted) quit

标记存储设备为 LVM 物理卷。

1
2
3
sudo pvcreate /dev/sda
# 多个设备
sudo pvcreate /dev/sda /dev/sdb

从 Physical Volumes 创建 Volume Group

1
2
3
sudo vgcreate lvm-storage /dev/sda
# 多个设备
sudo vgcreate lvm-storage /dev/sda /dev/sdb

从 Volume Group 创建 Logical Volume

1
2
3
4
5
# 创建指定 size
sudo lvcreate -L 500G -n lvm-storage-hadoop lvm-storage

# 使用所有剩余空间
sudo lvcreate -l 100%FREE -n lvm-storage-hadoop lvm-storage

格式化分区

1
sudo mkfs.ext4 /dev/<lvm-vg-name>/<lvm-lv-name> 

挂载 LV

1
sudo mount /dev/<lvm-vg-name>/<lvm-lv-name> /path/to/destination

自动挂载

1
2
3
4
5
6
7
# 查看 logical volume 的 uuid
sudo blkid
/dev/mapper/<lvm-lv-name>: UUID="0192e4be-db57-4dc9-9f07-cb7bd673811b" BLOCK_SIZE="4096" TYPE="ext4"
# 添加自动挂载
sudo vim /etc/fstab
# 新增如下内容
UUID=0192e4be-db57-4dc9-9f07-cb7bd673811b /storage/hadoop ext4 defaults 0 2

更多操作

向 Volume Group 添加 Physical Volume

1
sudo vgextend <volume-group-name> /dev/sdb

增加 Logical Volume 的空间

Solution 1

1
2
3
4
sudo lvresize -L +5G --resizefs <lvm-vg-name>/<lvm-lv-name>  # 调整 lvm size
sudo lvresize -l +100%FREE /dev/<lvm-vg-name>/<lvm-lv-name> # 使用所有剩余空间
# sudo lvdisplay; 找到 Logical Volume 的 LV Path
sudo resize2fs <lv-path> # 生效

注意: lvresize 之后通过 df -h 查看空间,并不会生效,需要再运行 resize2fs

Solution 2

为 Ubuntu 的 lv 分区扩容

1
2
3
$ sudo vgdisplay  # 查看 vg 信息
$ sudo lvdisplay # 查看 lv 信息
$ sudo lvextend -l +100%FREE -r /dev/ubuntu-vg/ubuntu-lv

删除 Logical Volume

1
2
sudo umount /dev/<lvm-vg-name>/<lvm-lv-name>
sudo lvremove <lvm-vg-name>/<lvm-lv-name>

删除 Volume Group

1
2
sudo umount /dev/<lvm-vg-name>/* # unmount vg 下所有 lv
sudo vgremove <lvm-vg-name>

删除 Physical Volume

1
sudo pvremove /dev/sda

挂载新硬盘

1
2
3
4
5
6
7
8
9
10
11
# 创建文件系统
$ sudo mkfs -t ext4 /dev/sdb
# 分区
$ sudo parted -a optimal /dev/sdb
(parted) mklabel gpt
(parted) mkpart primary 0% 100%
# 格式化
$ sudo mkfs.ext4 /dev/vdb1
# 挂载
$ sudo mkdir /data
$ sudo mount -t auto /dev/sdb1 /data

查看接口

1
2
sudo dmidecode --type connector
# 可以查看 USB、SATA、M.2 接口

参考

Linux之网络配置

DNS

Debian+

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# interfaces; configured by dns-nameserver
$ cat /etc/network/interfaces
...
auto wlan0
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.8.160
netmask 255.255.255.0
network 192.168.8.1
gateway 192.168.8.1
broadcast 192.168.8.255
wpa-essid "<wifi-id>"
wpa-psk "<wifi-password>"
dns-nameserver 8.8.8.8
dns-nameserver 8.8.4.4
dns-nameserver 192.168.8.1

Proxy

全局代理

1
2
export http_proxy=socks5://<host>:<port>
export https_proxy=socks5://<host>:<port>

适用

  • cURL

Git 代理

1
2
3
4
5
6
7
# 设置代理
git config --global https.proxy socks5://<host>:<port>
git config --global https.proxy socks5://<host>:<port>

# 取消
git config --global --unset http.proxy
git config --global --unset https.proxy

CMD ip

1
2
via : [FAMILY] ADDRESS, 指定下一跳地址
src : ADDRESS, 发送至目的地时优先使用的源地址

table

1
2
3
4
5
6
7
8
9
10
# show table
ip route show table all
ip route show table 10

# add table
ip route add 192.168.6.0/24 dev br0 table 10
ip route add default via 192.168.6.1 table 10

# 删除 table
ip route delete table 12 192.168.9.0/24

rule

1
2
3
4
5
# show rule
ip rule show

# 添加
ip rule add from 192.168.6.0/24 table 10 priority 1

gateway

1
2
3
4
5
# 添加
ip route add default via 192.168.1.1 dev eth0

# 更新 (所有配置都要添加vc)
ip route replace default via 192.168.1.1 dev eth0

静态路由

1
2
# github ip 走网关 192.168.6.68 
sudo ip route add 20.205.243.166 via 192.168.6.68

CMD route

1
2
# 添加路由
route -q -n add -inet 192.168.6.0/24 -interface utun3

Route Trace

1
2
3
$ traceroute -4 baidu.com
$ traceroute -6 baidu.com # ipv6
$ traceroute -g 192.168.6.1 # 指定 gateway

tcpdump

1
2
# 客户端抓取向服务端发送的数据
$ tcpdump dst host {dst-host} and dst port {dst-port} -w out.pacp

树莓派 - PWM 调速马达

L298N

L298N motor controller board

接口

  • OUT A,接马达 A
  • OUT B ,接马达 B
  • POWER,+5V、GND、+12V
    • 5V 电源,接 +5V + GND
    • 12V 电源,接 +12V + GND
  • 控制端口,ENA、INA1、INA2、INB1、INB2、ENB
    • 接 GPIO
    • ENA、INA1、INA2 控制马达 A
    • ENB、INB1、INB2 控制马达 B

JVM 参数

参数

参数 默认值 说明
-XX:MaxDirectMemorySize 64M 非堆内存大小

GC

G1GC

G1GC是区域化、分代式垃圾回收器。堆内存被划分为大小相同的若干区域(Region),区域大小取值为[1,32]之间2的幂,若不配置Region大小,JVM以数量不超过2048个区域为目标,确定Region大小。这些Region逻辑上组合成传统的Eden、Survivor、Tenured。

概念

  • Region:对内存块,逻辑组合为传统的年轻代、老年代
  • CSet:回收集
  • RSet:记忆集
  • SATB: Snapshot-At-The-Beginning,初始快照
  • IHOP:Initiating Heap Occupancy Percent

分区

阶段

G1GC在两个阶段之间交替,young-only和space-reclamation。young-only 阶段包括垃圾回收,其逐渐将

Young-only 阶段

该阶段开始是一些普通年轻代回收(Normal yount collection),其将对象晋升至老年代。Young-only向Space-reclamatioin阶段过渡始自老年代使用率达到设定阈值。此时,G1执行**并行开始年轻代回收(Concurrent Start young collection)**替代普通年轻代回收。过渡周期包含以下阶段。

  • Concurrent Start:除了执行普通年轻代回收,同时开始标记过程(marking process)。并行标记决定老年代区域中(old generation regions)所有当前可达对象,在接下来的space-reclamation阶段被保留。当回收标记还未完成时,可能会进行普通年轻代回收。标记完成伴随两个STW阶段:Remark和Cleanup。
  • Remark:完成标记本身、执行全局引用处理、类卸载、回收空区域、清理内部数据结构。在Remark和Cleanup之间,G1会计算信息,以便后面能够在选中的老年代区域中并发回收可用空间,该过程在Cleanup阶段完成。
  • Cleanup:决定是否将实际执行space-reclamation阶段。如果随后进行space-reclamation阶段,young-only阶段以单个就绪混合年轻代回收(Prepare Mixed young collection)结束。

Space-reclamation 阶段

该阶段包含多个混合回收,除了年轻代区域外,还会压缩(evacuate)老年代区域集合中的存活对象。当G1确定压缩更多老年代区域不会产生足够值得努力的空间时,space-reclamation阶段结束。

细节

确定初始堆占用率

初始堆占用率(Initiating Heap Occupancy Percent,IHOP)是触发初始标记回收的阈值,定义为老年代大小的百分比。

默认情况下,G1通过观察标记耗时及标记周期内老年代分配内存,自动决定最佳的IHOP。该特性称为Adaptive IHOP,当该特性激活时,参数-XX:InitiatingHeapOccupancyPercent指定的值作为,G1在还没有足够观察值确定该值时的初始值。通过参数-XX:-G1UseAdaptiveIHOP可关闭该特性,此时 -XX:InitiatingHeapOccupancyPercent 参数指定的值总是决定该阈值。

标记

G1标记使用初始快照算法(Snapshot-At-The-Beginning,SATB)。在初始标记暂停时(Initial Mark pause),为堆创建虚拟快照,

参数

参数 默认值 说明
-XX:+UseG1GC - 使用G1回收器
-XX:MaxGCPauseMillis 200 最大GC停顿时间,单位毫秒
-XX:InitiatingHeapOccupancyPercent 45 触发标记周期的堆占用率阈值
-XX:NewRatio 2 新生代与老年代大小比例
-XX:SurvivorRatio 8 eden与suvivor区大小比例
-XX:MaxTenuringThreshold 15 提升年老代的最大临界值
-XX:ParallelGCThreads - STW工作线程数
-XX:ConcGCThreads - 并行标记线程数
-XX:G1ReservePercent 10 空闲空间的预留内存百分比
-XX:G1HeapWastePercent 10 触发混合垃圾回收的可回收堆内存阈值
-XX:G1HeapRegionSize - region分片size,1M~32M,2的幂
-XX:G1MixedGCCountTarget 8
-XX:G1OldCSetRegionThresholdPercent 10
-XX:-G1UseAdaptiveIHOP - 关闭自动设置IHOP特性

实验参数

使用实验参数,需要添加解锁实验参数标记。

参数 默认值 说明
-XX:+UnlockExperimentalVMOptions - 解锁实验参数
-XX:G1NewSizePercent 5 年轻代最小百分比
-XX:G1MaxNewSizePercent=60 60 年轻代最大百分比
-XX:G1MixedGCLiveThresholdPercent 65 混合垃圾回收周期中要包括的老年代region使用率阈值

日志

参数 说明
-verbose:gc -
-XX:+PrintGCDetails -
-XX:+PrintGCDateStamps -
-XX:+PrintGCApplicationStoppedTime 打印应用停留时间
-XX:+PrintTenuringDistribution 老年代分布
-Xloggc:/path/to/gc.log -
-XX:+UseGCLogFileRotation -
-XX:NumberOfGCLogFiles=10 -
-XX:GCLogFileSize=128M -

注意

  • G1触发Full GC,退化使用Serial收集完成垃圾回收,仅适用单线程
  • 避免使用 -Xmn或 -XX:NewRatio 显示设置年轻代大小,会覆盖期望STW时间设置
  • 优先调优项
    • -XX:InitiatingHeapOccupancyPercent
    • -XX:G1MixedGCLiveThresholdPercent
    • -XX:G1HeapWastePercent
    • -XX:G1MixedGCCountTarget
    • -XX:G1OldCSetRegionThresholdPercent

参考

memset & fill

memset

头文件

1
2
3
4
// c
#include <string.h>
// c++
#include <cstring>

使用

1
2
3
4
5
6
void *memset( void *dest, int ch, size_t count );
dest : 需要填充内存指针
ch : 填充内容,被强转成unsigned char使用
count: 需要填充数量

dest指针开始前count个字节的每个字节赋值为ch

示例

1
2
3
4
5
6
char str[] = "hello world";
memset (str, '-', 5);
puts(str);

// output
"----- world"

fill

头文件

1
#include <algorithm>

使用

1
2
3
4
5
template< class ForwardIt, class T >
constexpr void fill( ForwardIt first, ForwardIt last, const T& value );
first : 开始迭代器
last : 中止迭代器
value : 需要填充的值