卡尔曼滤波(Kalman Filter)

2023-05-16

卡尔曼滤波(Kalman Filter)

微信公众号:幼儿园的学霸
个人的学习笔记,关于OpenCV,关于机器学习, …。问题或建议,请公众号留言;

目录

[TOC]

what is Kalman Filter

举个例子,对于雷达来说,我们感兴趣的是其能够跟踪目标,但对目标的位置、速度、加速度的测量值往往存在噪声。卡尔曼滤波利用目标的动态信息,设法去掉噪声的影像,得到一个关于目标位置的好的估计。这个估计可以是对当前目标位置的估计(滤波),也可以是对于将来位置的估计(预测),也可以是对过去位置的估计(插值或者平滑)。

卡尔曼滤波器的两个重要假设

1.被建模的系统是线性的:K时刻的系统状态可以用某个矩阵与K-1时刻的系统状态的乘积表示;
2.影像测量的噪声属于高斯分布的白噪声(White Gaussian Noise):噪声与时间不相关,且只用均值和协方差就可以准确地为幅值建模(也就是噪声完全由一阶矩和二阶距描述)。

卡尔曼滤波理论回顾

首先对于离散控制系统,其系统状态和系统测量值可进行以下表示:

X(k) = A*X(k-1) + B*U(k) + W(k)    

Z(k) = H*X(k) + V(k)     

X(k):系统k时刻状态
A:状态转移矩阵,对应opencv里kalman滤波器的transitionMatrix矩阵(关于opencv kalman滤波器详细定义会在2中给出)
B:控制输入矩阵,对应opencv里kalman滤波器的controlMatrix矩阵
U(k):k时刻对系统的控制量
Z(k): k时刻的测量值
H:系统测量矩阵,对应opencv里kalman滤波器的measurementMatrix矩阵
W(k):系统过程噪声,为高斯白噪声,协方差为Q,对应opencv里的kalman滤波器的processNoiseCov矩阵
V(k): 测量噪声,也为高斯白噪声,协方差为R,对应opencv里的kalman滤波器的measurementNoiseCov矩阵

对于满足上面的条件(线性随机微分系统,过程和测量都是高斯白噪声),卡尔曼滤波器是最优的信息处理器。
接下来便是核心的5个公式。
卡尔曼滤波公式

这5个式子可分成3部分看。
第一部分:
式(1)-(2):预测值的计算
式(1):计算基于k-1时刻状态对k时刻系统状态的预测值
X(k|k-1):基于k-1时刻状态对k时刻状态的预测值,对应opencv里kalman滤波器的predict()输出,即statePre矩阵
X(k-1|k-1):k-1时刻状态的最优结果,对应opencv里kalman滤波器的上一次状态的statePost矩阵
U(k): k时刻的系统控制量,无则为0
A: 状态转移矩阵,对应opencv里kalman滤波器的transitionMatrix矩阵
B: 控制输入矩阵,对应opencv里kalman滤波器的controlMatrix矩阵
式(2):计算X(k|k-1)对应的协方差的预测值
P(k|k-1): 基于k-1时刻的协方差计算k时刻协方差的预测值,对应opencv里kalman滤波器的errorCovPre矩阵
P(k-1|k-1):k-1时刻协方差的最优结果,对应opencv里kalman滤波器的上一次状态的errorCovPost矩阵
Q: 系统过程噪声协方差,对应opencv里kalman滤波器的processNoiseCov矩阵
第二部分:
式(3):增益的计算
Kg(k):k时刻的kalman增益,为估计量的方差占总方差(估计量方差和测量方差)的比重,对应opencv里kalman滤波器的gain矩阵
H:系统测量矩阵,对应opencv里kalman滤波器的measurementMatrix矩阵
R:测量噪声协方差,对应opencv里的kalman滤波器的measurementNoiseCov矩阵
第三部分:
式(4)--(5):k时刻的更新
式(4):计算k时刻系统状态最优值
X(k|k):k时刻系统状态的最优结果,对应opencv里kalman滤波器的k时刻状态的statePost矩阵
Z(k):k时刻系统测量值
式(5):计算k时刻系统最优结果对应的协方差
P(k|k):k时刻系统最优结果对应的协方差,对应opencv里kalman滤波器的errorCovPost矩阵

以上便是Kalman的核心部分
运行(1)(2)-(3)-(4)(5)-(1)(2)…
输出即为X(k|k),k时刻系统状态最优估计值.
运行流程见下图所示
卡尔曼滤波器运行流程

OpenCV中的KalmanFilter详解

KalmanFilter类注释说明

OpenCV中有两个版本的卡尔曼滤波方法KalmanFilter(C++)和CvKalman©,用法差不太多,这里只介绍KalmanFilter。

C++版本中将KalmanFilter封装到一个类中,其结构如下所示:

class CV_EXPORTS_W KalmanFilter
{
public:    
    CV_WRAP KalmanFilter(); //构造默认KalmanFilter对象
    CV_WRAP KalmanFilter(int dynamParams, //状态的维数
        int measureParams, //测量的维数
        int controlParams=0, //控制量的维数
        int type=CV_32F//创建矩阵类型(CV_32F or CV_64F)
        ); //完整构造KalmanFilter对象方法
    void init(int dynamParams, int measureParams, int controlParams=0, int type=CV_32F); //初始化KalmanFilter对象,会替换原来的KF对象
  
    CV_WRAP const Mat& predict(const Mat& control=Mat()); //计算预测的状态值    
    CV_WRAP const Mat& correct(const Mat& measurement); //根据测量值更新状态值
 
    Mat statePre;            //预测值 (x'(k)): x(k)=A*x(k-1)+B*u(k)
    Mat statePost;           //状态值 (x(k)): x(k)=x'(k)+K(k)*(z(k)-H*x'(k))
    Mat transitionMatrix;    //状态转移矩阵 A
    Mat controlMatrix;       //控制矩阵 B 
    Mat measurementMatrix;   //测量矩阵 H
    Mat processNoiseCov;     //系统误差 Q
    Mat measurementNoiseCov; //测量误差 R
    Mat errorCovPre;         //最小均方误差 (P'(k)): P'(k)=A*P(k-1)*At + Q)
    Mat gain;                //卡尔曼增益   (K(k)): K(k)=P'(k)*Ht*inv(H*P'(k)*Ht+R)
    Mat errorCovPost;        //修正的最小均方误差 (P(k)): P(k)=(I-K(k)*H)*P'(k)
 
    // 临时矩阵
    Mat temp1;
    Mat temp2;
    Mat temp3;
    Mat temp4;
    Mat temp5;
};
 
enum
{
    OPTFLOW_USE_INITIAL_FLOW = CV_LKFLOW_INITIAL_GUESSES,
    OPTFLOW_LK_GET_MIN_EIGENVALS = CV_LKFLOW_GET_MIN_EIGENVALS,
    OPTFLOW_FARNEBACK_GAUSSIAN = 256
};

只有四个方法:

  • 构造KF对象KalmanFilter(DP,MP,CP)
  • 初始化KF对象init(DP,MP,CP)
  • 预测predict( )
  • 更新correct( )。

除非你要重新构造KF对象,否则用不到init( )。而KalmanFilter(DP,MP,CP)和init( )就是赋值,用来构造或者初始化KF对象。
注意:KalmanFilter结构体中并没有测量值,测量值需要自己定义,而且一定要定义,因为后面要用。

KalmanFilter编程步骤

  • step1:定义KalmanFilter类并初始化
//构造KF对象
KalmanFilter KF(DP, MP, 0);

//初始化相关参数
KF.transitionMatrix //转移矩阵 A
KF.measurementMatrix //测量矩阵 H
KF.processNoiseCov//过程噪声 Q
KF.measurementNoiseCov//测量噪声 R
KF.errorCovPost//最小均方误差 P
KF.statePost//系统初始状态 x(0)
Mat measurement//定义初始测量值 z(0)
  • step2:预测
KF.predict( ) //返回的是下一时刻的状态值KF.statePost (k+1)
  • step3:更新
//更新measurement;
//注意measurement不能通过观测方程进行计算得到,要自己定义!

//更新KF
KF.correct(measurement)

//最终的结果应该是更新后的statePost.

相关参数的确定

对于系统状态方程,简记为Y=AX+B,X和Y是表示系统状态的列向量,A是转移矩阵,B是其他项。
状态值(向量)只要能表示系统的状态即可,状态值的维数决定了转移矩阵A的维数,比如X和Y是NX1的,则A是NXN的。
A的确定跟X有关,只要保证方程中不相干项的系数为0即可,看下面例子

  • X和Y是二维的,

[ x y ] = [ 1 0 0 1 ] ∗ [ x y ] + B \left[ \begin{matrix} x \\ y \end{matrix} \right] = \left[ \begin{matrix} 1 & 0 \\ 0 & 1 \end{matrix} \right] * \left[ \begin{matrix} x \\ y \end{matrix} \right] + B [xy]=[1001][xy]+B

对于二维的变量,我看到用法比较多的是如下这种形式的(可以这样理解:x’ = x+dx):

为什么状态值一般都设置成(x,y,△x,△y)?我们不妨设置成(x,y,△x),对应的转移矩阵也改成3×3的。可以看到仍能跟上,不过在x方向跟踪速度快,在y方向跟踪速度慢。进一步设置成(x,y)和2×2的转移矩阵,程序的跟踪速度简直是龟速。所以,简单理解,△x和△y严重影响对应方向上的跟踪速度。

[ x − y − d x d y ] = [ 1 0 1 0 0 1 0 1 0 0 1 0 0 0 0 1 ] ∗ [ x y d x d y ] + B \left[ \begin{matrix} x^- \\ y^- \\ dx \\ dy \end{matrix} \right] = \left[ \begin{matrix} 1 & 0 & 1 & 0\\ 0 & 1 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{matrix} \right] * \left[ \begin{matrix} x \\ y \\ dx \\ dy \end{matrix} \right] + B xydxdy=1000010010100101xydxdy+B

  • x、y、z是三维的

[ x y z ] = [ 1 0 0 0 1 0 0 0 1 ] ∗ [ x y z ] + B \left[ \begin{matrix} x \\ y \\ z \\ \end{matrix} \right] = \left[ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{matrix} \right] * \left[ \begin{matrix} x \\ y \\ z \end{matrix} \right] + B xyz=100010001xyz+B

  • x、y是三维的,但x和dx是相关项,此时按照矩阵元素排列形式,有如下两种形式

[ x y d x ] = [ 1 0 1 0 1 0 0 0 1 ] ∗ [ x y d x ] + B \left[ \begin{matrix} x \\ y \\ dx \\ \end{matrix} \right] = \left[ \begin{matrix} 1 & 0 & 1 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{matrix} \right] * \left[ \begin{matrix} x \\ y \\ dx \end{matrix} \right] + B xydx=100010101xydx+B

[ x d x y ] = [ 1 1 0 0 1 0 0 0 1 ] ∗ [ x d x y ] + B \left[ \begin{matrix} x \\ dx \\ y \\ \end{matrix} \right] = \left[ \begin{matrix} 1 & 1 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{matrix} \right] * \left[ \begin{matrix} x \\ dx \\ y \end{matrix} \right] + B xdxy=100110001xdxy+B
即:X1=X+dX,依次类推。所以这个矩阵还是很容易却确定的,可以根据自己的实际情况定制转移矩阵。
当然上面转移矩阵中并不一定得是1和0,也可以是其他值。

OpenCVKalmanFilter编程示例

点的圆周运动预测

//====================================================================//
// Created by liheng on 19-2-26.
//Program:OpenCV自带的卡尔曼滤波器示例
//Data:2019.2.26
//Author:liheng
//Version:V1.0
//====================================================================//

#include <opencv2/video/tracking.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc_c.h>
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;

//计算相对窗口的坐标值,因为坐标原点在左上角,所以sin前有个负号
static inline Point calcPoint(Point2f center, double R, double angle)
{
    return center + Point2f((float)cos(angle), (float)-sin(angle))*(float)R;
}

static void help()
{
    printf( "\nExamle of c calls to OpenCV's Kalman filter.\n"
            "   Tracking of rotating point.\n"
            "   Rotation speed is constant.\n"
            "   Both state and measurements vectors are 1D (a point angle),\n"
            "   Measurement is the real point angle + gaussian noise.\n"
            "   The real and the estimated points are connected with yellow line segment,\n"
            "   the real and the measured points are connected with red line segment.\n"
            "   (if Kalman filter works correctly,\n"
            "    the yellow segment should be shorter than the red one).\n"
            "\n"
            "   Pressing any key (except ESC) will reset the tracking with a different speed.\n"
            "   Pressing ESC will stop the program.\n"
    );
}

int main(int, char**)
{
    help();
    Mat img(500, 500, CV_8UC3);
    KalmanFilter KF(2, 1, 0); //创建卡尔曼滤波器对象KF.虽然这个点是在2维平面中运动,但由于它是在一个圆弧上运动,只有一个自由度,角度,所以还是1维的
    Mat state(2, 1, CV_32F); //state(角度,△角度)
    Mat processNoise(2, 1, CV_32F);
    Mat measurement = Mat::zeros(1, 1, CV_32F);//定义测量值
    char code = (char)-1;

    for(;;)
    {
        //1.初始化
        cv::randn( state, Scalar::all(0), Scalar::all(0.1) );//填充高斯分布随机数
        KF.transitionMatrix = (Mat_<float>(2, 2) << 1, 1, 0, 1);  //转移矩阵A[1,1;0,1]


        //将下面几个矩阵设置为对角阵
        //cv::setIdentity()函数--将矩阵的对角线元素设为指定值,其他元素为0
        cv::setIdentity(KF.measurementMatrix);                             //测量矩阵H
        cv::setIdentity(KF.processNoiseCov, Scalar::all(1e-5));            //系统噪声方差矩阵Q,//过程噪声协方差矩阵,标准差为1e-5
        cv::setIdentity(KF.measurementNoiseCov, Scalar::all(1e-1));        //测量噪声方差矩阵R,//测量噪声协方差矩阵R,标准差为1e-1
        cv::setIdentity(KF.errorCovPost, Scalar::all(1));                  //后验错误估计协方差矩阵P//P(1|1),估计协方差矩阵

        cv::randn(KF.statePost, Scalar::all(0), Scalar::all(0.1));          //x(0)初始化

        for(;;)
        {
            Point2f center(img.cols*0.5f, img.rows*0.5f);          //center图像中心点
            float R = img.cols/3.f;                                //半径
            double stateAngle = state.at<float>(0);                //跟踪点角度
            Point statePt = calcPoint(center, R, stateAngle);     //跟踪点坐标statePt

            //2. 预测
            Mat prediction = KF.predict();                       //计算预测值,返回x'
            double predictAngle = prediction.at<float>(0);          //预测点的角度
            Point predictPt = calcPoint(center, R, predictAngle);   //预测点坐标predictPt


            //3.更新
            //measurement是测量值
            randn( measurement, Scalar::all(0), Scalar::all(KF.measurementNoiseCov.at<float>(0)));     //给measurement赋值N(0,R)的随机值

            // generate measurement
            measurement += KF.measurementMatrix*state;  //z = z + H*x;

            double measAngle = measurement.at<float>(0);
            Point measPt = calcPoint(center, R, measAngle);

            // plot points
            //定义了画十字的方法,值得学习下
#define drawCross( center, color, d )                                 \
                line( img, Point( center.x - d, center.y - d ),                \
                             Point( center.x + d, center.y + d ), color, 1, CV_AA, 0); \
                line( img, Point( center.x + d, center.y - d ),                \
                             Point( center.x - d, center.y + d ), color, 1, CV_AA, 0 )

            img = Scalar::all(0);
            drawCross( statePt, Scalar(255,255,255), 3 );
            drawCross( measPt, Scalar(0,0,255), 3 );
            drawCross( predictPt, Scalar(0,255,0), 3 );
            line( img, statePt, measPt, Scalar(0,0,255), 3, CV_AA, 0 );
            line( img, statePt, predictPt, Scalar(0,255,255), 3, CV_AA, 0 );


            //调用kalman这个类的correct方法得到加入观察值校正后的状态变量值矩阵
            if(theRNG().uniform(0,4) != 0)
                KF.correct(measurement);

            //不加噪声的话就是匀速圆周运动,加了点噪声类似匀速圆周运动,因为噪声的原因,运动方向可能会改变
            randn( processNoise, Scalar(0), Scalar::all(sqrt(KF.processNoiseCov.at<float>(0, 0))));   //vk
            state = KF.transitionMatrix*state + processNoise;

            imshow( "Kalman", img );
            code = (char)waitKey(100);

            if( code > 0 )
                break;
        }
        if( code == 27 || code == 'q' || code == 'Q' )
            break;
    }

    return 0;
}

鼠标位置的预测

//====================================================================//
// Created by liheng on 19-2-28.
//Program:卡尔曼滤波器示例2--跟踪鼠标位置
//Data:2019.2.28
//Author:liheng
//Version:V1.0
//====================================================================//


#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdio.h>
using namespace cv;
using namespace std;

const int winHeight=600;
const int winWidth=800;


Point mousePosition= Point(winWidth>>1,winHeight>>1);

//mouse event callback
void mouseEvent(int event, int x, int y, int flags, void *param )
{
    if (event==cv::EVENT_MOUSEMOVE) {
        mousePosition = Point(x,y);
    }
}

int main (void)
{
    RNG rng;
    //1.kalman filter setup
    const int stateNum=4;                                      //状态值4×1向量(x,y,△x,△y)//状态数,这里鼠标坐标X,Y和速度DX,DY
    const int measureNum=2;                                    //测量值2×1向量(x,y)//观测量数量,这里只写了X,Y
    KalmanFilter KF(stateNum, measureNum, 0);                   //第三个为控制量参数,这里没有

    KF.transitionMatrix = (Mat_<float>(4, 4) <<1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1);  //转移矩阵A
    setIdentity(KF.measurementMatrix);                                             //测量矩阵H
    setIdentity(KF.processNoiseCov, Scalar::all(1e-5));                            //系统噪声方差矩阵Q
    setIdentity(KF.measurementNoiseCov, Scalar::all(1e-1));                        //测量噪声方差矩阵R
    setIdentity(KF.errorCovPost, Scalar::all(1));                                  //后验错误估计协方差矩阵P
    rng.fill(KF.statePost,RNG::UNIFORM,0,winHeight>winWidth?winWidth:winHeight);   //初始状态值x(0)
    Mat measurement = Mat::zeros(measureNum, 1, CV_32F);                           //初始测量值x'(0),因为后面要更新这个值,所以必须先定义

    namedWindow("kalman");
    setMouseCallback("kalman",mouseEvent);

    Mat image(winHeight,winWidth,CV_8UC3,Scalar(0));

    while (1)
    {
        //2.kalman prediction
        Mat prediction = KF.predict();
        Point predict_pt = Point(prediction.at<float>(0),prediction.at<float>(1) );   //预测值(x',y')

        //3.update measurement
        measurement.at<float>(0) = (float)mousePosition.x;
        measurement.at<float>(1) = (float)mousePosition.y;

        //4.update
        KF.correct(measurement);

        //最优值
        Point statePt = Point(KF.statePost.at<float>(0),KF.statePost.at<float>(1));

        //draw
        image.setTo(Scalar(255,255,255,0));
        circle(image,predict_pt,5,Scalar(0,255,0),3);    //predicted point with green
        circle(image,mousePosition,5,Scalar(255,0,0),3); //current position with red
        circle(image,statePt,5,Scalar(0,255,255),3); //current position with yellow

        char buf[256];
        sprintf(buf,"predicted position:(%3d,%3d)",predict_pt.x,predict_pt.y);
        putText(image,buf,cv::Point(10,30),cv::FONT_HERSHEY_SCRIPT_COMPLEX,1,Scalar(0,0,0),1,8);

        sprintf(buf,"current position :(%3d,%3d)",mousePosition.x,mousePosition.y);
        putText(image,buf,cv::Point(10,60),cv::FONT_HERSHEY_SCRIPT_COMPLEX,1,Scalar(0,0,0),1,8);

        sprintf(buf,"best position:(%3d,%3d)",statePt.x,statePt.y);
        putText(image,buf,cv::Point(10,90),cv::FONT_HERSHEY_SCRIPT_COMPLEX,1,Scalar(0,0,0),1,8);

        imshow("kalman", image);
        int key=waitKey(3);
        if (key==27){//esc
            break;
        }
    }
}

运行结果如图所示:
鼠标位置预测

卡尔曼滤波器的不足之处

1.滤波限制条件比较苛刻,它要求系统模型精确以及系统误差模型和观测误差模型已知,这在实际应用中是很难满足的,或者在系统工作过程中,模型发生变化,这些都导致传统KF的滤波发散或精度下降。
2.计算机字长的限制,这种情况可能导致计算过程中出现舍入误差,从而导致方差阵P ( k | k)不对称引起滤波发散。
3.观测数据发生突变,由于传感器故障或外部条件发生改变,极有可能出现数据突变,即野值,这会对滤波器的收敛性产生严重影响,甚至导致发散,可以说,野值是对滤波器稳定性的一个考验。

卡尔曼滤波的发展

针对上述不足,很多学者提出了不同的方法加以克服,如限定记忆法、平方根滤波、渐消记忆滤波、自适应卡尔曼滤波(AKF)、抗野值滤波等。其中,AKF因为具有自适应特性非常适合动态系统滤波而受到广泛重视。因此,在采用卡尔曼滤波处理动态测量数据时,一般都要考虑采取适当的自适应滤波方法来解决这一问题。
AKF



下面的是我的公众号二维码图片,欢迎关注。
图注:幼儿园的学霸

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

卡尔曼滤波(Kalman Filter) 的相关文章

  • 无人机仿真XTDrone学习六:XTDrone键盘控制无人机multirotor_communication.py程序分析三

    multirotor communication py程序 这个程序是实现对无人机控制的主要程序 xff0c 需要重点分析 可以实现对无人机的位置 xff0c 速度 xff0c 加速度的控制 主要节点 xff1a sys span clas
  • 无人机仿真XTDrone学习七:XTDrone键盘控制无人机 multirotor_keyboard_control.py程序分析四

    multirotor keyboard control py 该程序可以通过键盘对一个或者多个无人机进行速度或者加速度的控制并更改无人机或领导者无人机飞行状态 这个脚本通过发布状态命令和速度命令话题与通讯脚本进行通讯 xff0c 通讯脚本进
  • XTDrone仿真平台与Prometheus仿真平台

    常见的无人机仿真平台大都是用于对底层飞控算法的仿真与调试 xff0c XTDrone仿真平台与Prometheus仿真平台可以针对无人机上层算法进行仿真或者进行编队仿真 xff0c 这两者都采用ROS 43 PX4 43 Gazebo开源平
  • ROS中功能包二进制安装改为源码安装

    在学习XTDrone的二维路径规划时需要使用navigation功能包 xff0c 使用文档安装方式为二进制安装 sudo apt install span class token operator span y ros span clas
  • 2016晚安 2017你好

    不知不觉开通CSDN账号已有三年多的时间 xff0c 三年多以前抱着学习坚持的态度想要在CSDN上记录自己学习的点滴 结果三年多过去了 xff0c 2016年也随着过去了 xff0c 回顾2016年主要的三件事情就是 xff1a 1 从大学
  • Python入门学习--环境配置

    工作将近两年了 xff0c 做过B S结构的项目 xff0c 也做过android xff0c 也做过C S结构的项目 xff0c 相信无论是那种项目都是基于Java 学习运用Java也已经好多年了 xff0c 虽然也接触过C C 43 4
  • Python入门学习-数据类型

    一 类型的概念 首先 xff0c 对于一个数据1011100 xff0c 改怎么解释呢 xff1f 同Java等变成语言类型 xff0c 首先我们要明确数据的类型 xff0c 程序设计语言不允许语法歧义 xff0c 因此需要明确数据的类型
  • 流年似水 启航2019

    凌晨1点无意间看到一个演讲视频 感谢你给我机会上场 xff0c 很久之前的一个演讲视频 xff0c 看完除了羡慕还是羡慕吧 xff0c 也许就是一句话吧 xff0c 开挂的人生不需要解释 30多年的生活他做了很多事 xff0c 也做成了很多
  • Matplotlib 可视化必备神书,附pdf下载

    出品 xff1a Python数据之道 大家好 xff0c 我是阳哥 大家知道 xff0c 在利用Python进行数据可视化过程中 xff0c 基本上是很难绕开 Matplotlib 的 xff0c 因为 不少其他的可视化库多多少少是建立在
  • ubuntu学习笔记02

    1 sudo sh 与sudo bash sh区别 以超级用户身份运行 34 sh 34 xff0c sh实用程序是一个命令语言解释器 以超级用户身份运行 34 bash 34 xff0c Bash是shell或命令语言解释器 xff0c
  • 史上最浅显易懂的Git教程!

    从零起步的Git教程 xff0c 让你无痛苦上手世界上最流行的分布式版本控制系统Git xff01 既然号称史上最浅显易懂的Git教程 xff0c 那这个教程有什么让你怦然心动的特点呢 xff1f 首先 xff0c 本教程绝对面向初学者 x
  • 数据库死锁原因及解决办法

    死锁 xff08 Deadlock xff09 所谓死锁 xff1a 是指两个或两个以上的进程在执行过程中 xff0c 因争夺资源而造成的一种互相等待的现象 xff0c 若无外力作用 xff0c 它们都将无法推进下去 此时称系统处于死锁状态
  • spring和springmvc父子容器的关系

    大家都知道 xff0c 在spring的配置中要分开配置service层的注解扫描 xff0c 以及springmvc变现层的注解扫描 xff0c 如下 xff1a lt 扫描加载Service实现类 gt lt context compo
  • pageHelper分页插件实现原理及使用方法

    插件官方网站 xff1a https github com pagehelper Mybatis PageHelper tree master src main java com github pagehelper 实现原理 xff1a 使
  • 虚拟机Linux系统安装nginx服务器并启动的步骤

    工作前的准备 xff1a 1 装有Linux的虚拟机 2 nginx安装包 xff0c 注意是gz结尾的压缩文件 具体步骤1 xff1a 1 nginx安装环境 nginx是 C 语言开发 xff0c 建议在 linux 上运行 xff0c
  • 什么是反射机制,有什么作用

    1 反射机制定义 反射的概念是由Smith在1982年首次提出的 xff0c 主要是指程序可以访问 检测和修改其本身状态或行为的一种能力 在Java环境中 xff0c 反射机制允许程序在执行时获取某个类自身的定义信息 xff0c 例如熟悉和
  • 写给2016

    你不能期待着遇见怎样的自己 xff0c 但你可以选择成为怎样的自己 转眼16年就迎来了它的落幕 xff0c 不论怎样华丽的开场 xff0c 总有归于平静散场的结束 xff0c 不早不晚 xff0c 于清晨到傍晚 xff0c 于四季的轮回 x
  • 模块化建立项目流程(Maven聚合模块)

    先说项目使用Maven的好处 1 项目构建 Maven定义了软件开发的整套流程体系 xff0c 并进行了封装 xff0c 开发人员只需要指定项目的构建流程 xff0c 无需针对每个流程编写自己的构建脚本 2 依赖管理 除了项目构建 xff0
  • 如何在linux下判断web服务是否开启?

    对于web服务的开启的判断有以下几种常用方法 xff1a 1 端口查看 xff1a 本地 xff1a ss xff0c netstat xff0c lsof 1 2 3 4 5 6 7 8 9 10
  • git基本命令

    最近再写一些项目上传到github xff0c 所以要用到git命令 本地需要先安装git客户端 xff0c 然后指定一个git地址为本地仓库 然后右键git bash here打开git命令界面 首先服务端需要创建一个项目以便clone到

随机推荐

  • jps查看Java线程,jstack查看具体线程堆状态

    想要使用jps需要配置环境变量 xff0c 在classpath后在加一个指定Java bin目录 具体命令如下 t2挂起了 xff0c 堆里面显示t2为RUNNABLE xff0c suspend xff0c resume废弃使用 IBM
  • heap_1.c详解--------FreeRTOS内存管理

    heap 1源码分析 include lt stdlib h gt Defining MPU WRAPPERS INCLUDED FROM API FILE prevents task h from redefining all the A
  • 记录一个类加载变量引发的问题

    类加载变量导致的问题 类加载变量导致的问题 类加载变量导致的问题 因为项目需要 xff0c 银行要求使用weblogic部署并且启动所有项目 xff0c 不允许项目单独开服务启动一般都有这样的要求 xff0c 我所在的项目组有两个单独mai
  • Ubuntu16.04安装intel RealSense D435i驱动并在ROS中使用

    参考 xff1a https blog csdn net qq 43265072 article details 106437287https blog csdn net zhangfenger article details 849980
  • 【ROS】的单线程Spinning和多线程Spinning

    参考 xff1a https www cnblogs com feixiao5566 p 5288206 htmlhttps www freesion com article 9499126134 https blog csdn net y
  • Intel RealSense D435i 深度相机介绍

    参考 xff1a https www sohu com a 340984033 715754https www chiphell com thread 1945054 1 1 htmlhttps blog csdn net cherry y
  • 【ROS】rosnode信息命令

    参考 xff1a https www cnblogs com kay2018 p 10314741 html 一 概述 ROS信息命令用于识别话题 服务 节点和参数等信息 尤其是rostopic rosservice rosnode和ros
  • 【ROS】launch文件详解

    参考 xff1a https www cnblogs com fuzhuoxin p 12588402 html 在节点少 xff0c 程序小的情况下可以一个一个节点来启动 xff0c 测试运行效果 xff1b 但是当工程规模大 xff0c
  • uC/OS-II的任务同步与通信

    在多任务合作过程中的 xff0c 操作系统应解决两个问题 xff1a 一是各任务之间应具有一种互斥关系 xff0c 即对于某个共享资源的共享 xff0c 如果一个任务正在使用 xff0c 则其他任务只能等待 xff0c 等到该任务释放该资源
  • Jetson Xavier NX系统烧录(使用NVIDIA SDK Manager)

    目录 一 在host主机下安装NVIDIA SDK Manager 二 安装系统镜像 三 设置SSD为系统启动项 四 安装CUDA等环境的包 注意 xff1a 本文使用的是国产开发套件 xff0c 不支持SD卡镜像文件烧录 一 在host主
  • 使用Spring Security,在登陆页面没有跳转的问题。(ssm)

    首先检查有没有在spring security xml中配置成功页面和失败页面 其次判断web xml中是否引用了spring security xml文件 最后 xff0c 如果上两步都没问题 xff0c 删去spring securit
  • for 循环嵌套性能的比较

    有人对着汇编语言不够一屑 xff0c 认为那已经是古老的低级语言 xff0c 是当今的非主流语言 xff0c 学了也不知道有什么用 是的 xff0c 我们不得不承认 xff0c 作为一门古老的语言 xff0c 汇编已经完成了历史赋予它的使命
  • 同一个单片机系统要做到共地

    同一系统可以不同的电源供电 xff0c 但是要做到共地 原因 xff1a 不同的仪器要连接成一个电气系统 共地就是建立一个共同的电位参考点 否则没有标准如何能够测量 同时 公共地一般也是接大地的地线 仪器外壳接地可以消除干扰信号
  • STM32串口下载程序

    STM32 串口下载程序 引言 xff1a 如果我们用下载器下载程序很快 xff0c 很方便 xff0c 但是需要购买下载器 xff0c 很破费 为此我们用串口 下载程序 xff0c 省去了购买下载器的麻烦 下面介绍用串口下载程序的方法 x
  • Python实现微信自动回复

    先安装 itchat requests itchat uos itchat uos主要解决微信提示禁止网页登录导致登录失败的问题 以下有三种可玩方式 xff1a 1 回复好友 源代码如下 xff1a wechat autoreply imp
  • linux屏幕录像

    安装 sudo apt get install kazam 功能 屏幕录像 屏幕截图 区域 全屏 窗口 自定义区域 音频 光标 扬声器 麦克风 配置 帧率 录音源 保存位置
  • 安卓串口通讯工具库封装及使用

    串口通讯 引言 对于安卓开发的小伙伴来说 xff0c 很少用到串口通信开发 主要用来外接一些硬件设备 xff0c 例如扫码器 xff0c 读卡器 xff0c 体温枪等一些硬件设备 这些设备与安卓之间通过串口来交换数据 如果有安卓串口开发这方
  • shell启动程序的四种方式

    需要执行script sh 文件 方式一 xff1a script sh 执行shell脚本时是在当前shell xff08 称为父shell xff09 开启一个子shell环境 xff0c 此shell脚本就在这个子shell环境中执行
  • ZED深度相机的使用--zed-ros-wrapper

    ZED相机能做什么 可以获取3D RGB点云用于生成地图 xff0c 带有imu传感器可以获取位姿与移动轨迹 xff0c 下面是厂家的宣传内容 下载并安装ZED SDK ZED SDK 3 6 Download Stereolabs Dev
  • 卡尔曼滤波(Kalman Filter)

    卡尔曼滤波 Kalman Filter 微信公众号 xff1a 幼儿园的学霸 个人的学习笔记 xff0c 关于OpenCV 关于机器学习 问题或建议 xff0c 请公众号留言 目录 TOC what is Kalman Filter 举个例