Hero Image
使用Cartographer进行建图

ubuntu22.04安装cartograph 源码安装 在我们的项目中,需要在ubuntu22.04下源码安装cartograph.可以按照以下步骤进行. git clone git@github.com:ros2/cartographer.git git clone git@github.com:ros2/cartographer_ros.git # 安装依赖项 absl c++扩展库,参考下install_abseil.sh里使用的absl版本 git clone git@github.com:abseil/abseil-cpp.git cd abseil-cpp git checkout 215105818dfde3174fe799600bb0f3cae233d0bf cd build cmake -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ -DCMAKE_INSTALL_PREFIX=/usr/local/stow/absl \ .. ninja sudo ninja install cd /usr/local/stow sudo stow absl # 安装 ceres 非线性优化库 sudo apt install libceres-dev # 安装lua 脚本语言库,提供配置文件解析 sudo apt install liblua5.3-dev # 安装protobuf 数据序列化开发库 sudo apt install protobuf-compiler libprotobuf-dev # 安装地图可视化库,支持轨迹绘制以及地图可视化 sudo apt install libcairo2-dev # 安装boost C++ 库集合 sudo apt install libboost-all-dev # 安装 Eigen3 线性代数库 sudo apt install libeigen3-dev # 编译cartographer_ros colcon build --packages-up-to cartographer_ros # rviz插件我们直接使用apt安装 sudo apt install ros-humble-nav2-rviz-plugins sudo apt install ros-humble-cartographer-rviz 保存地图 使用Cartographer进行建图时,可以将建图结果保存下来,我们这里可以采用ROS2自带的保存地图工具nav2_map_server.

Hero Image
Github错误处理

github 问题处理 分离指针 HEAD detached from ff8573b 分离头指针是说Git仓库的HEAD指针没有指向任何分支,而是直接指向一个特定的commit。正常情况下,HEAD应该指向一个确定的分支,但在分离头指针状态下,HEAD指向了某个commit。 以下指令会导致处于分离头指针状态: 直接检出了某个commit 检出远程指针时并没有在本地创建对应的本地分支 在主仓库中的submodule仓库(子模块)一般都处于分离头指针状态,这是因为主仓库对应的是子仓库的某一次提交,在检出时就会检出特定的commit提交,而不是某个分支。 HEAD detached from就是报告了github处于分离头指针状态,如果我们需要将当前的修改保存到main分支,则按照下述指令进行。 # 创建临时分支,保存修改 git branch temp # 切换到主分支 git checkout main # 合并temp 分支 git merge temp # 删除 temp 分支 git branch -d temp # 将修改推送到远程 git push origin main 拉取分支 将云端指定分支拉取到本地 # 获取远程分支信息 git fetch origin # 查看远程分支有哪些分支 git branch -r # 创建指定分支 git checkout -b dev origin/dev 丢弃提交 丢弃某一次commit 在项目开发中,如果进行了一次错误提交,需要删除这次提交所对应的修改,最安全的方式是创建一次新的commit来撤销之前的commit。 # 创建一个新的commit来撤销之前的commit git revert <commit-hash> 拉取仓库错误 拉取仓库错误 ssh: Could not resolve hostname github.com: Temporary failure in name resolution fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. 在wsl中拉取仓库中出现了这个错误,但是在宿主机是可以访问github的,这个问题是DNS原因导致的,可以按照如下步骤解决:

Hero Image
树莓派5操作GPIO

在树莓派上操作GPIO lgpio 库详解与使用指南 lgpio 是一个用于 Linux 系统的 GPIO(通用输入输出)控制库,专门为树莓派等单板计算机设计。它提供了高性能的 GPIO 操作接口,支持: GPIO 读写操作 PWM 信号生成 舵机控制 中断处理 硬件定时器 lgpio 安装方法 在树莓派上安装 # 更新系统 sudo apt update sudo apt upgrade # 安装 lgpio sudo apt install python3-lgpio # 或者使用 pip 安装 pip3 install lgpio 验证安装 import lgpio print(lgpio.__version__) 核心功能 1. GPIO 设备管理 import lgpio # 打开 GPIO 设备 handle = lgpio.gpiochip_open(0) # 0 表示第一个 GPIO 控制器 # 关闭 GPIO 设备 lgpio.gpiochip_close(handle) 2. GPIO 配置 # 设置为输出模式 lgpio.gpio_claim_output(handle, gpio_pin, initial_value) # 设置为输入模式 lgpio.gpio_claim_input(handle, gpio_pin) # 设置为输入模式并启用上拉电阻 lgpio.gpio_claim_input(handle, gpio_pin, lgpio.PULL_UP) 3. GPIO 读写操作 # 写入 GPIO(输出模式) lgpio.gpio_write(handle, gpio_pin, value) # value: 0 或 1 # 读取 GPIO(输入模式) value = lgpio.gpio_read(handle, gpio_pin) # 返回 0 或 1 实际应用示例 示例 1:LED 控制 import lgpio import time class LEDController: def __init__(self, led_pin=18): self.led_pin = led_pin self.handle = None def init_led(self): """初始化 LED GPIO""" try: # 打开 GPIO 设备 self.handle = lgpio.gpiochip_open(0) if self.handle < 0: print("无法打开 GPIO 设备") return False # 设置 LED 引脚为输出模式 lgpio.gpio_claim_output(self.handle, self.led_pin, 0) print(f"LED 初始化成功,引脚: {self.led_pin}") return True except Exception as e: print(f"LED 初始化失败: {e}") return False def turn_on(self): """点亮 LED""" if self.handle is not None: lgpio.gpio_write(self.handle, self.led_pin, 1) print("LED 已点亮") def turn_off(self): """熄灭 LED""" if self.handle is not None: lgpio.gpio_write(self.handle, self.led_pin, 0) print("LED 已熄灭") def blink(self, times=5, interval=0.5): """LED 闪烁""" for i in range(times): self.turn_on() time.sleep(interval) self.turn_off() time.sleep(interval) def cleanup(self): """清理资源""" if self.handle is not None: lgpio.gpiochip_close(self.handle) self.handle = None print("LED 资源已清理") # 使用示例 if __name__ == "__main__": led = LEDController(led_pin=18) try: if led.init_led(): led.blink(3, 1.0) # 闪烁 3 次,间隔 1 秒 finally: led.cleanup() 示例 2:按钮输入检测 import lgpio import time class ButtonController: def __init__(self, button_pin=23): self.button_pin = button_pin self.handle = None self.last_state = None def init_button(self): """初始化按钮 GPIO""" try: self.handle = lgpio.gpiochip_open(0) if self.handle < 0: return False # 设置为输入模式,启用上拉电阻 lgpio.gpio_claim_input(self.handle, self.button_pin, lgpio.PULL_UP) print(f"按钮初始化成功,引脚: {self.button_pin}") return True except Exception as e: print(f"按钮初始化失败: {e}") return False def read_button(self): """读取按钮状态""" if self.handle is not None: # 读取按钮状态(上拉电阻,按下为 0,松开为 1) state = lgpio.gpio_read(self.handle, self.button_pin) return state == 0 # 返回 True 表示按下 def wait_for_press(self, timeout=None): """等待按钮按下""" start_time = time.time() while True: if self.read_button(): return True if timeout and (time.time() - start_time) > timeout: return False time.sleep(0.01) # 10ms 检测间隔 def cleanup(self): """清理资源""" if self.handle is not None: lgpio.gpiochip_close(self.handle) self.handle = None # 使用示例 if __name__ == "__main__": button = ButtonController(button_pin=23) try: if button.init_button(): print("按下按钮...") if button.wait_for_press(timeout=10): print("按钮已按下!") else: print("等待超时") finally: button.cleanup() 示例 3:舵机控制 import lgpio import time class ServoController: def __init__(self, servo_pin=18): self.servo_pin = servo_pin self.handle = None def init_servo(self): """初始化舵机""" try: self.handle = lgpio.gpiochip_open(0) if self.handle < 0: return False # 设置舵机引脚为输出模式 lgpio.gpio_claim_output(self.handle, self.servo_pin, 0) print(f"舵机初始化成功,引脚: {self.servo_pin}") return True except Exception as e: print(f"舵机初始化失败: {e}") return False def set_angle(self, angle): """设置舵机角度 (0-180度)""" if self.handle is None: print("舵机未初始化") return False try: # 计算脉冲宽度(微秒) min_pulse = 500 # 0.5ms max_pulse = 2500 # 2.5ms pulse_width = min_pulse + (angle / 180.0) * (max_pulse - min_pulse) # 使用 lgpio.tx_servo 控制舵机 lgpio.tx_servo(self.handle, self.servo_pin, int(pulse_width)) # 等待舵机转动 time.sleep(0.5) # 停止 PWM 信号 lgpio.tx_servo(self.handle, self.servo_pin, 0) print(f"舵机已转到 {angle} 度") return True except Exception as e: print(f"设置舵机角度失败: {e}") return False def cleanup(self): """清理资源""" if self.handle is not None: lgpio.tx_servo(self.handle, self.servo_pin, 0) lgpio.gpiochip_close(self.handle) self.handle = None print("舵机资源已清理") # 使用示例 if __name__ == "__main__": servo = ServoController(servo_pin=18) try: if servo.init_servo(): # 舵机转动演示 angles = [0, 45, 90, 135, 180, 90, 0] for angle in angles: servo.set_angle(angle) time.sleep(1) finally: servo.cleanup() 高级功能 PWM 控制 # 设置 PWM 频率和占空比 lgpio.tx_pwm(handle, gpio_pin, frequency, duty_cycle) # 停止 PWM lgpio.tx_pwm(handle, gpio_pin, 0, 0) 中断处理 # 设置 GPIO 中断回调 lgpio.callback(handle, gpio_pin, lgpio.RISING_EDGE, callback_function) 硬件定时器 # 创建硬件定时器 timer = lgpio.timer_start(frequency, callback_function) 注意事项 权限要求:需要 root 权限或 gpio 组权限 引脚冲突:避免使用系统保留的引脚 资源管理:及时清理 GPIO 资源 错误处理:添加适当的异常处理 性能考虑:避免过于频繁的 GPIO 操作 常见问题解决 权限问题 # 将用户添加到 gpio 组 sudo usermod -a -G gpio $USER # 重新登录后生效 引脚被占用 # 查看 GPIO 使用情况 gpioinfo # 释放被占用的引脚 sudo gpio unexportall 性能优化 使用适当的检测间隔 避免在循环中进行不必要的 GPIO 操作 考虑使用中断而不是轮询 总结 lgpio 是一个功能强大、性能优异的 GPIO 控制库,特别适合树莓派等单板计算机的硬件控制项目。通过合理使用其提供的功能,可以实现各种复杂的硬件控制应用。

Hero Image
Docker的使用

Docker 使用 1. Docker基础概念 Image:Image是将运行的程序以及依赖等文件打包在一起。是程序的运行环境。 Container:Container是Image运行后形成的进程,一个Image可以创建1个或多个Container,每个Container之间是相互隔离的。 2. Docker image下载 下载指定平台的docker image sudo docker pull --platform linux/amd64 openjdk:21-jdk-slim` 当一个笔记本上的容器存在多个平台下的版本时,需要使用tag来进行区分 # 拉取 amd64 版本 docker pull --platform linux/amd64 mysql:latest docker tag mysql:latest mysql:amd64 # 拉取 arm 版本 docker pull --platform linux/arm64 mysql:latest docker tag mysql:latest mysql:arm 3. Docker 指令 启动 `sudo docker run -it --name myapp-container -p 8080:8080 myapp:latest /bin/bash` 开机自启动 打开开机自启动 sudo docker update --restart=always 容器名字或ID 关闭开机自启动 sudo docker update --restart=no 容器名字或ID 指定最大重启次数 sudo docker update --restart=on-failure:3 容器名或ID 查询容器自启动状态 sudo docker inspect -f "{{ .HostConfig.RestartPolicy.Name }}" 容器名或ID 4. Docker compose version: "3.8" services: db: image: mysql:latest restart: always environment: MYSQL_ROOT_PASSWORD: ****** # 设置root用户的密码 MYSQL_USER: userName # 创建一个新用户 MYSQL_PASSWORD: userName # 用户的密码 ports: - "3306:3306" # 映射MySQL端口到宿主机的3306端口 5. Docker 部署 本地保存Docker sudo docker save -o java21_x64.tar java21_x64:latest 上传文件到服务器 scp **** 服务器端加载docker `sudo docker load -i java21_x64.tar`

Hero Image
clangd的使用

clang clangd clangd 是一个语言服务器(Language Server),专门为 C/C++ 代码提供智能编辑功能。具有以下功能: 代码补全:智能提示函数、变量、类等 语法检查:实时检查语法错误 代码导航:跳转到定义、查找引用 重构支持:重命名、提取函数等 错误诊断:显示编译错误和警告 clang-format clang-format 是一个代码格式化工具,通过配置简单易懂的格式化选项,可以在保持代码功能不变的情况下,自动处理缩进、空格、括号、逗号等细节,提高代码的可读性和一致性,减轻代码审查和格式化的工作量,使代码维护更加高效。具有以下功能: 代码风格统一:自动调整缩进、空格、换行等 多种预设风格:Google、LLVM、Microsoft 等 自定义配置:支持 .clang-format 配置文件 批量格式化:可以格式化整个文件或代码块 clangd 与 clangd-format 特性 clangd clang-format 主要功能 语言服务器,智能编辑 代码格式化工具 运行方式 后台服务,持续运行 按需执行,一次性 输出结果 代码提示、错误诊断 格式化的代码 配置方式 编辑器集成配置 .clang-format 文件 使用场景 日常代码编辑 代码风格统一s 安装 ubuntu sudo apt-get install clangd sudo apt install clang-format windows LLVM-CLANG下载连接 安装vscode插件 在vscode中使用 在项目根目录或源代码所在目录下创建一个名为.clang-format的文件。 根据自己的编码风格偏好,在.clang-format文件中指定格式化选项,例如缩进、空格、括号风格等。 可以使用官方文档中提供的样式选项或自定义选项来配置文件。 保存.clang-format文件后,clang-format会在格式化代码时自动读取这些选项。 .clang-format文件详解 clang-format文件是用于配置clang-format的文件,采用基于YAML的格式。文件结构包括一系列的键值对,用于定义不同的格式化选项,其中格式化选项可以嵌套使用,形成层级结构。 .clang-format配置文件的常用格式化选项含义如下: --- # 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto Language:Cpp # BasedOnStyle:LLVM # 访问说明符(public、private等)的偏移 AccessModifierOffset:-4 # 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行) AlignAfterOpenBracket:Align # 连续赋值时,对齐所有等号 AlignConsecutiveAssignments:true # 连续声明时,对齐所有声明的变量名 AlignConsecutiveDeclarations:true # 左对齐逃脱换行(使用反斜杠换行)的反斜杠 AlignEscapedNewlinesLeft:true # 水平对齐二元和三元表达式的操作数 AlignOperands:true # 对齐连续的尾随的注释 AlignTrailingComments:true # 允许函数声明的所有参数在放在下一行 AllowAllParametersOfDeclarationOnNextLine:true # 允许短的块放在同一行 AllowShortBlocksOnASingleLine:false # 允许短的case标签放在同一行 AllowShortCaseLabelsOnASingleLine:false # 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All AllowShortFunctionsOnASingleLine:Empty # 允许短的if语句保持在同一行 AllowShortIfStatementsOnASingleLine:false # 允许短的循环保持在同一行 AllowShortLoopsOnASingleLine:false # 总是在定义返回类型后换行(deprecated) AlwaysBreakAfterDefinitionReturnType:None # 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), # AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) AlwaysBreakAfterReturnType:None # 总是在多行string字面量前换行 AlwaysBreakBeforeMultilineStrings:false # 总是在template声明后换行 AlwaysBreakTemplateDeclarations:false # false表示函数实参要么都在同一行,要么都各自一行 BinPackArguments:true # false表示所有形参要么都在同一行,要么都各自一行 BinPackParameters:true # 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 BraceWrapping: # class定义后面 AfterClass:false # 控制语句后面 AfterControlStatement:false # enum定义后面 AfterEnum:false # 函数定义后面 AfterFunction:false # 命名空间定义后面 AfterNamespace:false # ObjC定义后面 AfterObjCDeclaration:false # struct定义后面 AfterStruct:false # union定义后面 AfterUnion:false # catch之前 BeforeCatch:true # else之前 BeforeElse:true # 缩进大括号 IndentBraces:false # 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) BreakBeforeBinaryOperators:NonAssignment # 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), # Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似), # Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom # 注:这里认为语句块也属于函数 BreakBeforeBraces:Custom # 在三元运算符前换行 BreakBeforeTernaryOperators:true # 在构造函数的初始化列表的逗号前换行 BreakConstructorInitializersBeforeComma:false # 每行字符的限制,0表示没有限制 ColumnLimit:200 # 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 CommentPragmas:'^ IWYU pragma:' # 构造函数的初始化列表要么都在同一行,要么都各自一行 ConstructorInitializerAllOnOneLineOrOnePerLine:false # 构造函数的初始化列表的缩进宽度 ConstructorInitializerIndentWidth:4 # 延续的行的缩进宽度 ContinuationIndentWidth:4 # 去除C++11的列表初始化的大括号{后和}前的空格 Cpp11BracedListStyle:false # 继承最常用的指针和引用的对齐方式 DerivePointerAlignment:false # 关闭格式化 DisableFormat:false # 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) ExperimentalAutoDetectBinPacking:false # 需要被解读为foreach循环而不是函数调用的宏 ForEachMacros:[ foreach, Q_FOREACH, BOOST_FOREACH ] # 对#include进行排序,匹配了某正则表达式的#include拥有对应的优先级,匹配不到的则默认优先级为INT_MAX(优先级越小排序越靠前), # 可以定义负数优先级从而保证某些#include永远在最前面 IncludeCategories: - Regex:'^"(llvm|llvm-c|clang|clang-c)/' Priority:2 - Regex:'^(<|"(gtest|isl|json)/)' Priority:3 - Regex:'.*' Priority:1 # 缩进case标签 IndentCaseLabels:false # 缩进宽度 IndentWidth:4 # 函数返回类型换行时,缩进函数声明或函数定义的函数名 IndentWrappedFunctionNames:false # 保留在块开始处的空行 KeepEmptyLinesAtTheStartOfBlocks:true # 开始一个块的宏的正则表达式 MacroBlockBegin:'' # 结束一个块的宏的正则表达式 MacroBlockEnd:'' # 连续空行的最大数量 MaxEmptyLinesToKeep:1 # 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All NamespaceIndentation:Inner # 使用ObjC块时缩进宽度 ObjCBlockIndentWidth:4 # 在ObjC的@property后添加一个空格 ObjCSpaceAfterProperty:false # 在ObjC的protocol列表前添加一个空格 ObjCSpaceBeforeProtocolList:true # 在call(后对函数调用换行的penalty PenaltyBreakBeforeFirstCallParameter:19 # 在一个注释中引入换行的penalty PenaltyBreakComment:300 # 第一次在<<前换行的penalty PenaltyBreakFirstLessLess:120 # 在一个字符串字面量中引入换行的penalty PenaltyBreakString:1000 # 对于每个在行字符数限制之外的字符的penalty PenaltyExcessCharacter:1000000 # 将函数的返回类型放到它自己的行的penalty PenaltyReturnTypeOnItsOwnLine:60 # 指针和引用的对齐: Left, Right, Middle PointerAlignment:Left # 允许重新排版注释 ReflowComments:true # 允许排序#include SortIncludes:true # 在C风格类型转换后添加空格 SpaceAfterCStyleCast:false # 在赋值运算符之前添加空格 SpaceBeforeAssignmentOperators:true # 开圆括号之前添加一个空格: Never, ControlStatements, Always SpaceBeforeParens:ControlStatements # 在空的圆括号中添加空格 SpaceInEmptyParentheses:false # 在尾随的评论前添加的空格数(只适用于//) SpacesBeforeTrailingComments:2 # 在尖括号的<后和>前添加空格 SpacesInAngles:true # 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 SpacesInContainerLiterals:true # 在C风格类型转换的括号中添加空格 SpacesInCStyleCastParentheses:true # 在圆括号的(后和)前添加空格 SpacesInParentheses:true # 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 SpacesInSquareBrackets:true # 标准: Cpp03, Cpp11, Auto Standard:Cpp11 # tab宽度 TabWidth:4 # 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always UseTab:Never ... 如果不需要重新定义所有的规则,而是基于已有的代码风格模板进行修改,可以使用BasedOnStyle标识来进行部分格式规则的重定义: --- # We'll use defaults from the LLVM style, but with 4 columns indentation. BasedOnStyle: LLVM IndentWidth: 4 --- Language: Cpp # Force pointers to the type for C++. DerivePointerAlignment: false PointerAlignment: Left --- Language: JavaScript # Use 100 columns for JS. ColumnLimit: 100 --- Language: Proto # Don't format .proto files. DisableFormat: true --- Language: CSharp # Use 100 columns for C#. ColumnLimit: 100 ... 如果代码文件中有部分代码不希望采用.clang-format进行格式化,可以在这部分代码块的前后使用如下的注释进行标识: // clang-format off 这两个注释中间的代码不受clang-format的影响 // clang-format on 参考文章 ClangFormat

Hero Image
github 使用语法

github 语法流程图 本地初始化仓库 git init git add README.md git commit -m "first commit" git branch -M main git remote add origin git@github.com:user_name/test_init.git git push -u origin main 推送现有仓库到远程仓库 git remote add origin git@github.com:user_name/test_init.git git branch -M main git push -u origin main 克隆远程仓库到本地 git clone git@github.com:user_name/test_init.git 仓库管理 git init # 初始化新的Git仓库 git clone <url> # 克隆远程仓库 git remote add origin <url> # 添加远程仓库 git remote -v # 查看远程仓库 推送与拉取 git push origin <branch> # 推送到远程分支 git push -u origin <branch> # 设置上游分支并推送 git pull origin <branch> # 从远程拉取并合并 git fetch origin # 获取远程更新 git fetch --all # 获取所有远程更新 状态查看 git status # 查看工作区状态 git status -s # 简短格式显示状态 git log # 查看提交历史 git log --oneline -n # 单行显示最近n条提交历史 git log --graph # 图形化显示分支历史 git diff # 查看工作区与暂存区的差异 git diff --staged # 查看暂存区与HEAD的差异 文件操作 git add <file> # 添加文件到暂存区 git add . # 添加所有文件到暂存区 git add *.c # 添加所有.c文件 git rm <file> # 将文件从暂存区和工作区中删除 git rm --cashed <file> # 将文件从暂存区删除,工作区得以保留 git rm -f <file> # 将文件从暂存区和工作区中删除 git mv <old> <new> # 重命名文件 git checkout -- <file> # 从最近的一次提交中恢复文件,撤销工作区的修改,如果该文件曾经提交到 暂存区,则暂存区中的文件不受影响 git restore <file> # 恢复特定文件到暂存区状态 git restore . # 恢复所有文件到暂存区状态 提交管理 git commit -m "消息" # 提交更改 git commit -am "消息" # 添加并提交已跟踪的文件 git commit --amend # 打开编辑器,修改最后一次提交 git commit --amend -m "消息" # 直接修改最后一次提交 git reset HEAD <file> # 工作区不变,将本地仓库和暂存区修改到指定的<commit-hash> git reset --soft <commit-hash> # 暂存区,工作区不变,将本地仓库修改到指定的<commit-hash> git reset --hard HEAD # 完全重置到最后一次提交,暂存区,工作区,本地仓库均变化 分支管理 git branch # 查看本地分支 git branch -a # 查看所有分支,本地和远程 git branch <name> # 创建新分支 git checkout <branch> # 切换到指定分支 git checkout -b <name> # 创建并切换到新分支 git branch -d <name> # 删除分支 git branch -m <old> <new> # 重命名分支 合并与变基 git merge <branch> # 合并当前分支到<branch>分支,在流程图中有交叉 git rebase <branch> # 变基操作,将当前分支合并到<branch>分支,在流程图中没有交叉 git cherry-pick <commit-hash> # 将特定的<commit-hash>提交从一个分支引入到当前分支 标签管理 git tag # 查看所有标签 git tag <name> # 创建标签 git tag -a <name> -m "消息" # 创建带注释的标签 git push origin --tags # 推送所有标签 搜索查看 git show <commit> # 显示指定提交的详细信息 git blame <file> # 查看文件的每一行是谁修改的 git grep "关键词" # 在仓库中搜索关键词 git log -S "关键词" # 搜索包含关键词的提交 清理维护 git clean -n # 预览要清理的文件 git clean -f # 强制清理未跟踪的文件 git gc # 垃圾回收 git prune # 清理孤立的提交 stash操作 git stash # 将工作区,暂存区放置到 stash 区域,会删除工作区,暂存区的修改 git stash list # 查看 stash 列表 git stash pop <commit-hash> # 将stash区域保存的<commit-hash>状态恢复到工作区,暂存区,并删除该stash状态 git stash apply <commit-hash> # 将stash区域保存的<commit-hash>状态恢复到工作区,暂存区,不删除该stash状态

Hero Image
在无显示屏状态下使用vnc登录树莓派

在树莓派上通过sd卡设置固定ip地址 安装操作系统 按照前序文章将操作系统安装到SD卡上。 如果树莓派不连接显示器,也无法连接鼠标键盘,此时我们可以在SD卡中直接设置固定IP地址以方便后续通过VNC-Viewer登录。 设置IP地址 将SD卡通过读卡器连接到电脑,直接打开SD卡,使用记事本打开cmdline.txt文件,在文件末尾增加 ip=192.168.1.200::192.168.1.1:255.255.255.0:rpi:eth0:off,需要注意的是在新增的内容前有一个空格。 修改完成之后将SD卡插入树莓派中,启动树莓派。 ssh登录 在windows上打开终端(如下图所示),通过指令登录树莓派 ssh登录树莓派 在终端输入以下指令登录树莓派 ssh rpi@192.168.1.200 # 回车后,如果需要输入密码,则输入密码即可,在输入过程中密码是不可见的,输入完密码,直接回车即可 如果在登陆时,如果提示REMOTE HOST IDENTIFICATION HAS CHANGED!,说明之前连接过相同IP地址,但不是当前设备。此时需要删除已经存在的host。 删除已经存在的host 在图示路径下打开known_hosts文件,删除我们访问的ip地址以及后面的公钥指纹。 配置VNC 开启VNC 成功登录树莓派后,在终端执行以下指令,并按照图示进行选择 sudo raspi-config 切换到x11服务 设置VNC分辨率 以上配置结束后,记得重新启动树莓派,以让所有配置生效 vnc-viewer 登录 经过测试,推荐使用VNC-VIEWER。 vncview 下载地址 mobaxterm下载地址 mobaxterm备用下载地址 VNC登录 使用 vnc-viewer ,输入树莓派IP地址,按照过程输入安装过程中设置的用户名以及密码即可。 帮助 如果vnc连接后打开的为灰色屏幕 # 使用 SSH 登录树莓派,输入以下指令查看 x11 服务是否启用 sudo systemctl status vncserver-x11-serviced.service # 如果没有启用,则输入以下指令启用 sudo systemctl enable vncserver-x11-serviced.service sudo systemctl start vncserver-x11-serviced.service