init commit
|
@ -0,0 +1,378 @@
|
||||||
|
##
|
||||||
|
## PROJECT: Mouri Internal Library Essentials
|
||||||
|
## FILE: .gitignore
|
||||||
|
## PURPOSE: The root .gitignore file for Mile.Project Project
|
||||||
|
##
|
||||||
|
## LICENSE: The MIT License
|
||||||
|
##
|
||||||
|
## DEVELOPER: Mouri_Naruto (Mouri_Naruto AT Outlook.com)
|
||||||
|
##
|
||||||
|
|
||||||
|
##
|
||||||
|
## Ignore Mile.Project specific temporary files, build results,
|
||||||
|
## and files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
Output/
|
||||||
|
|
||||||
|
##
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
|
@ -0,0 +1,25 @@
|
||||||
|
**Fusion360 使用教程**
|
||||||
|
|
||||||
|
## **一、场景基本的控制**
|
||||||
|
|
||||||
|
**1.1 场景的旋转:**Shift + 鼠标左键
|
||||||
|
|
||||||
|
## 二、工具的基本使用
|
||||||
|
|
||||||
|
**2.1 曲面工具:**
|
||||||
|
|
||||||
|
通过二维的轮廓,然后360°旋转所生成的实体。需要指定1)旋转轴 2)轮廓 两个信息实现曲面的生成。
|
||||||
|
|
||||||
|
## **三、模型的导出**
|
||||||
|
|
||||||
|
fusion360采用的是项目管理的方式,在下图中我们可以看到有Admin Project和BalanceCar两个项目,这些项目默认是云端同步的。
|
||||||
|
|
||||||
|
<img src="./Image/Project_All.png" alt="image-20220917192141176" style="zoom:33%;" />
|
||||||
|
|
||||||
|
在项目中选择模型,右键选择导出可以导出Fusion360的文件格式。
|
||||||
|
|
||||||
|
<img src="./Image/Project_BalanceCar.png" alt="image-20220917192224716" style="zoom:45%;" />
|
||||||
|
|
||||||
|
在导出对话框中可以将模型导出到本地文件夹
|
||||||
|
|
||||||
|
<img src="./Image/Model_Export.png" alt="image-20220917192246893" style="zoom:33%;" />
|
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 42 KiB |
|
@ -0,0 +1,176 @@
|
||||||
|
# Kotlin调用Jni的写法
|
||||||
|
|
||||||
|
## 一、安装CMake和NDK
|
||||||
|
|
||||||
|
在android studio的设置中安装Cmake,安装Cmake的时候注意cmake的版本。如果忘记CMake的版本,那么可以通过Android SDK Locatio目录中查看CMake的版本。如下图所示的CMake和NDK。
|
||||||
|
|
||||||
|
![image-20230221221558825](E:\技术武器库\技术开发笔记\Android开发笔记\Image\image-20230221221558825.png)
|
||||||
|
|
||||||
|
## 二、创建工程
|
||||||
|
|
||||||
|
选择一个带 Native C++ 支持的工程,如下图所示:
|
||||||
|
|
||||||
|
![image-20230221223742943](E:\技术武器库\技术开发笔记\Android开发笔记\Image\image-20230221223742943.png)
|
||||||
|
|
||||||
|
## 三、配置 ndk 目录
|
||||||
|
|
||||||
|
在文件 local.properties 中加入 ndk 的配置
|
||||||
|
|
||||||
|
## 四、目录结构
|
||||||
|
|
||||||
|
以下文件都是自动生成的
|
||||||
|
|
||||||
|
![image-20230221223834839](E:\技术武器库\技术开发笔记\Android开发笔记\Image\image-20230221223834839.png)
|
||||||
|
|
||||||
|
## 五、配置模块 build.gradle
|
||||||
|
|
||||||
|
```shell
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 29
|
||||||
|
buildToolsVersion "29.0.2"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.lujianfei.androidjnicall"
|
||||||
|
minSdkVersion 26
|
||||||
|
targetSdkVersion 29
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
cppFlags ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path "src/main/cpp/CMakeLists.txt"
|
||||||
|
version "3.10.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
|
||||||
|
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
|
implementation 'androidx.core:core-ktx:1.2.0'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 六、配置CMakeLists.txt和native-lib.cpp
|
||||||
|
|
||||||
|
```
|
||||||
|
# For more information about using CMake with Android Studio, read the
|
||||||
|
# documentation: https://d.android.com/studio/projects/add-native-code.html
|
||||||
|
|
||||||
|
# Sets the minimum version of CMake required to build the native library.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.4.1)
|
||||||
|
|
||||||
|
# Creates and names a library, sets it as either STATIC
|
||||||
|
# or SHARED, and provides the relative paths to its source code.
|
||||||
|
# You can define multiple libraries, and CMake builds them for you.
|
||||||
|
# Gradle automatically packages shared libraries with your APK.
|
||||||
|
|
||||||
|
add_library( # Sets the name of the library.
|
||||||
|
native-lib
|
||||||
|
|
||||||
|
# Sets the library as a shared library.
|
||||||
|
SHARED
|
||||||
|
|
||||||
|
# Provides a relative path to your source file(s).
|
||||||
|
native-lib.cpp )
|
||||||
|
|
||||||
|
# Searches for a specified prebuilt library and stores the path as a
|
||||||
|
# variable. Because CMake includes system libraries in the search path by
|
||||||
|
# default, you only need to specify the name of the public NDK library
|
||||||
|
# you want to add. CMake verifies that the library exists before
|
||||||
|
# completing its build.
|
||||||
|
|
||||||
|
find_library( # Sets the name of the path variable.
|
||||||
|
log-lib
|
||||||
|
|
||||||
|
# Specifies the name of the NDK library that
|
||||||
|
# you want CMake to locate.
|
||||||
|
log )
|
||||||
|
|
||||||
|
# Specifies libraries CMake should link to your target library. You
|
||||||
|
# can link multiple libraries, such as libraries you define in this
|
||||||
|
# build script, prebuilt third-party libraries, or system libraries.
|
||||||
|
|
||||||
|
target_link_libraries( # Specifies the target library.
|
||||||
|
native-lib
|
||||||
|
|
||||||
|
# Links the target library to the log library
|
||||||
|
# included in the NDK.
|
||||||
|
${log-lib} )
|
||||||
|
```
|
||||||
|
|
||||||
|
```C++
|
||||||
|
#include <jni.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jstring JNICALL
|
||||||
|
Java_com_lujianfei_androidjnicall_MainActivity_stringFromJNI(
|
||||||
|
JNIEnv* env,
|
||||||
|
jobject /* this */) {
|
||||||
|
std::string hello = "Hello from C++";
|
||||||
|
return env->NewStringUTF(hello.c_str());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 七、Activity调用
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
package com.lujianfei.androidjnicall
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import android.os.Bundle
|
||||||
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
// Example of a call to a native method
|
||||||
|
sample_text.text = stringFromJNI()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A native method that is implemented by the 'native-lib' native library,
|
||||||
|
* which is packaged with this application.
|
||||||
|
*/
|
||||||
|
external fun stringFromJNI(): String
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// Used to load the 'native-lib' library on application startup.
|
||||||
|
init {
|
||||||
|
System.loadLibrary("native-lib")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 173 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 26 KiB |
|
@ -0,0 +1,103 @@
|
||||||
|
# 安卓开发环境配置问题
|
||||||
|
|
||||||
|
## 一、gradle的问题
|
||||||
|
|
||||||
|
由于国内网络环境的问题,导致gradle经常没有办法正常下载,从而难以正常构建Android程序。
|
||||||
|
|
||||||
|
## 1.1 gradle下载失败的问题
|
||||||
|
|
||||||
|
Android Studio首次创建项目或其他操作时,会更新Gradle,由于一些原因会导致下载失败,就会提示ERROR:Gradle project sync failed。解决办法如下:
|
||||||
|
1.根据报错提示的链接直接下载gradle-xxxxx.zip,可以通过浏览器在 https://services.gradle.org/distributions/ 下载对应的版本。
|
||||||
|
|
||||||
|
![image-20231124132205455](./Image/image-20231124132205455.png)
|
||||||
|
|
||||||
|
如上图所示,可以看到Android Studio正在下载gradle-8.0-bin.zip, 如果反复失败,可以通过上面的网址直接通过浏览器下载(如果不能访问可能需要使用科学上网),在网页中,我们可以找到对应的下载链接。:
|
||||||
|
|
||||||
|
<img src="./Image/image-20231124132430205.png" alt="image-20231124132430205" style="zoom: 50%;" />
|
||||||
|
|
||||||
|
2.虽然AndroidStudio Gradle下载失败,但是会在你的C盘创建一个文件夹,如 C:\Users(你的用户名).gradle\wrapper\dists\gradle-6.5-bin\xxxxxxx(最后一级目录,每个人的文件名可能不一样)
|
||||||
|
|
||||||
|
<img src="/Image/image-20231124132703141.png" alt="image-20231124132703141" style="zoom:50%;" />
|
||||||
|
|
||||||
|
我们将步骤1中下载号的gradle-8.0-bin.zip复制到存在gradle-8.0-bin.zip.lck和gradle-8.0-bin.zip.part文件的文件夹中。
|
||||||
|
|
||||||
|
3.修改Android Studio的gradle-wrapper文件
|
||||||
|
|
||||||
|
<center>
|
||||||
|
<img src="./Image/image-20231124133122986.png" alt="image-20231124133122986" style="zoom:50%;" />
|
||||||
|
</center>
|
||||||
|
|
||||||
|
修改的方式如下,不同环境下路径存在不同,根据实际情况调整即可,重要的是要正确映射gradle的位置。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Fri Nov 24 11:56:39 CST 2023
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
# 这是修改后的distributionUrl,把原先的网络地址映射为本地地址,程序通过本地地址下载
|
||||||
|
distributionUrl=file:///C:/Users/admin/.gradle/wrapper/dists/gradle-8.0-bin/ca5e32bp14vu59qr306oxotwh/gradle-8.0-bin.zip
|
||||||
|
# 下面是原地址
|
||||||
|
#distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
```
|
||||||
|
|
||||||
|
4.最后,重启AndroidStudio或者点击Sync Now就可以了。
|
||||||
|
|
||||||
|
## 二、Maven仓库配置问题
|
||||||
|
|
||||||
|
目前最新版本的Android Studio的依赖配置和旧版本不太一样。一般来说,如果采用默认的仓库配置,下载速度过慢同时容易失败。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 旧版
|
||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
//新增这 4 个
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/jcenter/' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/central/' }
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
|
repositories {
|
||||||
|
//新增这 4 个
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/jcenter/' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/central/' }
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "helloworld"
|
||||||
|
include ':app'
|
||||||
|
# 最新版 maven写法发生了改变 maven { url 'https://jitpack.io' } => maven { url = uri("https://jitpack.io") }
|
||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/public/") }
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/google/") }
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/jcenter/") }
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/central/") }
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
|
repositories {
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/public/") }
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/google/") }
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/jcenter/") }
|
||||||
|
maven { url = uri("https://maven.aliyun.com/repository/central/") }
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
## Android引入其他工程
|
||||||
|
|
||||||
|
在安卓开发中,我们为了开发方便,所以需要引入其他的已经封装好的模块。如下所示:
|
||||||
|
|
||||||
|
<img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230211150717050.png" alt="image-20230211150717050" style="zoom: 50%;" />
|
||||||
|
|
||||||
|
在app工程中,需要用到libsmb库提供的smb管理和访问的功能。需要在两个地方进行配置。首先是app工程目录下的settings.gradle中配置。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# settings.gradle的配置,是编译器包含libsmb
|
||||||
|
rootProject.name = "My Application"
|
||||||
|
include ':app'
|
||||||
|
include ':libsmb'
|
||||||
|
# 在build.gradle中添加依赖选项
|
||||||
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
...
|
||||||
|
implementation project(':libsmb')
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
## Android 播放器使用
|
||||||
|
|
||||||
|
### 一、调用第三方视频播放器
|
||||||
|
|
||||||
|
Android通过Intent调用第三方播放器,通过Url播放视频。
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 启动第三方播放器
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.setAction(android.content.Intent.ACTION_VIEW);
|
||||||
|
intent.setDataAndType(Uri.parse(http), "video/*");
|
||||||
|
startActivity(intent);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 二、Exo播放器的使用
|
|
@ -0,0 +1,173 @@
|
||||||
|
# Android 线程池ThreadPoolExecutor 的使用和封装(kotlin)
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 传统开启线程方式
|
||||||
|
Thread(Runnable {
|
||||||
|
//to do异步请求
|
||||||
|
|
||||||
|
}).start()
|
||||||
|
```
|
||||||
|
|
||||||
|
**1.使用new Thread()创建线程存在的问题**
|
||||||
|
|
||||||
|
1. 如果在一个list每一个item都创建一个Thread,list量大的话会大量创建Thread,导致内存抖动,GC频繁的回收。要知道,GC的回收是在主线程的,这样会导致卡顿。
|
||||||
|
|
||||||
|
2. 线程过多,导致各个线程竞争抢夺CPU执行权,线程的频繁切换导致效率的降低。
|
||||||
|
|
||||||
|
3. ListView的每一个item滑出窗口,线程无法停止也无法控制。
|
||||||
|
|
||||||
|
|
||||||
|
**2.使用线程池的好处**
|
||||||
|
|
||||||
|
1. 重用已经创建的好的线程,避免频繁创建进而导致的频繁GC
|
||||||
|
2. 控制线程并发数,合理使用系统资源,提高应用性能
|
||||||
|
3. 可以有效的控制线程的执行,比如定时执行,取消执行等
|
||||||
|
|
||||||
|
**3.创建线程池 ThreadPoolExecutor 7个参数**
|
||||||
|
|
||||||
|
- corePoolSize 线程池中核心线程的数量
|
||||||
|
|
||||||
|
- maximumPoolSize 线程池中最大线程数量,等待队列的任务塞满了之后,才会触发开启非核心线程,直到总线程数达到 maximumPoolSize
|
||||||
|
|
||||||
|
- keepAliveTime 非核心线程的超时时长,当系统中非核心线程闲置时间超过keepAliveTime之后,则会被回收。如果ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,则该参数也作用于核心线程的超时时长
|
||||||
|
|
||||||
|
- unit 第三个参数的单位,有纳秒、微秒、毫秒、秒、分、时、天等
|
||||||
|
|
||||||
|
- workQueue 线程池中的任务队列,该队列主要用来存储已经被提交但是尚未执行的任务。存储在这里的任务是由ThreadPoolExecutor的execute方法提交来的。这个队列任务塞满了之后,才会触发开启非核心线程
|
||||||
|
|
||||||
|
- threadFactory 为线程池提供创建新线程的功能,这个我们一般使用默认即可
|
||||||
|
|
||||||
|
- handler 拒绝策略,当线程无法执行新任务时(一般是由于线程池中的线程数量已经达到最大数或者线程池关闭导致的),默认情况下,当线程池无法处理新线程时,会抛出一个RejectedExecutionException。
|
||||||
|
|
||||||
|
**4.线程池 ThreadPoolExecutor 的方法**
|
||||||
|
|
||||||
|
1. shutDown() 关闭线程池,不影响已经提交的任务
|
||||||
|
|
||||||
|
2. shutDownNow() 关闭线程池,并尝试去终止正在执行的线程
|
||||||
|
|
||||||
|
3. allowCoreThreadTimeOut(boolean value) 允许核心线程闲置超时时被回收
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
|
||||||
|
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import java.util.concurrent.*
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Created by LiangJingJie on 2019/5/16.
|
||||||
|
* 线程池封装类
|
||||||
|
* */
|
||||||
|
class ThreadPoolManager private constructor() {
|
||||||
|
|
||||||
|
private var threadPoolMap = hashMapOf<String, ThreadPoolExecutor>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu数量
|
||||||
|
* */
|
||||||
|
private val CPU_COUNT = Runtime.getRuntime().availableProcessors()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心线程数为手机CPU数量+1
|
||||||
|
* */
|
||||||
|
private val CORE_POOL_SIZE = CPU_COUNT + 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大线程数为手机CPU数量×2+1
|
||||||
|
* */
|
||||||
|
private val MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程活跃时间 秒,超时线程会被回收
|
||||||
|
* */
|
||||||
|
private val KEEP_ALIVE_TIME: Long = 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待队列大小
|
||||||
|
* */
|
||||||
|
private val QUEUE_SIZE = 128
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getInstance() = SingleHolder.SINGLE_HOLDER
|
||||||
|
}
|
||||||
|
|
||||||
|
object SingleHolder {
|
||||||
|
val SINGLE_HOLDER = ThreadPoolManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tag 针对每个TAG 获取对应的线程池
|
||||||
|
* @param corePoolSize 线程池中核心线程的数量
|
||||||
|
* @param maximumPoolSize 线程池中最大线程数量
|
||||||
|
* @param keepAliveTime 非核心线程的超时时长,
|
||||||
|
* 当系统中非核心线程闲置时间超过keepAliveTime之后,则会被回收
|
||||||
|
* 如果ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,
|
||||||
|
则该参数也作用于核心线程的超时时长
|
||||||
|
* @param unit 第三个参数的单位,有纳秒、微秒、毫秒、秒、分、时、天等
|
||||||
|
* @param queueSize 等待队列的长度 一般128 (参考 AsyncTask)
|
||||||
|
* workQueue 线程池中的任务队列,
|
||||||
|
该队列主要用来存储已经被提交但是尚未执行的任务。
|
||||||
|
存储在这里的任务是由ThreadPoolExecutor的execute方法提交来的。
|
||||||
|
* threadFactory 为线程池提供创建新线程的功能,这个我们一般使用默认即可
|
||||||
|
*
|
||||||
|
* 1.ArrayBlockingQueue:这个表示一个规定了大小的BlockingQueue,ArrayBlockingQueue的构造函数接受一个int类型的数据,
|
||||||
|
* 该数据表示BlockingQueue的大小,存储在ArrayBlockingQueue中的元素按照FIFO(先进先出)的方式来进行存取。
|
||||||
|
* 2.LinkedBlockingQueue:这个表示一个大小不确定的BlockingQueue,在LinkedBlockingQueue的构造方法中可以传
|
||||||
|
* 一个int类型的数据,这样创建出来的LinkedBlockingQueue是有大小的,也可以不传,不传的话,
|
||||||
|
* LinkedBlockingQueue的大小就为Integer.MAX_VALUE
|
||||||
|
* */
|
||||||
|
private fun getThreadPool(tag: String): ThreadPoolExecutor {
|
||||||
|
var threadPoolExecutor = threadPoolMap[tag]
|
||||||
|
if (threadPoolExecutor == null) {
|
||||||
|
threadPoolExecutor = ThreadPoolExecutor(
|
||||||
|
CORE_POOL_SIZE,
|
||||||
|
MAXIMUM_POOL_SIZE,
|
||||||
|
KEEP_ALIVE_TIME,
|
||||||
|
TimeUnit.SECONDS,
|
||||||
|
ArrayBlockingQueue<Runnable>(QUEUE_SIZE),
|
||||||
|
Executors.defaultThreadFactory(),
|
||||||
|
RejectedExecutionHandler { _, _ ->
|
||||||
|
Logger.d("$ThreadPoolManager RejectedExecutionHandler----")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
//允许核心线程闲置超时时被回收
|
||||||
|
threadPoolExecutor.allowCoreThreadTimeOut(true)
|
||||||
|
threadPoolMap[tag] = threadPoolExecutor
|
||||||
|
}
|
||||||
|
return threadPoolExecutor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tag 针对每个TAG 获取对应的线程池
|
||||||
|
* @param runnable 对应的 runnable 任务
|
||||||
|
* */
|
||||||
|
fun removeTask(tag: String, runnable: Runnable) {
|
||||||
|
getThreadPool(tag)?.queue?.remove(runnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tag 针对每个TAG 获取对应的线程池
|
||||||
|
* @param runnable 对应的 runnable 任务
|
||||||
|
* */
|
||||||
|
fun addTask(tag: String, runnable: Runnable) {
|
||||||
|
getThreadPool(tag).execute(runnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tag 针对每个TAG 获取对应的线程池
|
||||||
|
* 取消 移除线程池
|
||||||
|
* */
|
||||||
|
|
||||||
|
//shutDown():关闭线程池后不影响已经提交的任务
|
||||||
|
//shutDownNow():关闭线程池后会尝试去终止正在执行任务的线程
|
||||||
|
fun exitThreadPool(tag: String) {
|
||||||
|
var threadPoolExecutor = threadPoolMap[tag]
|
||||||
|
if (threadPoolExecutor != null) {
|
||||||
|
threadPoolExecutor.shutdownNow()
|
||||||
|
threadPoolMap.remove(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
```java
|
||||||
|
// 给定视频的URL
|
||||||
|
final String url = videoUrl;
|
||||||
|
// 调用Android的MediaMetadataRetriever获取视频封面
|
||||||
|
final MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||||
|
new Thread(() -> {
|
||||||
|
Map<String, String> headers = new HashMap<>() ;
|
||||||
|
// 指定header和url
|
||||||
|
mmr.setDataSource(url, headers);
|
||||||
|
// 设置截取视频第10秒钟内容
|
||||||
|
Long sec = 10L;
|
||||||
|
// sec转us单位
|
||||||
|
Long msec = sec * 1000L;
|
||||||
|
Long us = msec * 1000L;
|
||||||
|
|
||||||
|
final Bitmap image = mmr.getFrameAtTime(us, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
|
||||||
|
// 更新imageview显示图片
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
ImageView tv = findViewById(R.id.imageView);
|
||||||
|
tv.setImageBitmap(image);
|
||||||
|
});
|
||||||
|
// 释放mmr,断开连接
|
||||||
|
mmr.release();
|
||||||
|
}).start();
|
||||||
|
```
|
||||||
|
|
||||||
|
HTTP视频请求Range的计算方法
|
|
@ -0,0 +1,16 @@
|
||||||
|
app : 程序的主页面(MainActivity),程序的启动页面(SplashActivity)
|
||||||
|
|
||||||
|
AppConfig模块 :负责App的功能设置
|
||||||
|
|
||||||
|
**播放器显示控制器逻辑:**
|
||||||
|
|
||||||
|
DanDanVideoPlayer -> onKeyDown检测KeyEvent事件类型 -> {1、音量加 2、音量减 3、其他 : 触发控制View}
|
||||||
|
|
||||||
|
DanDanVideoPlayer -> 触摸检测 检测TouchEvent事件类型 -> {左上下滑动:亮度 右上下滑动:音量 横向滑动:视频进度}
|
||||||
|
|
||||||
|
自动更新功能:BaseApplication(应用启动时的单例) => EMASHelper(阿里巴巴EMAS应用研发平台) => 发起弹窗和下载
|
||||||
|
|
||||||
|
**SMB文件浏览逻辑:**
|
||||||
|
|
||||||
|
位置:local_component/ui/fragment/media/MediaFragment
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
# DanDanPlay主页显示
|
||||||
|
|
||||||
|
## HomeFragmentViewModel
|
||||||
|
|
||||||
|
**位置:**anime_component/ui/fragment/home/HomeFragment
|
||||||
|
|
||||||
|
**核心:** 首页的显示Fragement
|
||||||
|
|
||||||
|
# MediaFragment
|
||||||
|
|
||||||
|
**位置:**local_component/ui/fragment/meda/MediaFragment
|
||||||
|
|
||||||
|
核心:主页媒体的显示Fragement
|
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 116 KiB |
After Width: | Height: | Size: 116 KiB |
|
@ -0,0 +1,61 @@
|
||||||
|
# Kotlin 操作Layout控件
|
||||||
|
|
||||||
|
在Android Acitivity开发中,传统的java开发中findviewbyid。在kotlin中,有两种写法都可以操作layout控件。
|
||||||
|
|
||||||
|
## 一、传统写法(不推荐)
|
||||||
|
|
||||||
|
不推荐的原因主要是麻烦,满屏幕都是findViewById,非常的繁琐。
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
package com.geek.motion
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
var textView = findViewById<TextView>(R.id.textView)
|
||||||
|
textView.setText("Hello Kotlin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 二、省略写法(推荐)
|
||||||
|
|
||||||
|
下面采用的是省略写法,注意需要引入import kotlinx.android.synthetic.main.activity_main.*
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
package com.geek.motion
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import android.os.Bundle
|
||||||
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
textView.text = "Hello kotlin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
如果在引用import kotlinx.android.synthetic.main.activity_main.*时报错,注意在build.gradle中,添加:**'kotlin-android-extensions'**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
plugins {
|
||||||
|
id 'com.android.application'
|
||||||
|
id 'org.jetbrains.kotlin.android'
|
||||||
|
// 添加
|
||||||
|
id 'kotlin-android-extensions'
|
||||||
|
}
|
||||||
|
android {
|
||||||
|
compileSdk 32
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
```kotlin
|
||||||
|
Unit : 相当于JAVA的void
|
||||||
|
```
|
||||||
|
|
||||||
|
kotlin中when的用法
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun foo(value: Int): String {
|
||||||
|
return when (value) {
|
||||||
|
0 -> {
|
||||||
|
"Zero"
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
"One"
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
"Two"
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
"Other"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
# Kotlin测量经过的时间
|
||||||
|
|
||||||
|
## 一、使用 `System.nanoTime()` 功能
|
||||||
|
|
||||||
|
在 Kotlin 中测量程序运行时间的推荐方法是 `System.nanoTime()`,它以纳秒精度返回 JVM 时间源的当前值。
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun main() {
|
||||||
|
val begin = System.nanoTime()
|
||||||
|
/* 代码开始 */
|
||||||
|
// 休眠 2 秒
|
||||||
|
Thread.sleep(2000)
|
||||||
|
/* 代码结束 */
|
||||||
|
val end = System.nanoTime()
|
||||||
|
println("Elapsed time in nanoseconds: ${end-begin}")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 二、使用 `System.currentTimeMillis()` 功能
|
||||||
|
|
||||||
|
您还可以使用 `System.currentTimeMillis()`,但结果可能不是那么准确。
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val begin = System.currentTimeMillis()
|
||||||
|
/* 代码开始 */
|
||||||
|
// 休眠 2 秒
|
||||||
|
Thread.sleep(2000)
|
||||||
|
/* 代码结束 */
|
||||||
|
val end = System.currentTimeMillis()
|
||||||
|
println("Elapsed time in milliseconds: ${end-begin}")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这是使用的替代解决方案 `Instant.now()` 内部使用 `System.currentTimeMillis()`.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val begin = Instant.now().toEpochMilli()
|
||||||
|
/* 代码开始 */
|
||||||
|
// 休眠 2 秒
|
||||||
|
Thread.sleep(2000)
|
||||||
|
/* 代码结束 */
|
||||||
|
val end = Instant.now().toEpochMilli()
|
||||||
|
println("Elapsed time in milliseconds: ${end-begin}")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 三.使用 `Date.getTime()` 功能
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val begin = Date().time
|
||||||
|
/* 代码开始 */
|
||||||
|
// 休眠 2 秒
|
||||||
|
Thread.sleep(2000)
|
||||||
|
/* 代码结束 */
|
||||||
|
val end = Date().time
|
||||||
|
println("Elapsed time in milliseconds: ${end-begin}")
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
## Android Smb开发笔记
|
||||||
|
|
||||||
|
### 一、SMB的基本操作
|
||||||
|
|
||||||
|
Android的SMB开发会用到jcifs这个库。这个库提供了SMB的底层操作功能。
|
||||||
|
|
||||||
|
根据URI打开一个SMB。
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 指定SMB的路径
|
||||||
|
String uri = "smb://administrator:351002@192.168.31.52/H/琅琊榜 全54集 1080P/";
|
||||||
|
// 网络的相关操作必须通过新线程的方式启动,否则会触发Android的错误
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
// 根据uri打开SmbFile
|
||||||
|
SmbFile smbFile = new SmbFile(uri);
|
||||||
|
String fileName = smbFile.getName();
|
||||||
|
Log.d("Test", fileName);
|
||||||
|
// 控制台打印SMB路径下的文件
|
||||||
|
try{
|
||||||
|
String[] FileList = smbFile.list();
|
||||||
|
for (String s : FileList) {
|
||||||
|
Log.d("Test", s);
|
||||||
|
}
|
||||||
|
}catch (SmbException e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
```
|
||||||
|
|
||||||
|
### 二、SMB转HTTP
|
||||||
|
|
||||||
|
当我们把SMB的Uri提供给播放器后,播放器会请求GET视频。对于一个完整的视频,Http的请求如下所示。
|
||||||
|
|
||||||
|
如果我们在解析请求头的时候没有收到请求的范围信息,那么默认就是返回全部的内容。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
GET /smb/192.168.31.52/I/XXX.mp4 HTTP/1.1
|
||||||
|
User-Agent: ExoPlayerTime/1.0 (Linux;Android 12) ExoPlayerLib/2.7.1
|
||||||
|
Accept-Encoding:identity
|
||||||
|
Host: 127.0.0.1:2222
|
||||||
|
Connection: Keep-Alive
|
||||||
|
```
|
||||||
|
|
||||||
|
当我们拖动进度条的时候,此时视频不是从0开始播放,所以视频播放器会请求包含Range的信息:
|
||||||
|
|
||||||
|
```Shell
|
||||||
|
GET /smb/192.168.31.52/I/XXX.mp4 HTTP/1.1
|
||||||
|
User-Agent: ExoPlayerTime/1.0 (Linux;Android 12) ExoPlayerLib/2.7.1
|
||||||
|
Range: bytes=1207598076-
|
||||||
|
Accept-Encoding:identity
|
||||||
|
Host: 127.0.0.1:2222
|
||||||
|
Connection: Keep-Alive
|
||||||
|
```
|
||||||
|
|
||||||
|
上述情况下,如果我们收到包含Range信息的请求时,返回的时候就需要额外指定一些信息。HTTP的返回有如下的规则:
|
||||||
|
|
||||||
|
```Java
|
||||||
|
// 如果用户拖动了进度条,那么HttpRequest就会包含Range信息
|
||||||
|
// 1.此时contentLength = end - st, 需要返回Content-Length:头
|
||||||
|
"Content-Length: " + contentLength + "\r\n"
|
||||||
|
// 2.此时请求的是部分的信息,所以返回的Responce的类型是206,表示部分内容
|
||||||
|
HttpStatus.PARTIAL_CONTENT = 206
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```Java
|
||||||
|
// 获取文件长度bytes
|
||||||
|
long contentLen = file.length();
|
||||||
|
// 从文件获得输入流
|
||||||
|
InputStream contentIn = file.getInputStream();
|
||||||
|
// 检查输入数据流是否正常
|
||||||
|
if (contentLen <= 0 || contentIn == null) {
|
||||||
|
httpReq.returnBadRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 创建Http返回请求
|
||||||
|
HTTPResponse httpRes = new HTTPResponse();
|
||||||
|
// 指定视频数据格式
|
||||||
|
httpRes.setContentType("video/mpeg4");
|
||||||
|
|
||||||
|
if(startFrom == 0 && endAt == 0){
|
||||||
|
// 请求没有范围信息则返回全部内容,状态OK(200)表示全部内容
|
||||||
|
httpRes.setStatusCode(HTTPStatus.OK);
|
||||||
|
}else if(startFrom > 0){
|
||||||
|
// 如果是包含RangeCotent,则需要返回PARTIAL_CONTENT(206)
|
||||||
|
httpRes.setStatusCode(HTTPStatus.PARTIAL_CONTENT);
|
||||||
|
httpRes.setContentRange(startFrom,endAt, contentLen);
|
||||||
|
}
|
||||||
|
// 设置内容总长度
|
||||||
|
httpRes.setContentLength(contentLen);
|
||||||
|
// 指定内容数据流
|
||||||
|
httpRes.setContentInputStream(contentIn);
|
||||||
|
// HttpReq提交数据
|
||||||
|
httpReq.post(httpRes);
|
||||||
|
contentIn.close();
|
||||||
|
```
|
||||||
|
|
||||||
|
HTTP 视频请求
|
||||||
|
|
||||||
|
```Java
|
||||||
|
// 已知信息
|
||||||
|
File_length = 2794939639
|
||||||
|
File_Range_st = bytes=2792308814
|
||||||
|
// 分析
|
||||||
|
st = 2792308814
|
||||||
|
// 由于文件长度是2794939639,所以换算的索引是0~2794939639-1
|
||||||
|
ed = 2794939639 - 1
|
||||||
|
content_lenght = ( ed - st + 1 )= File_length - 1 - st + 1
|
||||||
|
= ed - st
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#### 依赖 git repository
|
||||||
|
|
||||||
|
依赖 Github 上的一个插件:
|
||||||
|
|
||||||
|
```text
|
||||||
|
dependencies:
|
||||||
|
bloc:
|
||||||
|
git:
|
||||||
|
url: https://github.com/felangel/bloc.git
|
||||||
|
ref: bloc_fixes_issue_110
|
||||||
|
path: packages/bloc
|
||||||
|
```
|
||||||
|
|
||||||
|
- url:github 地址
|
||||||
|
- ref:表示git引用,可以是 **commit hash, tag** 或者 **branch**
|
||||||
|
- path:如果 git 仓库中有多个软件包,则可以使用此属性指定软件包
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Flutter常见问题
|
||||||
|
|
||||||
|
基本上flutter安装官方教程进行环境安装即可,但是有些细节会导致安装出现问题。常见问题如下:
|
||||||
|
|
||||||
|
## 一、flutter doctor长时间等待问题
|
||||||
|
|
||||||
|
产生的原因:1) Powershell没有采用管理员权限运行 2) 没有采用国内镜像源
|
||||||
|
|
||||||
|
1、先配置国内镜像仓库源:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 参考网址:https://flutter.cn/community/china
|
||||||
|
# 下面命令不一定生效,可以采用手动的方式在环境变量中增加变量名和变量值
|
||||||
|
# 配置默认国内镜像源
|
||||||
|
$env:PUB_HOSTED_URL="https://pub.flutter-io.cn";
|
||||||
|
$env:FLUTTER_STORAGE_BASE_URL="https://storage.flutter-io.cn"
|
||||||
|
# 配置清华源
|
||||||
|
$env:PUB_HOSTED_URL="https://mirrors.tuna.tsinghua.edu.cn/dart-pub";
|
||||||
|
$env:FLUTTER_STORAGE_BASE_URL="https://mirrors.tuna.tsinghua.edu.cn/flutter"
|
||||||
|
```
|
||||||
|
|
||||||
|
2、采用管理员身份运行Powershell或者cmd
|
|
@ -0,0 +1,6 @@
|
||||||
|
<font face="逐浪新宋">我是逐浪新宋</font><font face="逐浪圆体">我是逐浪圆体</font><font face="逐浪花体">我是逐浪花体</font><font face="逐浪像素字">我是逐浪像素字</font><font face="逐浪立楷">我是逐浪立楷</font><font color=red>我是红色</font><font color=#008000>我是绿色</font><font color=yellow>我是黄色</font><font color=Blue>我是蓝色</font><font color= #871F78>我是紫色</font><font color= #DCDCDC>我是浅灰色</font><font size=5>我是尺寸</font><font size=10>我是尺寸</font><font face="逐浪立楷" color=green size=10>我是逐浪立楷,绿色,尺寸为5</font> 作者:字库大师程序员发哥 https://www.bilibili.com/read/cv5975926/ 出处:bilibili<font face="逐浪新宋">我是逐浪新宋</font><font face="逐浪圆体">我是逐浪圆体</font><font face="逐浪花体">我是逐浪花体</font><font face="逐浪像素字">我是逐浪像素字</font><font face="逐浪立楷">我是逐浪立楷</font><font color=red>我是红色</font><font color=#008000>我是绿色</font><font color=yellow>我是黄色</font><font color=Blue>我是蓝色</font><font color= #871F78>我是紫色</font><font color= #DCDCDC>我是浅灰色</font><font size=5>我是尺寸</font><font size=10>我是尺寸</font><font face="逐浪立楷" color=green size=10>我是逐浪立楷,绿色,尺寸为5</font> 作者:字库大师程序员发哥 https://www.bilibili.com/read/cv5975926/ 出处:bilibili
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<font size=10>字体大小size=10</font>
|
||||||
|
|
|
@ -0,0 +1,422 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Example for OneDark Theme
|
||||||
|
|
||||||
|
[toc]
|
||||||
|
|
||||||
|
## Headers
|
||||||
|
|
||||||
|
### h3
|
||||||
|
|
||||||
|
Markdown is a lightweight markup language with plain-text-formatting syntax. Its design allows it to be converted to many output formats, but the original tool by the same name only supports HTML. Markdown is often used to format readme files, for writing messages in online discussion forums, and to create rich text using a plain text editor.
|
||||||
|
|
||||||
|
#### h4
|
||||||
|
|
||||||
|
Since the initial description of Markdown contained ambiguities and unanswered questions, the implementations that appeared over the years have subtle differences and many come with syntax extensions.
|
||||||
|
|
||||||
|
##### h5
|
||||||
|
|
||||||
|
In MediaWiki, it is implemented in the currently unmaintained MarkdownExtraParser parser function extension
|
||||||
|
|
||||||
|
###### h6
|
||||||
|
|
||||||
|
Implementations of Markdown are available for over a dozen programming languages.
|
||||||
|
|
||||||
|
## Quote
|
||||||
|
|
||||||
|
> Most UI components including tooltip, dialog and buttons are painted by HTML. And you only need to change those part when you find the UI components are incompatible with your editor theme after finishing steps above. HTML files from the toolkit includes most common UI components for you to easily debug.
|
||||||
|
|
||||||
|
## Font Style
|
||||||
|
|
||||||
|
**Bold**, *italic*, ~~delete~~
|
||||||
|
|
||||||
|
<u>underline</u>, [Link](typora.io)
|
||||||
|
|
||||||
|
H~2~O, E=mc^2^
|
||||||
|
|
||||||
|
<span style="color:red">colored text</span>, ==highlight==
|
||||||
|
|
||||||
|
emoji: :smile:
|
||||||
|
|
||||||
|
- [ ] checkbox
|
||||||
|
|
||||||
|
## Codeblock
|
||||||
|
|
||||||
|
```python
|
||||||
|
# hello_world.py
|
||||||
|
class HelloWorld():
|
||||||
|
def __init__(self):
|
||||||
|
self.text='hello world!'
|
||||||
|
|
||||||
|
def show(self,word):
|
||||||
|
print(f'{word}, {self.text}')
|
||||||
|
|
||||||
|
test=HelloWorld()
|
||||||
|
test.show()
|
||||||
|
```
|
||||||
|
|
||||||
|
Run terminal then enter: `python hello_world.py`
|
||||||
|
|
||||||
|
## KBD
|
||||||
|
|
||||||
|
* bold:<kbd>Ctrl/Command</kbd> + <kbd>B</kbd>
|
||||||
|
|
||||||
|
* italic:<kbd>Ctrl/Command</kbd> + <kbd>I</kbd>
|
||||||
|
|
||||||
|
## MathJax
|
||||||
|
|
||||||
|
Given two populations, $x_1$ and $x_2$ , with logistic dynamics, the Lotka–Volterra formulation adds an additional term to account for the species' interactions. Thus the competitive Lotka–Volterra equations are:
|
||||||
|
$$
|
||||||
|
\begin{cases}
|
||||||
|
\cfrac{dx_1}{dt}=r_1x_1\bigg(1-\cfrac{x_1+\alpha_{12} x_2}{K_1}\bigg)\\
|
||||||
|
\cfrac{dx_2}{dt}=r_2x_2\bigg(1-\cfrac{x_2+\alpha_{21} x_1}{K_2}\bigg)
|
||||||
|
\end{cases}
|
||||||
|
$$
|
||||||
|
Here, $\alpha_{12}$ represents the effect species 2 has on the population of species 1 and $\alpha_{21}$represents the effect species 1 has on the population of species 2.
|
||||||
|
|
||||||
|
## Order
|
||||||
|
|
||||||
|
1. first item
|
||||||
|
2. second item
|
||||||
|
1. first item
|
||||||
|
2. second item
|
||||||
|
3. third item
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
* first item
|
||||||
|
* second item
|
||||||
|
* first item
|
||||||
|
* first item
|
||||||
|
* fourth item
|
||||||
|
|
||||||
|
## Table
|
||||||
|
|
||||||
|
| Cinderella | 11 | glass | transparent |
|
||||||
|
| :----------- | ---: | :---------- | :---------- |
|
||||||
|
| Name | Size | Material | Color |
|
||||||
|
| All Business | 9 | leather | brown |
|
||||||
|
| Roundabout | 10 | hemp canvas | natural |
|
||||||
|
|
||||||
|
## Footnote
|
||||||
|
|
||||||
|
You can create footnotes like this[^fn1] and this[^fn2].
|
||||||
|
|
||||||
|
[^fn1]: Here is the **text** of the first ***\*footnote\****.
|
||||||
|
[^fn2]: Here is the **text** of the second ***\*footnote\****.
|
||||||
|
|
||||||
|
## Image, Video
|
||||||
|
|
||||||
|
<img src="D:\Project\typora-onedark-theme\example\image.jpg" alt="Cosmos08" style="zoom:15%;" />
|
||||||
|
|
||||||
|
<video src="./video.mp4" />
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Bash command
|
||||||
|
</td>
|
||||||
|
<td>Description
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ls
|
||||||
|
</td>
|
||||||
|
<td>List directory contents
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>cd
|
||||||
|
</td>
|
||||||
|
<td>Change directory
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>cp
|
||||||
|
</td>
|
||||||
|
<td>Copy files
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>mv
|
||||||
|
</td>
|
||||||
|
<td>Move files
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## Graph
|
||||||
|
|
||||||
|
### sequence
|
||||||
|
|
||||||
|
```sequence
|
||||||
|
Alice->Bob: Hello Bob, how are you?
|
||||||
|
Note right of Bob: Bob thinks
|
||||||
|
Bob-->Alice: I am good thanks!
|
||||||
|
```
|
||||||
|
|
||||||
|
### flow
|
||||||
|
|
||||||
|
```flow
|
||||||
|
st=>start: Start
|
||||||
|
op=>operation: Your Operation
|
||||||
|
cond=>condition: Yes or No?
|
||||||
|
e=>end
|
||||||
|
|
||||||
|
st->op->cond
|
||||||
|
cond(yes)->e
|
||||||
|
cond(no)->op
|
||||||
|
```
|
||||||
|
|
||||||
|
### mermaid
|
||||||
|
|
||||||
|
#### Flowchart
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
Start --> Stop
|
||||||
|
```
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A([A]) --- B(B) -- C --- C{C}
|
||||||
|
C -- D --> D[[D]]
|
||||||
|
C -.->|E| E[E]
|
||||||
|
C -. F .-> F[(F)]
|
||||||
|
C ==>|G| G((G))
|
||||||
|
B == edge ==> H>H]
|
||||||
|
B --> I{{I}}
|
||||||
|
subgraph sub [subgraph]
|
||||||
|
I -->|J| J[/J/]
|
||||||
|
I -->|K| K[\K\]
|
||||||
|
I -->|L| L[\L/]
|
||||||
|
I -->|M| M[/M\]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Sequence diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
%% Example of sequence diagram
|
||||||
|
sequenceDiagram
|
||||||
|
participant A
|
||||||
|
participant B
|
||||||
|
participant C
|
||||||
|
Note right of B: note
|
||||||
|
Note over A,B: note
|
||||||
|
A->B: a
|
||||||
|
activate B
|
||||||
|
A-->B: b
|
||||||
|
activate B
|
||||||
|
A->>B: c
|
||||||
|
deactivate B
|
||||||
|
A-->>B: d
|
||||||
|
deactivate B
|
||||||
|
rect rgba(128,0,0,0.5)
|
||||||
|
A-xA: e
|
||||||
|
end
|
||||||
|
loop loop
|
||||||
|
A--xB: f
|
||||||
|
end
|
||||||
|
alt alt
|
||||||
|
B->>A: g
|
||||||
|
else else
|
||||||
|
B->>A: h
|
||||||
|
end
|
||||||
|
par par
|
||||||
|
A->C: i
|
||||||
|
and and
|
||||||
|
A->B: j
|
||||||
|
par nest
|
||||||
|
B->C: k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Class diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
A <|-- B: label
|
||||||
|
A "1" *-- "1.." C
|
||||||
|
A "*" o-- "0..1" D
|
||||||
|
C <-- E
|
||||||
|
C -- F
|
||||||
|
D <.. G
|
||||||
|
D <|.. H
|
||||||
|
D .. I
|
||||||
|
A: +int i1
|
||||||
|
A: -String s1
|
||||||
|
A: #List~int~ l1
|
||||||
|
A: ~f1(arg) bool
|
||||||
|
A: +f2()*
|
||||||
|
A: +f3()$
|
||||||
|
class B {
|
||||||
|
<<enumeration>>
|
||||||
|
RED
|
||||||
|
GREEN
|
||||||
|
BLUE
|
||||||
|
}
|
||||||
|
class D {
|
||||||
|
<<interface>>
|
||||||
|
int i1
|
||||||
|
f1()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### State diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram
|
||||||
|
[*] --> Still
|
||||||
|
Still --> [*]
|
||||||
|
|
||||||
|
Still --> Moving
|
||||||
|
Moving --> Still
|
||||||
|
Moving --> Crash
|
||||||
|
Crash --> [*]
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram
|
||||||
|
state fork_state <<fork>>
|
||||||
|
state "This is A" as A
|
||||||
|
[*] --> fork_state
|
||||||
|
[*] --> D
|
||||||
|
D --> fork_state
|
||||||
|
note right of D
|
||||||
|
note for D
|
||||||
|
end note
|
||||||
|
note left of A: note for A
|
||||||
|
fork_state --> A
|
||||||
|
fork_state --> B
|
||||||
|
A --> C: trans
|
||||||
|
B --> C
|
||||||
|
C --> [*]
|
||||||
|
state C {
|
||||||
|
[*] --> C1: test
|
||||||
|
C1 --> C2
|
||||||
|
C2 --> C3
|
||||||
|
C3 --> [*]
|
||||||
|
state C2 {
|
||||||
|
[*] --> C21
|
||||||
|
C21 --> [*]
|
||||||
|
state C21 {
|
||||||
|
[*] --> C211
|
||||||
|
}
|
||||||
|
}
|
||||||
|
C1: This is C1
|
||||||
|
--
|
||||||
|
[*] --> T
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
state fork_state <<fork>>
|
||||||
|
state "This is A" as A
|
||||||
|
[*] --> fork_state
|
||||||
|
[*] --> D
|
||||||
|
D --> fork_state
|
||||||
|
note right of D
|
||||||
|
note for D
|
||||||
|
end note
|
||||||
|
note left of A: note for A
|
||||||
|
fork_state --> A
|
||||||
|
fork_state --> B
|
||||||
|
A --> C: trans
|
||||||
|
B --> C
|
||||||
|
C --> [*]
|
||||||
|
state C {
|
||||||
|
[*] --> C1: test
|
||||||
|
C1 --> C2
|
||||||
|
C2 --> C3
|
||||||
|
C3 --> [*]
|
||||||
|
state C2 {
|
||||||
|
[*] --> C21
|
||||||
|
C21 --> [*]
|
||||||
|
state C21 {
|
||||||
|
[*] --> C211
|
||||||
|
}
|
||||||
|
}
|
||||||
|
C1: This is C1
|
||||||
|
--
|
||||||
|
[*] --> T
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Entity Relationship Diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
A |o--o| B : b
|
||||||
|
B ||--|| C : c
|
||||||
|
A }o..o{ D : d
|
||||||
|
D }|..|{ E : e
|
||||||
|
```
|
||||||
|
|
||||||
|
#### User Journey Diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
journey
|
||||||
|
title My working day
|
||||||
|
section A
|
||||||
|
A1: 5: Me
|
||||||
|
A2: 3: Me
|
||||||
|
A3: 1: Me, Cat
|
||||||
|
A4: 2
|
||||||
|
A5: 4
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Gantt
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
%% Example with selection of syntaxes
|
||||||
|
gantt
|
||||||
|
dateFormat YYYY-MM-DD
|
||||||
|
title Adding GANTT diagram functionality to mermaid
|
||||||
|
|
||||||
|
section A section
|
||||||
|
Completed task :done, des1, 2014-01-06,2014-01-08
|
||||||
|
Active task :active, des2, 2014-01-09, 3d
|
||||||
|
Future task : des3, after des2, 5d
|
||||||
|
Future task2 : des4, after des3, 5d
|
||||||
|
|
||||||
|
section Critical tasks
|
||||||
|
Completed task in the critical line :crit, done, 2014-01-06,24h
|
||||||
|
Implement parser and jison :crit, done, after des1, 2d
|
||||||
|
Create tests for parser :crit, active, 3d
|
||||||
|
Future task in critical line :crit, 5d
|
||||||
|
Create tests for renderer :2d
|
||||||
|
Add to mermaid :1d
|
||||||
|
|
||||||
|
section Documentation
|
||||||
|
Describe gantt syntax :active, a1, after des1, 3d
|
||||||
|
Add gantt diagram to demo page :after a1 , 20h
|
||||||
|
Add another diagram to demo page :doc1, after a1 , 48h
|
||||||
|
|
||||||
|
section Last section
|
||||||
|
Describe gantt syntax :after doc1, 3d
|
||||||
|
Add gantt diagram to demo page : 20h
|
||||||
|
Add another diagram to demo page : 48h
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Pie Chart
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
pie
|
||||||
|
title Pie Chart
|
||||||
|
"A" : 1
|
||||||
|
"B" : 2
|
||||||
|
"C" : 3
|
||||||
|
"D" : 4
|
||||||
|
"E" : 5
|
||||||
|
"F" : 6
|
||||||
|
"G" : 7
|
||||||
|
"H" : 8
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
1.1 `MySQL`的内容查看
|
||||||
|
|
||||||
|
在`MySQL`中,部分内容可能是`json`结构,此时我们可以选择要查看的内容,然后选择文本功能,即可完整查看复杂的文本内容。
|
||||||
|
|
||||||
|
![Snipaste_2023-12-27_22-09-28](C:\Users\admin\Desktop\Snipaste_2023-12-27_22-09-28.png)
|
||||||
|
|
||||||
|
1.2 MySQL允许所有主机连接
|
||||||
|
|
||||||
|
https://blog.csdn.net/CoCo629vanilla/article/details/129008644
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
|
||||||
|
# ESP内存和存储模型
|
||||||
|
|
||||||
|
ESP32-WROOM 规格说明书写到:
|
||||||
|
|
||||||
|
• 448 KB 的 ROM,用于程序启动和内核功能调用
|
||||||
|
|
||||||
|
• 用于数据和指令存储的 520 KB 片上 SRAM • RTC 快速存储器,为 8 KB 的 SRAM,可以在 Deep-sleep 模式下 RTC 启动时用于数据存储以及被主 CPU 访问
|
||||||
|
|
||||||
|
• RTC 慢速存储器,为 8 KB 的 SRAM,可以在 Deep-sleep 模式下被协处理器访问
|
||||||
|
|
||||||
|
• 1 Kbit 的 eFuse,其中 256 bit 为系统专用(MAC 地址和芯片设置); 其余 768 bit 保留给用户程序, 这些 程序包括 flash 加密和芯片 ID
|
||||||
|
|
||||||
|
**1.1、ESP32的内存结构**
|
||||||
|
|
||||||
|
- IRAM:internal ram 内部RAM,指的是集成到SoC内部的RAM
|
||||||
|
- DRAM:dynamic ram 动态RAM,特点就是容量大、价格低,缺点就是上电后不能直接使用,需要软件初始化后才可以使用。
|
||||||
|
|
||||||
|
```C
|
||||||
|
I (434) heap_init: Initializing. RAM available for dynamic allocation:
|
||||||
|
I (441) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
|
||||||
|
I (447) heap_init: At 3FFBC0E0 len 00023F20 (143 KiB): DRAM
|
||||||
|
I (454) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
|
||||||
|
I (460) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
|
||||||
|
I (466) heap_init: At 4008E7C4 len 0001183C (70 KiB): IRAM
|
||||||
|
```
|
||||||
|
|
||||||
|
从以上的输出结果来看,ESP32的DRAM149KB,IRAM一共195KB,合并一共344KB。
|
||||||
|
|
||||||
|
**1.2 字节Bytes和KB**
|
||||||
|
|
||||||
|
观察ESP32生成的程序信息:DRAM可用128KB,IRAM可用70KB。
|
||||||
|
|
||||||
|
```
|
||||||
|
Total sizes:
|
||||||
|
DRAM .data size: 11532 bytes
|
||||||
|
DRAM .bss size: 37864 bytes
|
||||||
|
Used static DRAM: 49396 bytes ( 131340 available, 27.3% used)
|
||||||
|
Used static IRAM: 59330 bytes ( 71742 available, 45.3% used)
|
||||||
|
Flash code: 349355 bytes
|
||||||
|
Flash rodata: 296268 bytes
|
||||||
|
Total image size:~ 716485 bytes (.bin may be padded larger)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Flash Code:即代码域,它通常是指编译器生成的机器指令,这些内容会被存储到ROM区。** 大约有340KB
|
||||||
|
|
||||||
|
**RO-data:Read Only data,即只读数据域,它指程序中用到的只读数据,这些数据被存储在ROM区,因而程序不能被修改的内容。** 大约290KB。
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# LVGL常用函数笔记
|
||||||
|
|
||||||
|
## 一、屏幕操作相关
|
||||||
|
|
||||||
|
**1.1 获取屏幕的对象**
|
||||||
|
|
||||||
|
```C
|
||||||
|
lv_obj_t * lv_scr_act(void) // 获取当前活动屏幕的指针
|
||||||
|
```
|
||||||
|
|
||||||
|
**1.2 在屏幕上创建对象**
|
||||||
|
|
||||||
|
```C
|
||||||
|
// 获取当前屏幕对象并创建对象
|
||||||
|
lv_obj_t* root_obj = lv_obj_create(lv_scr_act());
|
||||||
|
// 设置对象背景颜色
|
||||||
|
lv_obj_set_style_bg_color(root, lv_color_black(), 0);
|
||||||
|
// 设置对象背景透明度 Opacity:透明度
|
||||||
|
lv_obj_set_style_bg_opa(root, LV_OPA_COVER, 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
1.3
|
|
@ -0,0 +1,19 @@
|
||||||
|
## 一、X-Track执行页面的Unload过程
|
||||||
|
|
||||||
|
**1.1 在PageView中不需要删除对象**
|
||||||
|
|
||||||
|
准确的来说,应该是通过root节点创建的对象的是不需要删除的,对于非root节点创建的对象,如动画、style是需要在delete函数中删除的,否则会造成内存泄漏。
|
||||||
|
|
||||||
|
```c
|
||||||
|
lv_obj_del_async(base->root);
|
||||||
|
base->root = nullptr;
|
||||||
|
base->priv.IsCached = false;
|
||||||
|
base->onViewDidUnload();
|
||||||
|
```
|
||||||
|
|
||||||
|
从上面的代码可以看出X-Track先执行root节点的删除然后再调用onViewDidUnload()函数。由于在删除父节点的时候,子节点也会被删除,所以不建议在PageView里面调用lv_obj_del()函数。
|
||||||
|
|
||||||
|
|
||||||
|
$$
|
||||||
|
y=k*(x-0)+b \\= k*(x-xt)+b = k*x-k*xt+b + k*xt
|
||||||
|
$$
|
After Width: | Height: | Size: 122 KiB |
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 24 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
Unity3D 对象的旋转
|
||||||
|
|
||||||
|
```C#
|
||||||
|
Debug.Log("position " + transform.position); //世界坐标的位置
|
||||||
|
Debug.Log("localPosition " + transform.localPosition); //相对于父位置的坐标 即把父物体当作自己的中心
|
||||||
|
Debug.Log("eulerAngles " + transform.eulerAngles);//世界坐标欧拉⾓度
|
||||||
|
Debug.Log("localEulerAngles " + transform.localEulerAngles);//相对于⽗级的变换的旋转欧拉⾓度
|
||||||
|
Debug.Log("localScale " + transform.localScale);//相对于父位置的缩放
|
||||||
|
Debug.Log("localRotation " + transform.localRotation);//相对于父位置的旋转
|
||||||
|
Debug.Log("rotation " + transform.rotation);//世界坐标的旋转
|
||||||
|
```
|
|
@ -0,0 +1,33 @@
|
||||||
|
## Unity的基本操作
|
||||||
|
|
||||||
|
**一、场景的基本操作**
|
||||||
|
|
||||||
|
- 缩放:鼠标滚轮
|
||||||
|
- 旋转:鼠标箭头左键点击后拖动
|
||||||
|
- 拖动场景位置移动:鼠标滚轮按下
|
||||||
|
|
||||||
|
### **二、人物模型的控制**
|
||||||
|
|
||||||
|
**2.1 人物的结构和手动控制**
|
||||||
|
|
||||||
|
如下图所示,一般来说3D人物模型的身体部分都是躯体的骨骼模型,按照多叉树的结构组织的。对于每一部分的躯体部分都可以控制其平移、缩放、旋转等操作。
|
||||||
|
|
||||||
|
<img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220916003925721.png" alt="image-20220916003925721" style="zoom:45%;" />
|
||||||
|
|
||||||
|
完整的人物呈现如下图所示(默认状态):
|
||||||
|
|
||||||
|
<img src="./Image/Model_Default.png" style="zoom:50%;" />
|
||||||
|
|
||||||
|
对象的旋转、平移、缩放操作,可以通过窗口进行控制:
|
||||||
|
|
||||||
|
<div align=center><img src="./Image/Unity3D-Model-Transform.png" alt="image-20220916005017611" style="zoom:50%;" /></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
设置手臂的Y轴旋转角度为-90°,可以看到:
|
||||||
|
|
||||||
|
<div align=center><img src="./Image/Model_UpperArm-90.png" style="zoom:50%;" /></div>
|
||||||
|
|
||||||
|
**2.2 人物脚本控制**
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
Matplotlib使用笔记
|
||||||
|
|
||||||
|
1、Matplotlib结合numpy绘制图形
|
||||||
|
|
||||||
|
```python
|
||||||
|
import numpy as np
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
x = np.arange(1,11)
|
||||||
|
y = 2 * x + 5
|
||||||
|
plt.title("Matplotlib demo")
|
||||||
|
plt.xlabel("x axis caption")
|
||||||
|
plt.ylabel("y axis caption")
|
||||||
|
plt.plot(x,y)
|
||||||
|
plt.show()
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
# Numpy使用笔记
|
||||||
|
|
||||||
|
NumPy 全称为 Numerical Python,是 Python 的一个以矩阵为主的用于科学计算的基础软件包。NumPy 和 Pandas、Matpotlib 经常结合一起使用,所以被人们合称为数据分析三剑客。Numpy 中有功能强大的 ndarray 对象,能创建 N 维的数组,另外还提供很多通用函数,支持对数组的元素进行操作、支持对数组进行算法运算以及提供常用的统计函数。
|
||||||
|
|
||||||
|
相比 List 对象,NumPy 数组有以下优势:
|
||||||
|
|
||||||
|
1. 这是因为列表 list 的元素在系统内存中是分散存储的,而 NumPy 数组存储在一个均匀连续的内存块中。这样数组计算遍历所有元素,不像列表 list 还需要对内存地址进行查找,从而节省了计算资源。
|
||||||
|
2. Numpy数组能够运用向量化运算来处理整个数组,速度较快;而 Python 的列表则通常需要借助循环语句遍历列表,运行效率相对来说要差。
|
||||||
|
3. NumPy 中的矩阵计算可以采用多线程的方式,充分利用多核 CPU 计算资源,大大提升了计算效率。
|
||||||
|
4. Numpy 使用了优化过的 C API,运算速度较快。
|
||||||
|
|
||||||
|
## 一、数组创建和使用
|
||||||
|
|
||||||
|
**1.1、创建zeros数组**
|
||||||
|
|
||||||
|
```python
|
||||||
|
import numpy as np
|
||||||
|
# 创建1维数组
|
||||||
|
x1 = np.zeros(20)
|
||||||
|
# 打印一维数组
|
||||||
|
print(x1)
|
||||||
|
# 数组的赋值, 从0开始
|
||||||
|
for i in range(0,20):
|
||||||
|
x1[i] = i
|
||||||
|
print(str(x1[i]))
|
||||||
|
# 2维数组的创建
|
||||||
|
# 创建一个 3x4 的数组且所有值全为 0
|
||||||
|
x3 = np.zeros((3, 4), dtype=int)
|
||||||
|
print(x3)
|
||||||
|
# 创建一个 3x4 的数组且所有元素值全为 1
|
||||||
|
x4 = np.ones((3, 4), dtype=int)
|
||||||
|
print(x4)
|
||||||
|
# 创建一个 3x4 的数组,然后将所有元素的值填充为 2
|
||||||
|
x5 = np.full((3, 4), 2, dtype=int)
|
||||||
|
print(x5)
|
||||||
|
```
|
||||||
|
|
||||||
|
**1.2、创建随机数组**
|
||||||
|
|
||||||
|
```python
|
||||||
|
import numpy as np
|
||||||
|
# 创建2*2随机数组
|
||||||
|
lux_br_arr = np.random.random((2,2))
|
||||||
|
# 打印结果
|
||||||
|
print(lux_br_arr)
|
||||||
|
```
|
||||||
|
|
||||||
|
1.3 通过array_list创建数组
|
||||||
|
|
||||||
|
```python
|
||||||
|
import numpy as np
|
||||||
|
x_list = [1,2,3,4]
|
||||||
|
x = np.array(x_list)
|
||||||
|
print(x)
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
# Pandas-Dataframe使用笔记
|
||||||
|
|
||||||
|
## 一、Dataframe的读取和保存
|
||||||
|
|
||||||
|
**1.1 Dataframe导出csv**
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Dataframe转CSV
|
||||||
|
xlsx_file.to_csv('F:/XXX/XXX.csv', encoding="utf-8-sig",header=True)
|
||||||
|
```
|
||||||
|
|
||||||
|
**1.2 Pandas读取xlsx**
|
||||||
|
|
||||||
|
```python
|
||||||
|
# xlsx_file_name 如:'F:/XXX/XXX.xlsx'
|
||||||
|
# 一般xlsx默认的sheet_name是Sheet1
|
||||||
|
xlsx_file = pd.read_excel(xlsx_file_name, sheet_name='Sheet1')
|
||||||
|
```
|
||||||
|
|
||||||
|
**1.3 Dataframe的创建**
|
||||||
|
|
||||||
|
dataframe可以通过读取csv或者xlsx等方式创建,同时也可以通过数组创建
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
# 创建数组
|
||||||
|
data_list = [[6,10,3],[1,5,4],[1,2,4],[1,15,24],[1,0,2],[3,7,9],[2,8,5]]
|
||||||
|
# 通过数组创建dataframe, columns并不是必须的, 如果不提供的话默认用0,1,...,n表示
|
||||||
|
df = pd.DataFrame(data_list,columns=['A','B','C'])
|
||||||
|
# 指定dataframe的行索引, 这也不是必须的, 如果不提供的话默认用0,1,...,n表示
|
||||||
|
df.index = ['G','H','I','J','K','L','M']
|
||||||
|
# 打印结果
|
||||||
|
print(df)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 二、Dataframe的操作
|
||||||
|
|
||||||
|
**2.1 获取Dataframe和行数和列数**
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
# 创建dataframe
|
||||||
|
df = pd.DataFrame(np.arange(24).reshape(6,4), columns=['A', 'B', 'C', 'D'])
|
||||||
|
row_nums = df.shape[0]
|
||||||
|
col_nums = df.columns.size
|
||||||
|
print(row_nums)
|
||||||
|
print(col_nums)
|
||||||
|
|
||||||
|
# 获取特定行data.iloc[x,y]
|
||||||
|
```
|
||||||
|
|
||||||
|
**2.2 Dataframe删除行、列**
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
# 创建dataframe
|
||||||
|
df = pd.DataFrame(np.arange(24).reshape(6,4), columns=['A', 'B', 'C', 'D'])
|
||||||
|
print(df)
|
||||||
|
# 删除单行
|
||||||
|
df1 = df.drop(axis=0, index = 1, inplace=False)
|
||||||
|
print(df1)
|
||||||
|
# 删除多行
|
||||||
|
df2 = df.drop(axis=0, index = [1,2,4], inplace=False)
|
||||||
|
print(df2)
|
||||||
|
# 删除列
|
||||||
|
df3 = df.drop(axis=1, columns = ['A','D'], inplace=False)
|
||||||
|
print(df3)
|
||||||
|
```
|
||||||
|
|
||||||
|
注意删除多行的时候要确保index存在,一种非常隐蔽的错误是:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
df1 = pd.DataFrame(np.arange(12).reshape(3,4), columns=['A', 'B', 'C', 'D'])
|
||||||
|
df2 = pd.DataFrame(np.arange(12).reshape(3,4), columns=['A', 'B', 'C', 'D'])
|
||||||
|
# ignore_index=True 保留原索引
|
||||||
|
new_df = pd.concat([df1,df2], ignore_index=False)
|
||||||
|
# 打印可以看到拼接之后索引只有0,1,2
|
||||||
|
print(new_df)
|
||||||
|
# 当我们调用删除行函数的时候会报错,因为没有index=3,虽然这个dataframe是6x4大小的
|
||||||
|
# 这是一个非常隐蔽的错误
|
||||||
|
df3 = new_df.drop(axis=0, index = 3, inplace=False)
|
||||||
|
```
|
||||||
|
|
||||||
|
**2.3 Dataframe的排序**
|
||||||
|
|
||||||
|
dataframe的排序有通过行列的名称进行排序,也有同行的数值或者列的数值进行排序。对于数值排序,采用sort_values函数。
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
# 创建dataframe
|
||||||
|
data_list = [[6,10,3],[1,5,4],[1,2,4],[1,15,24],[1,0,36],[3,7,9],[2,8,5]]
|
||||||
|
df = pd.DataFrame(data_list,columns=['A','B','C'])
|
||||||
|
df.index = ['G','H','I','J','K','L','M']
|
||||||
|
# 对列A进行降序排列
|
||||||
|
# ascending表示是否升序排列, inplace表示在自身进行排序
|
||||||
|
df.sort_values(by='A',axis=0,ascending=False,inplace=True)
|
||||||
|
print(df)
|
||||||
|
|
||||||
|
df = pd.DataFrame(data_list,columns=['A','B','C'])
|
||||||
|
df.index = ['G','H','I','J','K','L','M']
|
||||||
|
# 对A列和B列进行升序排列,按照A、B的优先级进行排序
|
||||||
|
df_data_order = df.sort_values(by=['A','B'],ascending=[True,True])
|
||||||
|
print(df_data_order)
|
||||||
|
```
|
||||||
|
|
||||||
|
很多时候,对于一些默认行号的dataframe,排序之后会把把行号打乱。这个时候可以通过reset_index函数重置索引。
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
data = [['a','3'],['b','1'],['c','2']]
|
||||||
|
df = pd.DataFrame(data)
|
||||||
|
df = df.sort_values(by = 1,axis = 0,ascending = False)
|
||||||
|
# 排序后的行号是乱的
|
||||||
|
print(df)
|
||||||
|
# 重置索引后行号按照0,1,2,...顺序
|
||||||
|
df = df.reset_index(drop=True)
|
||||||
|
print(df)
|
||||||
|
```
|
||||||
|
|
||||||
|
**2.4 Dataframe的拼接**
|
||||||
|
|
||||||
|
Dataframe的拼接有几个函数:merge、concat等函数
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
df1 = pd.DataFrame(np.arange(12).reshape(3,4), columns=['A', 'B', 'C', 'D'])
|
||||||
|
df2 = pd.DataFrame(np.arange(12).reshape(3,4), columns=['A', 'B', 'C', 'D'])
|
||||||
|
# 拼接df1和df2,默认的拼接方向axis=0垂直方向拼接
|
||||||
|
# ignore_index=True 忽略原索引
|
||||||
|
new_df = pd.concat([df1,df2], ignore_index=True)
|
||||||
|
print(new_df)
|
||||||
|
# ignore_index=True 保留原索引
|
||||||
|
new_df = pd.concat([df1,df2], ignore_index=False)
|
||||||
|
print(new_df)
|
||||||
|
```
|
||||||
|
|
||||||
|
**2.5 Dataframe数据筛选**
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
# 创建数组
|
||||||
|
data_list = [['拖动',10,3],[1,5,4],['拖动',2,4],[1,15,24],['滑动',0,2],[3,7,9],[2,8,5]]
|
||||||
|
# 通过数组创建dataframe, columns并不是必须的, 如果不提供的话默认用0,1,...,n表示
|
||||||
|
df = pd.DataFrame(data_list,columns=['A','B','C'])
|
||||||
|
print(df)
|
||||||
|
# 去掉A列中包含拖动的数值
|
||||||
|
df1 = df[~(df['A']=='拖动')]
|
||||||
|
# 重建索引序号
|
||||||
|
df1 = df1.reset_index(drop=True)
|
||||||
|
print(df)
|
||||||
|
# 更加复杂的运算操作
|
||||||
|
# df=df[~((df['B']>7)|(df['D']==0))]
|
||||||
|
|
||||||
|
df1 = df[(df['A'].isin(['拖动','滑动']) == True)]
|
||||||
|
df1 = df1.reset_index(drop=True)
|
||||||
|
print(df1)
|
||||||
|
|
||||||
|
# 列筛选A列和B列
|
||||||
|
df = pd.DataFrame(data_list,columns=['A','B','C'])
|
||||||
|
df = df[['A','B']]
|
||||||
|
print(df)
|
||||||
|
```
|
||||||
|
|
||||||
|
对dataframe的字符串筛选也可以通过Dataframe的contain函数,这种方式可以允许子串的搜索,同时contain函数也支持正则表达式。
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
# 创建数组
|
||||||
|
data_list = [['拖动',10,3],[1,5,4],['拖动',2,4],[1,15,24],['滑动',0,2],[3,7,9],[2,8,5]]
|
||||||
|
# 通过数组创建dataframe, columns并不是必须的, 如果不提供的话默认用0,1,...,n表示
|
||||||
|
df = pd.DataFrame(data_list,columns=['A','B','C'])
|
||||||
|
print(df)
|
||||||
|
# 去掉A列中包含动的数值
|
||||||
|
df=df[(df['A'].str.contains('动') == True)]
|
||||||
|
# 重建索引序号
|
||||||
|
df = df.reset_index(drop=True)
|
||||||
|
print(df)
|
||||||
|
|
||||||
|
# contains函数支持正则表达式
|
||||||
|
df = pd.DataFrame(data_list,columns=['A','B','C'])
|
||||||
|
parttern = r'.*?'
|
||||||
|
df=df[(df['A'].str.contains(parttern) == True)]
|
||||||
|
print(df)
|
||||||
|
```
|
||||||
|
|
||||||
|
**2.6 Dataframe NaN处理**
|
||||||
|
|
||||||
|
axis: default 0指行,1为列
|
||||||
|
|
||||||
|
how: {‘any’, ‘all’}, default **‘any’指带缺失值的所有行**;**'all’指清除全是缺失值的**
|
||||||
|
|
||||||
|
thresh: int,保留含有int个非空值的行
|
||||||
|
|
||||||
|
subset: 对特定的列进行缺失值删除处理
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
df = pd.DataFrame({'A': [np.nan, 1, 2], 'B': [10, np.nan, 10], 'C': [10, 25, 15]})
|
||||||
|
print(df)
|
||||||
|
# any表示某一行或者某一列有NaN即被抛弃, all表示清除全部都是NaN
|
||||||
|
df = df.dropna(axis=0, how='any')
|
||||||
|
print(df)
|
||||||
|
# 删除pkg中存在NaN的列, subset=['pkg','xxx','xxxxx']
|
||||||
|
# df2 = df.dropna(axis='index', how='all', subset=['pkg'])
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
# Python 常用功能
|
||||||
|
|
||||||
|
## 一、python高频常用
|
||||||
|
|
||||||
|
**1.1 Python简单main框架**
|
||||||
|
|
||||||
|
```python
|
||||||
|
import os
|
||||||
|
def func():
|
||||||
|
print('func')
|
||||||
|
if __name__ =="__main__":
|
||||||
|
# 遍历文件夹所有文件
|
||||||
|
func()
|
||||||
|
```
|
||||||
|
|
||||||
|
**1.2 文件夹遍历**
|
||||||
|
|
||||||
|
```python
|
||||||
|
import os
|
||||||
|
|
||||||
|
def get_filelist(path):
|
||||||
|
Filelist = []
|
||||||
|
for home, dirs, files in os.walk(path):
|
||||||
|
for filename in files:
|
||||||
|
# 完整路径文件名列表
|
||||||
|
Filelist.append(os.path.join(home, filename))
|
||||||
|
# 文件名列表,只包含文件名
|
||||||
|
#Filelist.append(filename)
|
||||||
|
return Filelist
|
||||||
|
|
||||||
|
# 获取文件夹文件路径
|
||||||
|
Filelist = get_filelist('F:/data_all_apps/')
|
||||||
|
# 打印文件完整路径
|
||||||
|
for file in Filelist :
|
||||||
|
print(file)
|
||||||
|
```
|
||||||
|
|
||||||
|
**1.3 保留两位小数**
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 方法一:格式化字符串
|
||||||
|
a = 12.345
|
||||||
|
b = 12.122276
|
||||||
|
print("%.2f %.2f" % (a,b))
|
||||||
|
|
||||||
|
# 方法二:round函数
|
||||||
|
a = 12.44476
|
||||||
|
print(round(a,2))
|
||||||
|
```
|
||||||
|
|
||||||
|
**1.4 python格式化字符串**
|
||||||
|
|
||||||
|
```python
|
||||||
|
str = "hello"
|
||||||
|
print("this is a string: %s" % str)
|
||||||
|
print("this is a string: %s, %s" % (str, str))
|
||||||
|
idx = 2.66788
|
||||||
|
print("this %.2f is a string: %s, %s" % (idx, str, str))
|
||||||
|
```
|
||||||
|
|
||||||
|
其他丰富样例:
|
||||||
|
|
||||||
|
```python
|
||||||
|
first = "持续学习"
|
||||||
|
second = "持续开发"
|
||||||
|
slogan = first + second
|
||||||
|
print(slogan)
|
||||||
|
banner = "*" * 16
|
||||||
|
print(banner)
|
||||||
|
slice = slogan[2:4]
|
||||||
|
print(slice)
|
||||||
|
print(""""学习" in slogan : %s""" % ("学习" in slogan))
|
||||||
|
print(""""不学习" not in slogan : %s""" % ("不学习" not in slogan))
|
||||||
|
print(r"""打印\n换行被当做普通字符输出了!""")
|
||||||
|
# 以上我们都可以看到%,很多次代码都有说到这个,但是并没有过多解释
|
||||||
|
print("%s" % slogan) # 最常用了%s 格式化字符串
|
||||||
|
# print("%c"%'ccc')#TypeError: %c requires int or char
|
||||||
|
print("%c" % 'c') # %c 通常用来强制检测待输出的字符串必须长度为1
|
||||||
|
print("%c" % '雷') # %c 通常用来强制检测待输出的字符串必须长度为1
|
||||||
|
number = 102.40101
|
||||||
|
print("%%i 符号整数 %i" % number)
|
||||||
|
print("%%i 符号整数:%i" % -number)
|
||||||
|
print("%%d 符号整数 %d" % number)
|
||||||
|
print("%%d 符号整数 %d" % -number)
|
||||||
|
print("%%u 无符号整数:%u" % number)
|
||||||
|
print("%%u 无符号整数:%u" % -number)
|
||||||
|
#print("八进制 %o" % number)
|
||||||
|
print("%%o 八进制 %o" % 102)
|
||||||
|
print("%%x16进制 %x" % 102)
|
||||||
|
#print("16进制 %X" % 102)
|
||||||
|
print("%%e 自然常数 e进制: %e" % number)
|
||||||
|
#print("%E" % number)
|
||||||
|
print("%%f 浮点数 %f" % number)
|
||||||
|
#保证显示6微有效数字的前提下,灵活的选择小数方式,或者科学计数法
|
||||||
|
print("%%g 灵活的有效显示:%g" % number)
|
||||||
|
#print("%G" % number)
|
||||||
|
#保证显示6微有效数字的前提下,灵活的选择小数方式,或者科学计数法
|
||||||
|
print("%%g 灵活的有效显示:%g" % (number*10001))
|
||||||
|
#下面两种写法需要注意执行顺序
|
||||||
|
#print("%g" % number*10001) #注意这种写法
|
||||||
|
#print("%g" % number**10) #注意这种写法
|
||||||
|
```
|
||||||
|
|
||||||
|
1.5 系统暂停
|
||||||
|
|
||||||
|
```python
|
||||||
|
os.system('pause')
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
```python
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*-coding:utf-8 -*-
|
||||||
|
|
||||||
|
import copy
|
||||||
|
a = [1, 2, 3, 4, ['a', 'b']] #原始对象
|
||||||
|
|
||||||
|
b = a #赋值,传对象的引用
|
||||||
|
c = copy.copy(a) #对象拷贝,浅拷贝
|
||||||
|
d = copy.deepcopy(a) #对象拷贝,深拷贝
|
||||||
|
|
||||||
|
a.append(5) #修改对象a
|
||||||
|
a[4].append('c') #修改对象a中的['a', 'b']数组对象
|
||||||
|
|
||||||
|
print( 'a = ', a )
|
||||||
|
print( 'b = ', b )
|
||||||
|
print( 'c = ', c )
|
||||||
|
print( 'd = ', d )
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
## GPS 算法Python工具
|
||||||
|
|
||||||
|
一、距离的计算
|
||||||
|
|
||||||
|
```python
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
# Function : cal_distance
|
||||||
|
# Descripiton : 给定经纬度, 计算两点之间距离m
|
||||||
|
# Author : zhanli@vivo.com
|
||||||
|
# Date : 2022-07-06
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
def cal_distance(lat1,lon1,lat2,lon2):
|
||||||
|
dis = 0
|
||||||
|
# WGS-84椭球体长半轴
|
||||||
|
WGS84_RE = 6378136.49
|
||||||
|
# 第一偏向率的平方,e^2(WGS-84)
|
||||||
|
WGS84_ECCENTR2 = 6.69437999014e-3
|
||||||
|
# 角度转弧度系数
|
||||||
|
DEG2RAD = 0.017453292
|
||||||
|
|
||||||
|
lat = lat1 * DEG2RAD
|
||||||
|
|
||||||
|
sinLat = math.sin(lat)
|
||||||
|
p = 1 - WGS84_ECCENTR2 * (sinLat * sinLat)
|
||||||
|
temp = math.sqrt(p)
|
||||||
|
|
||||||
|
rmh = WGS84_RE * (1 - WGS84_ECCENTR2) / (p*temp)
|
||||||
|
rnh = WGS84_RE * math.cos(lat) / temp
|
||||||
|
|
||||||
|
rmh *= DEG2RAD
|
||||||
|
rnh *= DEG2RAD
|
||||||
|
|
||||||
|
latDiff = rmh*(lat1 - lat2)
|
||||||
|
lonDiff = rnh*(lon1 - lon2)
|
||||||
|
|
||||||
|
dis = math.sqrt(latDiff*latDiff + lonDiff*lonDiff)
|
||||||
|
|
||||||
|
return dis
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
## PDR的优化总结
|
||||||
|
|
||||||
|
一、PDR优化效果不明显分析
|
||||||
|
|
||||||
|
从逻辑上来讲,PDR算法具有一定的独立位置推算能力,实际上PDR并没有非常独立的推算能力。经过分析:在卡尔曼滤波中,利用IMU + PCA计算的方向的权重非常小,所以从结果上看IMU并没有发挥其轨迹推算能力,导致PDR的效果不明显。直接调大IMU的权重,此时轨迹错乱。
|
||||||
|
|
||||||
|
二、检验PDR算法的系统效果
|
||||||
|
|
||||||
|
简单来说就让手机水平放置,使得AHRS算法输出的YAW是正确的,验证此时的PDR是否工作正常,发现此时的PDR依旧效果存在问题。经过LOG调试分析发现AHRS输出的AHRS的航向角是偏差90度。最终定位到AHRS算法默认采用的是北东地的坐标系,经过修改后能够输出正确的偏航角。此时增大IMU的融合权重,此时可以观察到PDR算法能够独立推导轨迹,效果一般。
|
||||||
|
|
||||||
|
三、优化GPS的噪声权重模型
|
||||||
|
|
||||||
|
四、卡尔曼模型优化
|
||||||
|
|
||||||
|
原版的卡尔曼滤波算法是直接融合IMU提供的方向角和GPS的方向角,在这种方式下如果磁力计受到干扰会直接导致PDR的方向出现明显偏移轨迹出错。采用的优化思路是:IMU提供角度的增量信息而不是直接提供角度。采用这种方式,整体的轨迹比较稳定。
|
||||||
|
|
||||||
|
五、性能优化
|
||||||
|
|
||||||
|
原版的PDR算法采用的每次IMU更新的时候计算加速度均值的方式判断是否静止,这种方式产生的计算量太大了,没有必要。主要利用Visual Studio的性能探查器。
|
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
|
||||||
|
## 一、群、李群、李代数
|
||||||
|
|
||||||
|
群是一种代数结构,它是由集合加运算组成的。我们把运算记作$\cdot$,群要求这个运算满足封闭性 、结合律、幺元、逆四个性质。李群是具有光滑(连续)性质的群。那么马上可以想到全体单位四元数的集合加上四元数乘法也是群,其乘法满足群要求的四个性质,由于四元数是连续的所以全体单位四元数的集合加上四元数乘法也是李群。
|
||||||
|
|
||||||
|
SO(3) : 特殊正交群
|
||||||
|
|
||||||
|
SE(3) : 特殊欧式群
|
||||||
|
|
||||||
|
## 二、视觉里程计
|
||||||
|
|
||||||
|
**2.5 回环检测**
|
||||||
|
|
||||||
|
无论是视觉SLAM还是激光SLAM,随着系统持续运行,仅仅依靠视觉里程计会导致误差不断的积累,长期运行后结果将是不可靠的。所谓回环检测:回即是回到原点,环表示系统走过的路径的轨迹是一个环形。最简单的描述就是:检测SLAM系统绕了一圈回到原来走过的地方。
|
||||||
|
|
||||||
|
## 三、误差评估
|
||||||
|
|
||||||
|
**3.1 准确率、精确率和召回率**
|
||||||
|
|
||||||
|
- TP(True Positive):正确的正例,一个实例是正类并且也被判定成正类
|
||||||
|
- FN(False Negative):错误的反例,漏报,本为正类但判定为假类
|
||||||
|
- FP(False Positive):错误的正例,误报,本为假类但判定为正类
|
||||||
|
- TN(True Negative):正确的反例,一个实例是假类并且也被判定成假类
|
||||||
|
|
||||||
|
$$
|
||||||
|
Accuracy = \frac{TP+TN}{TP+TN+FP+FN} \\
|
||||||
|
Precision = \frac{TP}{TP +FP} \\
|
||||||
|
Reacall = \frac{TP}{TP +FN}
|
||||||
|
$$
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
数学基础
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1、从点到面的距离推导
|
||||||
|
|
||||||
|
求三维空间内点$p(x_p,y_p,z_p)$到平面$Ax+By+Cz+D$的距离。
|
||||||
|
|
||||||
|
很容易知道,平面方程$Ax+By+Cz+D=0$的法向量是$\vec n = (A,B,C)$。对于过空间点p且方向向量为$\vec n$的直线为:
|
||||||
|
|
||||||
|
|
||||||
|
$$
|
||||||
|
\frac{x-x_P}{A}=\frac{y-y_p}{B}=\frac{z-z_p}{C}
|
||||||
|
$$
|
||||||
|
联立方程组:
|
||||||
|
$$
|
||||||
|
\frac{x-x_P}{A}=\frac{y-y_p}{B}=\frac{z-z_p}{C} \\
|
||||||
|
Ax+By+Cz+D=0
|
||||||
|
$$
|
||||||
|
假设三维直线和三维平面的交点为$(x_0,y_0,z_0)$
|
||||||
|
$$
|
||||||
|
\frac{x_0-x_P}{A}=\frac{y_0-y_p}{B} \\
|
||||||
|
\frac{y_0-y_p}{B}=\frac{z_0-z_p}{C} \\
|
||||||
|
Ax_0+By_0+Cz_0+D_0=0
|
||||||
|
$$
|
||||||
|
那么根据距离公式:
|
||||||
|
$$
|
||||||
|
d=\sqrt{(x_0-x_p)^2+(y_0-y_p)^2+(z_0-z_p)^2}\\
|
||||||
|
d=\sqrt{(\frac{A}{B})^2\cdot(y_0-y_p)^2+(y_0-y_p)^2+(\frac{C}{B})^2\cdot(y_0-y_p)^2}\\
|
||||||
|
d^2=\frac{A^2\cdot(y_0-y_p)^2}{B^2}+(y_0-y_p)^2+\frac{C^2}{B^2}\cdot(y_0-y_p)^2
|
||||||
|
=\frac{(A^2+B^2+C^2)}{B^2}\cdot(y_0-y_p)^2
|
||||||
|
$$
|
|
@ -0,0 +1,41 @@
|
||||||
|
# 性组合导航算法原理
|
||||||
|
|
||||||
|
一、
|
||||||
|
|
||||||
|
## 二、汽车航位推算
|
||||||
|
|
||||||
|
**1、优化思路:**
|
||||||
|
|
||||||
|
**2.1.1 增加mahony中的$[ex,ey,ez]$策略,提高精度 [2020-01-06]**
|
||||||
|
|
||||||
|
本质原因,通过调整$[ex,ey,ez]$的策略,某种意义上提高了姿态估计的准确度,从而最终提高了组合导航的精度。
|
||||||
|
|
||||||
|
**2.1.2 预积分[2020-01-06]**
|
||||||
|
|
||||||
|
简单来说,我们利用$t-1$时刻的姿态$q_{t-1}$用于重力消除。从代码结构上来讲,我们是通过先消除重力然后进行运动积分,最后进行姿态解算的过程。那么姿态的估计就会有延迟。所以理论上可以利用$q_t-1$和$gyro_t$进行预先的积分,得到“相对较准”的姿态,利用这个估计的姿态$q$进行重力消除会更加准确。
|
||||||
|
|
||||||
|
从结果试验来看,是没有太大的效果,但是也可能是其他部分做的不够好导致的。
|
||||||
|
|
||||||
|
**2.1.3 离心加速度**
|
||||||
|
|
||||||
|
从实际的试验中发现,即使是低价的MEMS传感器,在汽车的转向时会受到离心加速度的影响。因此当我们知道汽车的角速度和线速度信息的时候可以计算出离心加速度的大小,通过修正离心加速度可以提高姿态估计的准确性,最终达到提升导航定位精度的目的。
|
||||||
|
|
||||||
|
**2.1.4 轨迹融合优化**
|
||||||
|
|
||||||
|
一种比较讨巧的办法,在汽车进行隧道期间进行历史位置匹配,提高位置定位的精度。这种办法确实也应用到手机中,从高通的部分泄露的信息发现高通也会缓存也部分历史信息用于提高定位精度,不过这种办法主要是应用在汽车导航场景。主要原因在于:汽车行驶的位置是有限制的,不能在任意地方行驶。在PDR场景中,我们也会用到历史信息缓存,主要原因在用户经常带着手机沿着固定的场景跑圈,这种情况下,采用估计融合可以提高多圈轨迹叠加的一致性。
|
||||||
|
|
||||||
|
**2.1.5 EKF和Mahony对导航精度的影响**
|
||||||
|
|
||||||
|
在同时调参的情况下,两种算法的差异不大。主要原因在于核心原理是相同的。
|
||||||
|
|
||||||
|
## 三、行人航位推算
|
||||||
|
|
||||||
|
2.1 GPS协议解析
|
||||||
|
|
||||||
|
2.2 AHRS姿态解算
|
||||||
|
|
||||||
|
2.3 行人动作识别
|
||||||
|
|
||||||
|
2.4 PCA主方向分析
|
||||||
|
|
||||||
|
假设用户甩动手臂是规律的,
|
|
@ -0,0 +1,33 @@
|
||||||
|
1、查看远端仓库情况
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git remote -v
|
||||||
|
# 样例输出如下:
|
||||||
|
origin http://logzhan.ticp.io:30000/logzhan/management.git (fetch)
|
||||||
|
origin http://logzhan.ticp.io:30000/logzhan/management.git (push)
|
||||||
|
```
|
||||||
|
|
||||||
|
2、将仓库添加到本地
|
||||||
|
执行完该命令,本地项目将同时关联到私有仓库与远程仓库地址。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 命令参数:upstream 表示远程仓库别名,类似于origin
|
||||||
|
git remote add upstream 主库git地址
|
||||||
|
```
|
||||||
|
|
||||||
|
3、从主仓库更新代码
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 这句代码需要说明:这句话表示我们要从upstream的main分支拉去代码到当前分支!例如我们相把远端的A同步的本地的B
|
||||||
|
# 需要先git checkout B 然后 git fetch upsteram A
|
||||||
|
# 实际样例如下:
|
||||||
|
git fetch upstream main
|
||||||
|
```
|
||||||
|
|
||||||
|
4、推送到远程分支
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 此处的master是一个样例,根据实际情况填写要合并的分支
|
||||||
|
git merge upstream/master
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
# **Git使用教程**
|
||||||
|
|
||||||
|
## 一、Git的公钥和私钥
|
||||||
|
|
||||||
|
github支持https和ssh方式访问代码库,https是无状态传输。git传输使用rsa算法,rsa生产一对数字,一个数字用来加密,另一个数字用来解密。git中这两个数字分别是公钥public key和私钥private key。通常,公钥给服务器,本地访问远端仓库下载代码时,服务器通过公钥加密代码然后发出去,本地电脑接收时,用本地存储的私钥解密它。如果匹配,就正常下载;如果不匹配,则下载失败。
|
||||||
|
|
||||||
|
|
||||||
|
## 二、生成密钥的步骤
|
||||||
|
|
||||||
|
1、在电脑桌面,鼠标右键,选择"Git Bash Here",打开Git命令窗口;
|
||||||
|
2、在Git命令窗口中配置用户,输入如下命令:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 这里的your_name需要替换为自己的id
|
||||||
|
git config --global user.name "your_name"
|
||||||
|
```
|
||||||
|
|
||||||
|
3、继续在Git窗口中配置邮箱,输入如下命令:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git config --global user.email "xxx@xx.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
4、此时会在C:\Users\zhouxy目录下生成.gitconfig配置文件(此文件不能删除);
|
||||||
|
5、查看.gitconfig配置文件里的内容;
|
||||||
|
|
||||||
|
6、继续在Git命令窗口中输入如下命令,即可生成SSH公钥和私钥
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ssh-keygen -t rsa -C "xxx@xx.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
![image-20220827162221537](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220827162221537.png)
|
||||||
|
|
||||||
|
7、进入C:\Users\Administrator.ssh目录下,查看生成的SSH密钥
|
||||||
|
|
||||||
|
# Git基本操作
|
||||||
|
|
||||||
|
qit切换分支
|
||||||
|
|
||||||
|
```
|
||||||
|
git checkout branchName
|
||||||
|
```
|
||||||
|
|
||||||
|
## Git创建分支并提交代码
|
||||||
|
|
||||||
|
```
|
||||||
|
# 创建新的本地分支, 新本地分支的代码是从原有分支拷贝
|
||||||
|
git checkout -b newB
|
||||||
|
# 将newB提交到远程仓库
|
||||||
|
git push -u origin newB
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
|
||||||
|
## 一、Commit回退
|
||||||
|
|
||||||
|
### 1.1 从一次commit回退到某一次commit
|
||||||
|
|
||||||
|
#### 1.1.1 查看历史提交记录
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# git 查看历史commit
|
||||||
|
git log
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.1.2 复制上一次提交的commit码
|
||||||
|
|
||||||
|
<img src="./Image/Git-Commit-History.png" style="zoom:50%;" />
|
||||||
|
|
||||||
|
#### 1.1.3、输入回退命令
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git revert your_commit_code
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.2 强制回到某一次提交
|
||||||
|
|
||||||
|
在部分时候,由于版本冲突的问题,1.1 中提到的方法报冲突错误,这个时候实在没有办法可以使用`git reset --hard`命令。其步骤如下所示。值得注意的是,由于这个命令会重写历史,所以需要跟仓库的协作者进行沟通。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 先找到要回去的commit的commit号
|
||||||
|
git log
|
||||||
|
# 回到某一次提交
|
||||||
|
git reset --hard your_commit_code
|
||||||
|
# 强制推送,这是因为本地修改后提交上去会重新覆盖之前的历史,如果不force会报冲突错误。
|
||||||
|
git push -f origin your_branch
|
||||||
|
```
|
||||||
|
|
||||||
|
## 二、放弃所有文件修改 (未Commit)
|
||||||
|
|
||||||
|
**2.1 解决方法**(两种解决方法)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 方法1
|
||||||
|
git add .
|
||||||
|
git reset --hard "commit_code"
|
||||||
|
|
||||||
|
# 方法2,实际测试
|
||||||
|
git stash
|
||||||
|
git stash drop #丢弃指定条目
|
||||||
|
```
|
||||||
|
|
||||||
|
**2.1 git stash 命令**
|
||||||
|
|
||||||
|
别急,Git提供了一个**git stash命令**恰好可以完美解决该问题, 其将当前未提交的修改(即,工作区的修改和暂存区的修改)先暂时储藏起来,这样工作区干净了后,就可以切换切换到master分支下拉一个fix分支。在完成线上bug的修复工作后,重新切换到dev分支下通过**git stash pop**命令将之前储藏的修改取出来,继续进行新功能的开发工作
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Git基本操作
|
||||||
|
|
||||||
|
qit切换分支
|
||||||
|
|
||||||
|
```
|
||||||
|
git checkout branchName
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Git创建分支并提交代码
|
||||||
|
|
||||||
|
```
|
||||||
|
# 创建新的本地分支, 新本地分支的代码是从原有分支拷贝
|
||||||
|
git checkout -b newB
|
||||||
|
# 将newB提交到远程仓库
|
||||||
|
git push -u origin newB
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
https://blog.csdn.net/weixin_43729127/article/details/133185964
|
|
@ -0,0 +1,11 @@
|
||||||
|
1、Git 某次Commit 有大文件,导致Github无法提交上去
|
||||||
|
|
||||||
|
解决方案是把这个大文件从历史的所有提交剔除,如下面的命令所示:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# 使用双引号将文件路径括起来
|
||||||
|
# 当你的路径存在空格的时候容易导致命令行识别错,可以把你要删除的路径的文件加上""
|
||||||
|
git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch "your path"' --prune-empty --tag-name-filter cat -- --all
|
||||||
|
|
||||||
|
```
|
||||||
|
|
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 268 KiB |
After Width: | Height: | Size: 934 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 555 KiB |
After Width: | Height: | Size: 862 KiB |
After Width: | Height: | Size: 527 KiB |
After Width: | Height: | Size: 485 KiB |
After Width: | Height: | Size: 917 KiB |
After Width: | Height: | Size: 724 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 581 KiB |
After Width: | Height: | Size: 485 KiB |
After Width: | Height: | Size: 1.0 MiB |
After Width: | Height: | Size: 851 KiB |
After Width: | Height: | Size: 233 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 164 KiB |
After Width: | Height: | Size: 305 KiB |
After Width: | Height: | Size: 606 KiB |
After Width: | Height: | Size: 386 KiB |
After Width: | Height: | Size: 774 KiB |
After Width: | Height: | Size: 840 KiB |
|
@ -0,0 +1,120 @@
|
||||||
|
# Lighthouse定位原理
|
||||||
|
|
||||||
|
2016年,Valve携手HTC一同发布了跨时代般的VR头显:HTC VIVE,随之而来的是一套全新的空间定位技术:命名为Lighthouse的定位系统,具备高精度、高响应、轻便易用等特点,至今仍是VR全身追踪玩家首选的追踪设备。本文章详细解析Lighthouse初代系统(1.0基站系统)与不完全解析第二代系统(2017年6月发布的2.0基站系统)基站原理与追踪器定位原理,为方便理解将以1.0基站指代初代系统,2.0基站指代第二代系统。
|
||||||
|
|
||||||
|
## 一、Lighthouse定位原理:
|
||||||
|
|
||||||
|
### 1.1 Lighthouse定位架构
|
||||||
|
|
||||||
|
每个1.0基站包含一个称为同步闪光灯的红外灯阵列和俩组马达(集成激光发射器)。系统内20ms为一个扫描周期。基站的定位原理如下图所示:
|
||||||
|
|
||||||
|
<img src="./Image/positioning-principle.png" style="zoom:80%;" />
|
||||||
|
|
||||||
|
一个周期的定位过程:1、首先基站的红外灯阵列闪烁一次,发射一组红外光同步光覆盖整个扫描范围,当追踪器*1 上一组光敏(每个追踪器含有多组光敏)传感器组件搭载的光电转换芯片接收到该端光敏传感器捕捉到的来自基站的红外同步光信息后,启动全部传感器与惯性系统(IMU)并将数据清零。2、基站的X轴马达横向发射激光(旋转10ms闪烁一次后停止)3、基站的红外灯阵列再闪烁一次,追踪器捕捉到第二次红外光同步信息后将准备捕捉Y轴光数据 4、Y轴马达纵向发射激光(旋转10ms闪烁一次后停止),至基站下次红外灯阵列闪烁后代表一个扫描周期结束。如下图所示:
|
||||||
|
|
||||||
|
![](./Image/Lighthouse扫描过程.webp)
|
||||||
|
|
||||||
|
### 1.2 Lighthouse基站运行模式
|
||||||
|
|
||||||
|
1.0基站共有三种运行模式(通过按钮切换):单独A模式,有线A、B模式,无线B、C模式。一个空间内只运行一个基站时,设置为A模式或B模式均可单独运行。一个空间内运行双基站,当俩个基站设置为A模式与B模式(有线模式)时,由A模式的基站作为主基站。将线缆连接俩个基站后,B模式的基站将与A模式基站通过线缆同步扫描周期(同步红外光阵列点亮时间与马达转速、激光发射器点亮间)当基站处于B、C模式(无线模式)时,由B模式的基站作为主基站,C模式的基站上的一组光敏捕捉到B模式基站的红外同步光后,通过分析一段时间内捕捉到的红外同步光的频率便可与B基站同步扫描周期(同步红外光阵列点亮时间与马达转速、激光发射器点亮时间)当一个空间内运行双基站时,由追踪器判定使用哪一个基站的激光:当多组光敏同时捕捉到某一个基站的光信息最多时,优先使用该组基站的激光参与融合计算。
|
||||||
|
|
||||||
|
## 二、 Lighthouse基站拆解
|
||||||
|
|
||||||
|
### 2.1 基站的面板拆解
|
||||||
|
|
||||||
|
1.0基站有俩种型号,分别为9灯与15灯基站(最早生产15灯基站,2017年后生产的基站基本为9灯基站),9灯基站(红外光同步阵列含9颗灯珠)、15灯基站(红外光同步阵列含15颗灯珠)。9灯基站与15灯基站(区别为红外同步阵列灯珠数量)定位效果与原理相同,9灯阵列灯珠亮度更高。
|
||||||
|
|
||||||
|
<img src="./Image/15灯基站.png" style="zoom:33%;" />
|
||||||
|
|
||||||
|
<center>15灯基站运行图片</center>
|
||||||
|
|
||||||
|
<img src="./Image/9灯基站.png" style="zoom:33%;" />
|
||||||
|
|
||||||
|
<center>9灯基站运行图片</center>
|
||||||
|
|
||||||
|
Tracker1.0等1.0追踪器(搭载TS3633芯片)设备将与基站完成红外光同步,识别捕捉到的红外光信息为基站发出时才会进行定位。而后代更换TS4231或TSTS4631芯片的追踪器(如Tracker2018、Tracker3.0、Vive Pro头显与Vive2.0手柄等)上取消了红外光同步模式,当这类追踪器运行在1.0基站模式下,捕捉到红外光信息后将直接启动全部传感器,但无法判断是否为基站发射的同步光。当环境存在其他发射红外光的设备时,追踪器可能将其会误判为基站发射的同步光而错误定位,也就会产生所谓“干扰”丢追现象。
|
||||||
|
|
||||||
|
<img src="./Image/基站拆解图.png" alt="基站拆解图" style="zoom:67%;" />
|
||||||
|
|
||||||
|
### 2.2 Tracker 1.0跟踪器原理和拆解
|
||||||
|
|
||||||
|
每个追踪器表面都覆盖有多组光敏传感器与光电转换器。当一组光敏传感器俩次捕捉到红外同步光后,分俩次捕捉到俩组激光。随后由该组光敏组件上搭载的光电转换器(如TS3633等)开始分别计算这俩组(X轴与Y轴)激光分别到达该组光敏的角度与时间,这个时间正好是基站X轴与Y轴马达旋转到特定的面、点亮激光发射器的时间与角度(基站位置为绝对静止,马达转速与激光发射器点亮时间为已知:一组马达一个周期旋转10ms并闪烁一次),而分布在追踪器上的光敏传感器的位置也是已知的,便可依此得到一组时间差数据发送给微控制器与FPGA。追踪器通过结合多组光电转换器得到的时间差数据并融合IMU惯性系统进行计算,随后将数据发送给电脑,便可得出追踪器的绝对位置与运动轨迹。下图为Tracker1.0跟踪器的拆解图:
|
||||||
|
|
||||||
|
<img src="./Image/Tracker拆解图.png" alt="Tracker拆解图" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>Tracker1.0上覆盖的多组光敏与光电转换器</center>
|
||||||
|
|
||||||
|
<img src="./Image/Tracker1.0 Mainboard.png" style="zoom: 67%;" />
|
||||||
|
|
||||||
|
<center>Tracker1.0主板</center>
|
||||||
|
|
||||||
|
<img src="./Image/Tracker1.0主板2.png" style="zoom: 67%;" />
|
||||||
|
|
||||||
|
<center>Tracker1.0主板</center>
|
||||||
|
|
||||||
|
### 2.3 基站2.0结构和原理
|
||||||
|
|
||||||
|
第二代基站将原先俩组马达与一组红外光阵列的结构改为单马达集成俩组激光发射器,取消红外光同步模式。每组激光发射器的相对位置有差别(如下图所示),每组发射器点亮时间也略有间隔,发射的每组激光都包含信息(包括识别信息)。当搭载TS4231或TSTS4631芯片的追踪器(如Tracker2018、Tracker3.0、Vive Pro头显与Vive2.0手柄等)接收到来自2.0基站的光信息后,追踪器可快速归位并直接进入定位状态,并且可识别捕捉到的激光来自哪一个基站。
|
||||||
|
|
||||||
|
![](./Image/基站2.0原理1.png)
|
||||||
|
|
||||||
|
<center>单马达集成俩组激光发射器结构(来自网络)</center>
|
||||||
|
|
||||||
|
<img src="./Image/基站2.0原理拆解.png" alt="基站2.0原理拆解" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>单马达集成俩组激光发射器结构(来自网络)</center>
|
||||||
|
2.0基站扫描过程:马达将快速旋转至设定转速,集成的俩组激光发射器旋转至特定位置时,间隔几纳秒分别闪烁一次,呈V字形发射X、Y轴激光。激光组件闪烁俩次后至下一次旋转到特定位置并再次闪烁前为一个扫描周期。如下图所示:
|
||||||
|
|
||||||
|
<img src="./Image/基站2.0扫描过程.webp" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>2.0基站运行过程(来自网络)</center>
|
||||||
|
|
||||||
|
2.0基站取消了红外光同步模式而改为激光通讯,使得每个基站可独立运行(多基站需要设置信道,理论最多16个基站同时运行)且启动、恢复对比1.0基站更加迅速,但不再兼容旧款搭载TS3633芯片(无法解码短波激光信息)的追踪器(如Tracker1.0,Vive初代头显与Vive 1.0手柄等)。**单马达结构也存在弊端**。集成俩组激光发射器且转速非常高的马达更容易损耗。当系统中某个基站上的一组激光发射器出现老化或马达转速异常时,将直接影响到整个系统的定位稳定性。且独立运行且基站间无同步的工作模式更容易导致多个基站之间发射的激光频率产生差异。一个空间内同时运行多个基站时,如果每个基站的相对位置过于紧凑或都处于同一平面(扫描区域重合较多)可能会导致追踪器对多个方向的激光束接收混乱,产生所谓“干扰”丢追现象。
|
||||||
|
|
||||||
|
### 2.4 基站2.0模式下追踪器定位原理
|
||||||
|
|
||||||
|
每个追踪器表面都覆盖有多组光敏传感器与光电转换器。当一组光敏传感器俩次捕捉到来自基站的激光后,由该组光敏组件上搭载的光电转换器(TS4231或TS4631)开始解码短波激光信息并分别计算这俩组(X轴与Y轴)激光到达该组光敏的角度与时间,这个时间正好是基站俩组激光发射器旋转至特定位置的时间与发射激光的角度(基站位置为绝对静止,马达转速与激光发射器点亮时间为已知)而分布在追踪器上的光敏传感器的位置也是已知的,便可依此得到一组时间差数据发送给微控制器与FPGA。追踪器通过结合多组光电转换器得到的时间差数据并融合IMU惯性系统进行计算,随后将数据发送给电脑,便可得出追踪器的绝对位置与运动轨迹。
|
||||||
|
|
||||||
|
<img src="./Image/Tracker2.0主板.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>Tracker2.0上覆盖的多组光敏传感器与光电转换器(来自网络)</center>
|
||||||
|
|
||||||
|
Tracker2018拆解图如下图所示:
|
||||||
|
|
||||||
|
<img src="./Image/Tracker2.0主板1.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>Tracker2018搭载的TS4231芯片将刷新率从上一代TS3633的60Hz提升到了100Hz,效率更高</center>
|
||||||
|
|
||||||
|
<img src="./Image/Tracker2.0主板2.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>Tracker2018主板</center>
|
||||||
|
|
||||||
|
<img src="./Image/Tracker2.0主板3.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>Tracker2018使用ATSAMG55微处理器</center>
|
||||||
|
|
||||||
|
### 2.5 Tracker3.0拆解图
|
||||||
|
|
||||||
|
Tracker3.0压缩了体积,但保持了覆盖光敏组件的数量。
|
||||||
|
|
||||||
|
<img src="./Image/Tracker3.0.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<img src="./Image/Tracker3.0-光敏模组.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>Tracker3.0上搭载的TS4631芯片</center>
|
||||||
|
|
||||||
|
<img src="./Image/Tracker3.0-主板.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>Tracker3.0上的主板</center>
|
||||||
|
|
||||||
|
<img src="./Image/Tracker3.0-主板2.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>Tracker3.0上的主板</center>
|
||||||
|
|
||||||
|
<img src="./Image/Tracker3.0-手柄TS4631.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>Index手柄上搭载的TS4631芯片特写:</center>
|
||||||
|
|
||||||
|
<img src="./Image/TundraTracker-TS4631.png" style="zoom:67%;" />
|
||||||
|
|
||||||
|
<center>N7R似乎采用的是和HTC同款方案,效果却不及HTC</center>
|
|
@ -0,0 +1,57 @@
|
||||||
|
import os
|
||||||
|
import chardet
|
||||||
|
import codecs
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
|
|
||||||
|
# 获取给定目录中的所有文件和子目录
|
||||||
|
def get_all_files(directory):
|
||||||
|
files = []
|
||||||
|
# 遍历目录中的所有文件和子目录
|
||||||
|
for root, subdirs, files_list in os.walk(directory):
|
||||||
|
for file in files_list:
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
files.append(file_path)
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
# 检测文件编码格式
|
||||||
|
def detect_encoding(file_path):
|
||||||
|
with open(file_path, 'rb') as file:
|
||||||
|
raw_data = file.read(8192)
|
||||||
|
return chardet.detect(raw_data)['encoding']
|
||||||
|
|
||||||
|
|
||||||
|
# 将文件转换为UTF-8编码格式
|
||||||
|
def convert_to_utf8(file_path, from_encoding):
|
||||||
|
with codecs.open(file_path, 'r', encoding=from_encoding, errors='ignore') as file:
|
||||||
|
lines = file.read()
|
||||||
|
with codecs.open(file_path, 'w', encoding='utf-8') as file:
|
||||||
|
file.write(lines)
|
||||||
|
|
||||||
|
|
||||||
|
# 将给定目录下的所有文件转换为UTF-8编码格式
|
||||||
|
def convert_files_in_directory(directory_path):
|
||||||
|
files = get_all_files(directory_path)
|
||||||
|
for file in files:
|
||||||
|
if file.endswith('.py') or file.endswith('.c') or file.endswith('.cpp') or file.endswith('.h'):
|
||||||
|
from_encoding = detect_encoding(file)
|
||||||
|
if from_encoding != 'utf-8':
|
||||||
|
print("file = " + file + "encoding = " + from_encoding)
|
||||||
|
convert_to_utf8(file, from_encoding)
|
||||||
|
print('所有文件均已转换为UTF-8编码格式')
|
||||||
|
|
||||||
|
|
||||||
|
# 按钮单击时执行的函数
|
||||||
|
def browse_folder():
|
||||||
|
folder_path = filedialog.askdirectory()
|
||||||
|
convert_files_in_directory(folder_path)
|
||||||
|
|
||||||
|
|
||||||
|
# 创建一个Tkinter窗口,其中包含一个选择文件夹的按钮
|
||||||
|
window = tk.Tk()
|
||||||
|
window.geometry('200x100')
|
||||||
|
button = tk.Button(text='选择文件夹', command=browse_folder)
|
||||||
|
button.pack()
|
||||||
|
window.mainloop()
|
|
@ -0,0 +1,7 @@
|
||||||
|
**一、删除面:**插入->面->删除面
|
||||||
|
|
||||||
|
<img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230506002227482.png" alt="image-20230506002227482" style="zoom:50%;" />
|
||||||
|
|
||||||
|
二、基本操作
|
||||||
|
|
||||||
|
平移:Ctrl + 鼠标滚轮
|
|
@ -0,0 +1,33 @@
|
||||||
|
## 一、Room Definition Violation
|
||||||
|
|
||||||
|
[Room Definition Violation] GeekIMU.PcbDoc Advanced PCB Room Definition: Between Room Sensor
|
||||||
|
|
||||||
|
主要解决方案是在DRC检查的时候,删除掉不用的ROOM。
|
||||||
|
|
||||||
|
## 二、Minimum Solder Mask Sliver Constraint
|
||||||
|
|
||||||
|
这个问题主要描述的是两个焊盘之间,阻焊层的最小间距。如果阻焊层的宽度过小,PCB在生产的时候可能导致阻焊层制造失败。如下图所示:
|
||||||
|
|
||||||
|
[Minimum Solder Mask Sliver Constraint Violation] GeekIMU.PcbDoc Advanced PCB Minimum Solder Mask Sliver Constraint: (4.842mil < 10mil)
|
||||||
|
|
||||||
|
<img src="E:\技术武器库\技术开发笔记\硬件开发笔记\Altium Designer\Image\Minimum Solder Mask Sliver.png" style="zoom:50%;" />
|
||||||
|
|
||||||
|
解决方案:在Design -> Rule -> Manufacturing中,找到Minimum Solder Mask Sliver。设置4mil即可。
|
||||||
|
|
||||||
|
## 三、Silk To Solder Mask Clearance
|
||||||
|
|
||||||
|
这个地方设置的是丝印到阻焊层的最小距离。
|
||||||
|
|
||||||
|
<img src="E:\技术武器库\技术开发笔记\硬件开发笔记\Altium Designer\Image\Silk To Solder Mask Clearance.png" style="zoom: 67%;" />
|
||||||
|
|
||||||
|
解决方案:在Design -> Rule -> Manufacturing中,找到Silk To Solder Mask Clearance,设置为0mil即可。
|
||||||
|
|
||||||
|
## 四、Hole Size Constrain
|
||||||
|
|
||||||
|
这个描述是最大孔径,默认是100mil,在生产制造的时候,如果挖的孔太大,可能机器的钻头无法钻出这么大的孔,如果生产能力满足,直接把规则设大即可。
|
||||||
|
|
||||||
|
解决方案:在Design -> Rule -> Manufacturing中,找到Hole,设置为合适值即可。
|
||||||
|
|
||||||
|
## 五、Silk To Silk Clearance Constraint
|
||||||
|
|
||||||
|
描述的是丝印之间的最小间距,这个问题不大,大不了就是丝印混在一起了。有时候真不好处理,可以设置为0mil。
|
|
@ -0,0 +1,133 @@
|
||||||
|
|
||||||
|
|
||||||
|
# 使用颜色突出显示网络——Altium Designer 笔记
|
||||||
|
|
||||||
|
* [在原理图编辑器中设置网络颜色](#_4)
|
||||||
|
* [在 PCB 编辑器中设置网络颜色](#_PCB__20)
|
||||||
|
* * [在 PCB 中网络的两种表示方式](#_PCB__23)
|
||||||
|
* [在 PCB 中网络的两个颜色设置](#_PCB__33)
|
||||||
|
* * [基本模式——图层和网络颜色的混合图案](#_53)
|
||||||
|
* [缩小行为——图层或网络颜色占主导](#_60)
|
||||||
|
* [设置和显示网络颜色](#_84)
|
||||||
|
* [在原理图和 PCB 之间传输颜色](#_PCB__102)
|
||||||
|
|
||||||
|
在[原理图](https://so.csdn.net/so/search?q=%E5%8E%9F%E7%90%86%E5%9B%BE&spm=1001.2101.3001.7020)编辑器中设置网络颜色
|
||||||
|
=====================================================================================================
|
||||||
|
|
||||||
|
使用 view > Set Net Colors 命令,可以在原理图编辑器中将高亮颜色应用于网络或总线。**请注意,网络颜色设置无法撤消**,要删除颜色设置,请使用 “Clear Net Color” 命令或 “Clear All Net Colors” 命令。
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/9d309b678fac4388a06cb803f34b4ecb.png?x-oss-process=image,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_13,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
||||||
|
|
||||||
|
设置原理图网络颜色
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/fce84713b7cf4e46aa67d61049d65bf8.png#pic_center)
|
||||||
|
|
||||||
|
网络颜色效果图
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
在 PCB 编辑器中设置网络颜色
|
||||||
|
================
|
||||||
|
|
||||||
|
在 PCB 中网络的两种表示方式
|
||||||
|
----------------
|
||||||
|
|
||||||
|
在 PCB 编辑器中,一个网络有两种表示方式;作为未布线的**连接线**或由一系列轨道段定义的**布线网络**。
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/57a7a6d8b7cb4df8ba912506da9c97c3.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
||||||
|
|
||||||
|
连接线和布线网络
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
在 PCB 中网络的两个颜色设置
|
||||||
|
----------------
|
||||||
|
|
||||||
|
在 PCB 编辑器中,一个网络有两个颜色设置;**图层** (layer) 颜色和**网络**颜色。网络颜色始终应用于连接线。布线网络可以以图层颜色或网络颜色显示。
|
||||||
|
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/b77a9f3e75624e81994361fd6d45e4d1.png#pic_center)
|
||||||
|
|
||||||
|
图层颜色
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/68cba868c811419eba4aa39696fb125f.png#pic_center)
|
||||||
|
|
||||||
|
网络颜色
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/34f4acb3865047f98315035bb2d4ef69.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
||||||
|
|
||||||
|
图层颜色和网络颜色效果图(**开和关闭可以通过F5完成开启和关闭**)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 基本模式——图层和网络颜色的混合图案
|
||||||
|
|
||||||
|
打开首选项(界面右上角齿轮图案),在 PCB Editor > Board Insight Color Overrides 界面可以设置图层颜色和网络颜色混合的基本图案。
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/de7bab4d458046538d982fa60c198638.png#pic_center)
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/c08f31ef94714459bc1781b70c1485d0.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
||||||
|
|
||||||
|
### 缩小行为——图层或网络颜色占主导
|
||||||
|
|
||||||
|
打开首选项(界面右上角齿轮图案),在 PCB Editor > Board Insight Color Overrides 界面可以设置缩小行为。
|
||||||
|
|
||||||
|
缩小时,此显示行为可以是:
|
||||||
|
|
||||||
|
* 缩小时保持不变(基本图案比例),或
|
||||||
|
* 图案可以逐渐消失以恢复图层颜色(图层颜色占主导地位),或
|
||||||
|
* 覆盖颜色 (即网络颜色) 可以加强(覆盖颜色占主导地位)。
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/ce449c4bd0e247b2b06a278705b731e7.png#pic_center)
|
||||||
|
|
||||||
|
缩小时保持不变(基本图案比例)
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/8696b749d33040cf89d6f41a42dde414.png#pic_center)
|
||||||
|
|
||||||
|
图案可以逐渐消失以恢复图层颜色(图层颜色占主导地位)
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/21d5bed5306a490abcf0e01abb9296b0.png#pic_center)
|
||||||
|
|
||||||
|
覆盖颜色 (即网络颜色) 可以加强(覆盖颜色占主导地位)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
设置和显示网络颜色
|
||||||
|
---------
|
||||||
|
|
||||||
|
在 PCB 编辑器的 PCB 面板中 (如果没有此面板,左下角 Panels 可以调出) ,选择 `Nets` 模式,点击 `All Net` 显示所有网络,右键单击选定的网络并选择 `Change Net Color` 命令可以设置网络颜色。
|
||||||
|
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/7c87804e10634f1a90796e04aee284fa.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
||||||
|
|
||||||
|
设置 PCB 网络颜色
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
布线网络默认是显示为其所在图层的**图层颜色**,要显示**网络颜色**则需要如上图所示,勾选网络以启用网络颜色。如果勾选后没有显示网络颜色,可以按下快捷键 F5 全局启用 / 禁用网络颜色显示,或在右下角 Panels 调出 View Configuration 面板,然后在 View Options 标签中使用 Net Color Override 按钮启用 / 禁用网络颜色显示。
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/99f737d065d54a55a5d28e3b241d1e81.png?x-oss-process=image,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_9,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/e7e8bef9bb6c4ea9b28c30655c134470.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_18,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
||||||
|
|
||||||
|
在原理图和 PCB 之间传输颜色
|
||||||
|
================
|
||||||
|
|
||||||
|
通过 Design > Update 命令,可以在原理图和 PCB 编辑器之间(双向)传输网络颜色。在工程变更单 (ECO) 中仅需勾选 Change Net Colors 项中的变更即可。
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/ad8e44b2bcd444e192675ac54567ff55.png?x-oss-process=image,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
||||||
|
|
||||||
|
|
||||||
|
如果颜色没有转移,请检查 Project > Project Options 对话框中是否启用了以下选项 :
|
||||||
|
|
||||||
|
* Comparato 选项卡:与网络相关的差异 —— 更改网络颜色
|
||||||
|
* ECO Generation 选项卡:与网络相关的修改 —— 更改网络颜色
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/3e426ad191c74b48ae077d306dc3839a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
||||||
|
|
||||||
|
![在这里插入图片描述](https://img-blog.csdnimg.cn/ee674ac8152b41caa776a2f551300450.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQmVuQmVuRjE5,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
|
|
@ -0,0 +1,4 @@
|
||||||
|
**元件水平翻转和垂直翻转** : 选中元件,鼠标左键按住同时 + 按下X按键\Y按键实现X轴和Y轴水平翻转
|
||||||
|
|
||||||
|
**元件旋转:**选中元件,**鼠标放松**,按下空格键
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
## 一、PCB板子形状重新定义
|
||||||
|
|
||||||
|
如下图所示,我们按住Shirt的同时点击紫色的机械层边框。然后找到设计(Design)->板子形状->按照选择的形状定义。
|
||||||
|
|
||||||
|
<img src="E:\技术武器库\技术开发笔记\硬件开发笔记\Altium Designer\Image\PCB_Board_Def.jpg" style="zoom:50%;" />
|
||||||
|
|
||||||
|
Altium Designer选项如下图所示:
|
||||||
|
|
||||||
|
<img src="E:\技术武器库\技术开发笔记\硬件开发笔记\Altium Designer\Image\PCB_Board_Def_Shape.jpg" style="zoom:50%;" />
|
||||||
|
|
||||||
|
## 二、元件的强制删除
|
||||||
|
|
||||||
|
部分情况下,我们在Altium Designer选中元件后,点击DEL无法起到删除的作用。此时Ctrl + DEL可以快速完成删除操作。
|
||||||
|
|
||||||
|
## 三、原理图自动分配位号
|
||||||
|
|
||||||
|
操作快捷键(TAA) 打开原理图图注配置,选择更新更改列表、接收更改。
|
||||||
|
|
||||||
|
<img src="E:\技术武器库\技术开发笔记\硬件开发笔记\Altium Designer\Image\Altium_SCH_Mark.png" alt="image-20230416152400400" style="zoom:50%;" />
|
|
@ -0,0 +1,13 @@
|
||||||
|
Altium Designer 常见问题解决方案
|
||||||
|
|
||||||
|
## 一、元件无法对齐 & 元件拖动步距过大
|
||||||
|
|
||||||
|
这是以为栅格的最小步长太小了,元件存在拖动无法对齐的问题。解决方案:视图(View) -> 栅格(Gird) -> 设置捕捉栅格(Set Snap Gird)。点击后弹出对话框,我们可以把最小的栅格修改变小。那么画图的时候会更加精确。
|
||||||
|
|
||||||
|
二、原理图修改样式和尺寸
|
||||||
|
|
||||||
|
部分原理图偏小,导致一个项目的原理图需要多个文件才能绘制完。可以把A4的原理图修改为A3.
|
||||||
|
|
||||||
|
<img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230416151604248.png" alt="image-20230416151604248" style="zoom:50%;" />
|
||||||
|
|
||||||
|
鼠标点击原理图,在右侧的Properties中就可以看到原理图的选项。一般我们选择标准的原理图大小。复杂一点的项目可以选择A3。方向一般选择Landsapce(水平)。Title一般用于记录公司、时间、作者等信息。
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Altium Designer必要设置
|
||||||
|
|
||||||
|
一、Altium Designer的层叠设置
|
||||||
|
|
||||||
|
如下图所示,在设计(Design)选项中可以找到Layer Stack Manager,其描述如下图所示:
|
||||||
|
|
||||||
|
<img src="E:\技术武器库\技术开发笔记\硬件开发笔记\Altium Designer\Image\PCB_LayerStackSetting.jpg" style="zoom: 33%;" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| 层次描述 | 作用 | 注解 |
|
||||||
|
| ------------ | ------------------------------------------------------------ | ------------------------------------------------------- |
|
||||||
|
| Top Overlay | Top Overlay是指PCB板顶部的覆盖层,通常包括PCB板的标识、标志、文字、线条和图形等信息。<br/>Top Overlay层通常是由PCB设计师在设计软件中添加的,用于标识和说明PCB板上各个元件、电路和功能的位置和用途。 | 一般是需要在最顶层或者最底层。 |
|
||||||
|
| Dielectric | 这个层是绝缘层,用于不同层之间绝缘 | |
|
||||||
|
| Signal & Gnd | 信号层或者地层 | 上图稚晖君把GND放在第三层,如果有射频可以考虑放在第二层 |
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
## Altium Designer 3D 渲染设置
|
||||||
|
|
||||||
|
Altium Designer的3D渲染设置,可以在右下角找到Panel, 然后 选择View Configraution
|
||||||
|
|
||||||
|
<img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230319152206373.png" alt="image-20230319152206373" style="zoom: 50%;" />
|
||||||
|
|
||||||
|
View Configuration的界面如下图所示,在Configuration中我们可以选择不同颜色的板子。比较主要注意的是Projection选项中的Orthographic和Perspective的区别。当我们选择的Orthographic模式的时候,3D渲染会显得非常的畸形。Perspective则是正常的近大远小的透视关系。
|
||||||
|
|
||||||
|
<img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230319152314180.png" alt="image-20230319152314180" style="zoom:50%;" />
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Altium Designer绘制PCB高频必要功能
|
||||||
|
|
||||||
|
## 一、布线操作
|
||||||
|
|
||||||
|
#### 1.1、基础操作快捷键
|
||||||
|
|
||||||
|
- `Ctrl + Shitf + 滚轮` :布线的时候添加过孔
|
||||||
|
- `Tab` : 布线的时候可以暂定调整参数并会记忆此参数
|
||||||
|
- `T + M` : 清除错误的标记
|
||||||
|
|
||||||
|
## 二、电路板检查
|
||||||
|
|
||||||
|
#### 2.1、电路板布线完整性检查
|
||||||
|
|
||||||
|
在画完PCB后,很有可能会出现存在未布线的情况或者其他违反电气规则的情况,所以在项目的结尾必须进行电路板的布线检查。在`Altium Designer 18`的版本中,采用`DRC`可以进行布线和电气的检查。
|
|
@ -0,0 +1,15 @@
|
||||||
|
## 一、高亮网络
|
||||||
|
|
||||||
|
这个功能非常的核心,它可以高亮整个网络,可以这个功能观察布线是否完成,线路的整体走势如何。一旦高亮显示网络,那么其他的网络的透明度会降低,甚至进入3D模式,网络也是高亮的。操作步骤如下:
|
||||||
|
|
||||||
|
**高亮网络 :**选中网络、Cirl + 鼠标左键单击
|
||||||
|
|
||||||
|
**关闭高亮网络:**选中网络、Cirl + 鼠标左键双击
|
||||||
|
|
||||||
|
## 二、Altium Designer 元件的透明度设置
|
||||||
|
|
||||||
|
在Altium Designer中,选中元件后,可以在properties中设置3D body的Opacity,这个参数可以控制3D渲染时3D元器件的透明度。对于部分对其他遮挡严重的器件,可以适当调整透明度,实现更好的渲染呈现。
|
||||||
|
|
||||||
|
## 三、Altium Designer 铺铜隐藏
|
||||||
|
|
||||||
|
在画电路板的时候,由于铺铜的存在,其会导致其他的线路被掩盖,导致我们无法看清其他的布线,我们可以在View Configuration中找到IObject visibity,
|
|
@ -0,0 +1,37 @@
|
||||||
|
一、Altium 编辑技巧总结
|
||||||
|
1、连线过孔
|
||||||
|
在Altium连线时,经常需要用到过孔功能。在连线模式下,Ctrl + Shift + 鼠标滚轮即可直接调用PCB过孔功能并反转到对应的PCB层。
|
||||||
|
2、PCB原理图生成PCB板图
|
||||||
|
在绘制好PCB图并完成原理图检查之后且保证每个原件被正确的添加封装之后,选择Design -> Update PCB document ***.PCB。
|
||||||
|
3、设置PCB的形状
|
||||||
|
在PCB的keep out layer层,用线绘制工具绘制封闭的图形,然后选取绘制的图形。选择Design -> Board Shape - > Define from select object。即可设置PCB的形状。
|
||||||
|
4、线与过孔的距离
|
||||||
|
在绘制线和过孔很难避免的就是线与过孔之间的距离,这个安全距离和厂家的技术参数有关系。就国内的店铺而言,可以支持5mil的安全距离。该参数的设置如下图所示。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
5、添加原件库
|
||||||
|
Altium的可以通过侧边栏的Library窗口添加所需要的元件库。这里的元件库可以是原理图库和PCB库。建议这两样同时匹配添加。方法 Librarires -> Add Library。注意这个功能需要在手动指定添加的类型。如下图所示。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
二、PCB打样总结
|
||||||
|
1、过孔大小
|
||||||
|
一般来说,大部分店铺支持的是0.3mm(12mil)的过孔大小。在条件允许的情况下,选择12mil(内)-18mil(外)的过孔的性价比高。价格比较便宜。
|
||||||
|
2、线宽
|
||||||
|
一般来说,线宽一些店铺可以支持到5mil,如果较为常规的技术参数而言,选择6mil性价比要高一些,主要是便宜。
|
||||||
|
3、PCB层数
|
||||||
|
对于常规参数的双层板而言,50元10片/ 2 - 3天工期。对于四层板而言,需要约200元/10片打样价格。
|
||||||
|
4、PCB颜色
|
||||||
|
一些店铺采用黑色的PCB板需要加30元左右的费用。最便宜的是绿油。当然也有一些店铺并不区分颜色和价格。
|
After Width: | Height: | Size: 472 KiB |
After Width: | Height: | Size: 179 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 380 KiB |
After Width: | Height: | Size: 39 KiB |