SLAM学习笔记(四)定位

2023-05-16

原创博客:http://blog.csdn.net/renshengrumenglibing?viewmode=contents
机器人定位的目的是为了知道“自己在什么地方”,目前,机器人定位的方法可以分为非自主定位与自
主定位两大类。所谓非自主定位是在定位的过程中机器人需要借助机器人本身以外的装置如:全球定位
系统(GPS)、全局视觉系统等进行定位;自主定位是机器人仅依靠机器人本身携带的传感器进行定位。
由于在室内环境中,不能使用GPS,而安装其它的辅助定位系统比较麻烦。因此机器人一般采用自主
定位的方法。
按照初始位姿是否已知,可把机器人自主定位分为初始位姿已知的位姿跟踪(Pose tracking)和初始位
姿未知的全局定位(Global localization)。

位姿跟踪是在已知机器人的初始位姿的条件下,在机器人的运动过程中通过将观测到的特征与地图中
的特征进行匹配,求取它们之间的差别,进而更新机器人的位姿的机器人定位方法。位姿跟踪通常采用扩
展卡尔曼滤波器(Extended Kalman Filter,EKF)来实现。该方法采用高斯分布来近似地表示机器人位姿
的后验概率分布,其计算过程主要包括三步:首先是根据机器人的运模型预测机器人的位姿,然后将观测
信息与地图进行匹配,最后根据预测后的机器人位姿以及匹配的特征计算机器人应该观测到的信息,并利
用应该观测到的信息与实际观测到的信息之间的差距来更新机器人的位姿。

全局定位是在机器人的初始位姿不确定的条件下,利用局部的、不完全的观测信息估计机器人的当前
位姿。能否解决最典型而又最富挑战性的“绑架恢复”问题在一定程度上反应了机器人全局定位方法的鲁棒
性与可靠性。

一、移动机器人 SLAM 技术
可靠的定位性能是自主移动系统的关键要素。传统的定位方法是基于里程计估计的,存在不可避免的
定位误差。自从移动机器人诞生以来,对定位问题的研究就和地图创建问题密切关联,已知环境地图的定
位问题和已知定位的地图创建问题已经被广泛研究,提出了多种有效的解决途径。当地图和机器人的位置
都事先未知时,问题就变得更加复杂,出现了许多独有的新特征。在这种情况下,要求机器人在一个完全
未知的环境中从一个未知的位置出发,在递增地建立环境的导航地图同时,利用已建立的地图来同步刷新
自身的位置。该问题被称作同步定位和构图,简称 SLAM。在 SLAM 问题中,机器人位置和地图两者的估
算是高度相关的,任何一方都无法独立获取,这样形成了一种相辅相生、不断迭代的过程,因此有些学者
将其比作“鸡与蛋”问题。
近年来,移动机器人 SLAM 技术获得显著进步,被认为是解决环境未知和传感器信息不确定条件下的
移动机器人自主导航的最有效的技术之一。SLAM 基本思想是利用已创建地图修正基于运动模型的机器人
位姿估计误差;同时根据可靠的机器人位姿,创建出精度更高的地图。
这里写图片描述
关于传感器的不确定,以最常见的里程计为例,其典型的误差积累如图 所示,其中,左图是独立
利用里程计定位、独立利用激光传感器感知环境所创建的地图,由于没有进行里程计误差补偿,几次创
建的地图差异很大,与实际环境也不符;右图是采用 SLAM 创建的地图,基于 SLAM 可以利用已创建的
地图修正里程计的误差,这样机器人的位姿误差就不会随着机器人的运动距离的增大而无限制增长,因
此可以创建精度更高的地图,也同时解决了未知环境中的机器人定位问题。

SLAM中,系统的状态由机器人的位姿和地图信息(特征的位置信息)组成。假设机器人在t时刻观测到
特征m1,如图2所示。根据观测信息只能获得特征m1在机器人坐标系R中的坐标。机器人需要估计机器
人自己本身在世界坐标系W中的位姿,然后通过坐标变换才能计算特征的世界坐标。可见在地图创建的过
程中,必须计算机器人的位姿,也就是进行机器人的定位。然而,根据里程计获得的机器人位置信息很不
准确,显然错误的位置信息将会导致地图的不准确。
//SLAM示意图
这里写图片描述
在初始时刻,激光雷达创建的地图中并没有任何的特征。当机器人观测到某特征m时,可以根据
机器人的位姿,以及特征在机器人坐标系下的位姿,计算出特征在世界坐标系下的位姿,此时将特征
加入到地图中(更新地图);当机器人位姿改变,再次观测到特征m,可以根据特征在世界坐标系下
的位姿和特征在机器人坐标系下的位姿,解算出当前机器人的位姿(机器人定位)。
当机器人继续运动时,它将观测到更多的特征,根据同样的方法。机器人会把它们加入到地图中,
并且根据观测到的信息更新机器人的位姿以及它们的世界坐标。简单的说,SLAM利用观测到的特征计
算它们的世界坐标以实现地图创建,同时更新机器人的位姿以实现机器人的定位。
SLAM方法有很多种,主要包括基于扩展卡尔曼滤波的SLAM技术,基于传统粒子滤波的SLAM技术,
快速SLAM技术,基于扫描匹配的SLAM技术等等。
1.1基于扫描匹配的 SLAM 技术
基于扫描匹配的 SLAM是基于最近邻扫描匹配来估计两次扫描间机器人的平移和旋转的算法。扫描
匹配算法主要源自迭代最近点(Iterative Closest Point, ICP)算法及其改进算法。该算法通过迭代细调由
机器人里程计给出的初始位姿,限定了搜索空间。然而,该算法假定机器人的初始位姿和机器人的真实
位姿之间的偏差足够小,以便于达到全局最优匹配。
1.2 范例 :
已知两条直线在激光雷达坐标系下和全局坐标系下的直线方程,求激光雷达在全局坐标下
的位置(x,y)和姿态theta
实际上已知两条直线求解是多解的,当theta是真实解,那么theta+pi同样是方程组的解,此时
可以引入新的约束,激光雷达实际上看到的两条直线,只能是直线交叉点一侧的部分,那么求解之
后可以进行验证,进而排除一个解,此时解唯一。
假设直线L1 全局下的坐标方程分别为y = a1*x + b,在雷达坐标系的方程y = a2*x+b2;
倾斜角分别为thetaW和thetaR,那么由转角alpha+ thetaR = thetaW => alpha = thetaW - thetaR;
[Xw] [cos(alpha)-sin(alpha)]Xr
Tx= [Yw] * [sin(alpha) cos(alpha)]Yr + Ty
由两条直线解出格子坐标系下的交点,代入上式可以解出Tx Ty,上式中都是矩阵计算,由于没有word那么
强大,各位只能勉强看了。
此时实际上解释存在两个的,解出之后需要进行验证,记下线段的端点,看知否在交点的同一侧,如果在同
一侧,那么结果就是对的,否则就要再转180度。
直线的拟合参照上一篇笔记,http://blog.csdn.net/renshengrumenglibing/article/details/8604245
为了提高进度,我们可以对数据进行一次中值滤波,抑制噪声同时尽量保留数据的边沿。

 //中值滤波 只能对初始的连续数据滤波
 //滤波基本不丢弃数据,两端会各自扔掉几个数据
 void OpenRadar::MedFilter(vector<int>& RadarRho, vector<double>& RadarTheta){
     vector<int>rho;
     vector<double>theta;
     int halfWindowSize = 2;
     int *neighbor = new int[2*halfWindowSize+1];
     int temp;
     for (int i = halfWindowSize; i< (int)RadarRho.size() - halfWindowSize;i++)
      {
          for (int j = -halfWindowSize;j <= halfWindowSize;j++)
          {
              neighbor[j + halfWindowSize] = RadarRho.at(i + j); 
          }
          //排序
          for (int m = 0; m < 2*halfWindowSize +1;m++)
          {
              for (int n = m + 1;n < 2*halfWindowSize + 1;n++)
              {
                  if (neighbor[m]> neighbor[n])
                  {
                      temp = neighbor[m];
                      neighbor[m] = neighbor[n];
                      neighbor[n] = temp;
                  }
              }
          }
          rho.push_back(neighbor[halfWindowSize]);
          theta.push_back(RadarTheta.at(i));
      }

     RadarRho.clear();
     RadarTheta.clear();

     for (int i = 0; i < (int)(rho.size());i++)
     {
         RadarRho.push_back(rho.at(i));
         RadarTheta.push_back(theta.at(i));
     }
 }

其他处理跟之前相同,此时可以根据已知的两条直线进行位姿解算。

//已知四条直线如何计算变换参数
void Coordinate::CalCoorTransPara(CoorTransPara &transPara,
                                  LinePara W1,
                                  LinePara W2, 
                                  LinePara R1, 
                                  LinePara R2)
{
    double theta = ( W1.Rho - R1.Rho + W2.Rho - R2.Rho )/2;
    //double theta = ( W1.Rho - R1.Rho);
    //求解出Xw Yw Xr Yr
    double Xw = (double)(W1.b - W2.b)/(W2.a - W1.a);
    double Yw = W1.a*Xw + W1.b;

    double Xr = (double)(R1.b - R2.b)/(R2.a - R1.a);
    double Yr = R1.a*Xr + R1.b;


    int Tx = (int)(Xw - cos(theta)*Xr + sin(theta)*Yr);
    int Ty = (int)(Yw - sin(theta)*Xr - cos(theta)*Yr);
    //交点判定,场地上的几条直线都是有角点的
    iPoint crossPoint;//交点
    iPoint vectorW1,vectorR1;//向量
    //iPoint vectorR2,vectorW2;
    if (W1.startPoint.x == W2.startPoint.x && W1.startPoint.y == W2.startPoint.y)
    {
        crossPoint = ipoint(W1.startPoint.x,W1.startPoint.y);
        vectorW1 = ipoint(W1.endPoint.x - W1.startPoint.x, W1.endPoint.y - W1.startPoint.y);
        //vectorW2 = ipoint(W2.endPoint.x - W2.startPoint.x, W2.endPoint.y - W2.startPoint.y);
    }else if (W1.endPoint.x == W2.startPoint.x && W1.endPoint.y == W2.startPoint.y)
    {
        crossPoint = ipoint(W1.endPoint.x,W1.endPoint.y);
        vectorW1 = ipoint(W1.startPoint.x - W1.endPoint.x, W1.startPoint.y - W1.endPoint.y);
        //vectorW2 = ipoint(W2.endPoint.x - W2.startPoint.x, W2.endPoint.y - W2.startPoint.y);
    }else if (W1.startPoint.x == W2.endPoint.x && W1.startPoint.y == W2.endPoint.y)
    {
         crossPoint = ipoint(W1.startPoint.x,W1.startPoint.y);
         vectorW1 = ipoint(W1.endPoint.x - W1.startPoint.x, W1.endPoint.y - W1.startPoint.y);
         //vectorW2 = ipoint(W2.startPoint.x - W2.endPoint.x, W2.startPoint.y - W2.endPoint.y);
    }else if (W1.endPoint.x == W2.endPoint.x && W1.endPoint.y == W2.endPoint.y)
    {
         crossPoint = ipoint(W1.endPoint.x,W1.endPoint.y);
         vectorW1 = ipoint(W1.startPoint.x - W1.endPoint.x, W1.startPoint.y - W1.endPoint.y);
         //vectorW2 = ipoint(W2.startPoint.x - W2.endPoint.x, W2.startPoint.y - W2.endPoint.y);
    }
    //将激光雷达下的两个点旋转到W系下
    transPara.theta = theta;
    transPara.Tx = Tx;
    transPara.Ty = Ty;
    iPoint R1ToW;
    //iPoint R2ToW;
    TransformCoord(transPara,R1.startPoint,R1ToW);
    //TransformCoord(transPara,R2.startPoint,R2ToW);
    vectorR1.x = R1ToW.x - crossPoint.x;
    vectorR1.y = R1ToW.y - crossPoint.y;
    //判断是否在同一侧?
    if (vectorW1.x * vectorR1.x + vectorW1.y*vectorR1.y < 0)
    {
        //旋转角度差了180度,需要调转180度
        transPara.theta = theta + PI;
        transPara.Tx = (int)(Xw - cos(transPara.theta)*Xr + sin(transPara.theta)*Yr);
        transPara.Ty = (int)(Yw - sin(transPara.theta)*Xr - cos(transPara.theta)*Yr);
    }else{

    }
    //数据测试
    /* TransformCoord(transPara,R1.startPoint,R1ToW);
     cout<<"R1ToW.x "<<R1ToW.x<<"  R1ToW.y "<<R1ToW.y<<endl;
     TransformCoord(transPara,R1.endPoint,R1ToW);
     cout<<"R1ToW.x "<<R1ToW.x<<"  R1ToW.y "<<R1ToW.y<<endl;

     TransformCoord(transPara,R2.startPoint,R2ToW);
     cout<<"R2ToW.x "<<R2ToW.x<<"  R2ToW.y "<<R2ToW.y<<endl;

     TransformCoord(transPara,R2.endPoint,R2ToW);
     cout<<"R2ToW.x "<<R2ToW.x<<"  R2ToW.y "<<R2ToW.y<<endl;*/
    //进行一次验证,看看交点进行坐标变换之后是否接近匹配的点
   /* iPoint R = ipoint(Xr,Yr);
    iPoint R2W;
    TransformCoord(transPara,R,R2W);
    cout<<"R2W.x "<<R2W.x<<"  R2W.y "<<R2W.y<<endl;*/

}

//完整的Coordinate.h

#pragma once
#include "WeightedFit.h"
#include <iostream>
using namespace std;

//场地中的关键点
static iPoint FieldPointA = ipoint(9192,0);
static iPoint FieldPointB = ipoint(0,9192); 
static iPoint FieldPointC = ipoint(-9192,0);
static iPoint FieldPointD = ipoint(0,-9192);
//场地中的直线变量
static LinePara FieldLine1 = linePara(-1.0,9192.3881554,FieldPointA,FieldPointB);
static LinePara FieldLine2 = linePara(1.0,9192.3881554,FieldPointB,FieldPointC);
static LinePara FieldLine3 = linePara(-1.0,-9192.3881554,FieldPointC,FieldPointD);
static LinePara FieldLine4 = linePara(1.0,-9192.3881554,FieldPointD,FieldPointA);
static LinePara FieldLine5 = linePara(100000.0,0.0,FieldPointB,FieldPointD);

//场地中的圆
static CirclePara FieldCircle1 = circlePara(-3000,1301,400,350);
static CirclePara FieldCircle2 = circlePara(-1951,880,400,350);
static CirclePara FieldCircle3 = circlePara(-651,815,400,350);
static CirclePara FieldCircle4 = circlePara(-495,2416,400,350);
static CirclePara FieldCircle5 = circlePara(-3347,-997,400,350);
static CirclePara FieldCircle6 = circlePara(-2400,-2848,400,350);
static CirclePara FieldCircle7 = circlePara(-1499,-2499,400,350);

static CirclePara FieldCircle8 = circlePara(3000,1301,400,350);
static CirclePara FieldCircle9 = circlePara(1951,880,400,350);
static CirclePara FieldCircle10 = circlePara(651,815,400,350);
static CirclePara FieldCircle11= circlePara(495,2416,400,350);
static CirclePara FieldCircle12 = circlePara(3347,-997,400,350);
static CirclePara FieldCircle13 = circlePara(2400,-2848,400,350);
static CirclePara FieldCircle14 = circlePara(1499,-2499,400,350);

//坐标系类,进行坐标系相关的计算
typedef struct{
    int Tx;
    int Ty;
    double theta;//旋转角
}CoorTransPara;  //坐标变换参数

class Coordinate
{
public:

    Coordinate(void);
    ~Coordinate(void);
    //已知四条直线如何计算变换参数
    void CalCoorTransPara(CoorTransPara &transPara,
                          LinePara W1,
                          LinePara W2, 
                          LinePara R1, 
                          LinePara R2);
    void CoortransTest();
    void CalRadarCoord();

    CoorTransPara RadarCoordTransPara;//全局坐标系和雷达坐标系之间的转换参数
    void printRadarCoordtransPara(CoorTransPara coordtrans);
    void TransformCoord(CoorTransPara transPara,iPoint R,iPoint& W);

};

//完整的Coordiate.cpp

#include "Coordinate.h"


Coordinate::Coordinate(void)
{
}


Coordinate::~Coordinate(void)
{
}

//已知四条直线如何计算变换参数
void Coordinate::CalCoorTransPara(CoorTransPara &transPara,
                                  LinePara W1,
                                  LinePara W2, 
                                  LinePara R1, 
                                  LinePara R2)
{
    double theta = ( W1.Rho - R1.Rho + W2.Rho - R2.Rho )/2;
    //double theta = ( W1.Rho - R1.Rho);
    //求解出Xw Yw Xr Yr
    double Xw = (double)(W1.b - W2.b)/(W2.a - W1.a);
    double Yw = W1.a*Xw + W1.b;

    double Xr = (double)(R1.b - R2.b)/(R2.a - R1.a);
    double Yr = R1.a*Xr + R1.b;


    int Tx = (int)(Xw - cos(theta)*Xr + sin(theta)*Yr);
    int Ty = (int)(Yw - sin(theta)*Xr - cos(theta)*Yr);
    //交点判定,场地上的几条直线都是有角点的
    iPoint crossPoint;//交点
    iPoint vectorW1,vectorR1;//向量
    //iPoint vectorR2,vectorW2;
    if (W1.startPoint.x == W2.startPoint.x && W1.startPoint.y == W2.startPoint.y)
    {
        crossPoint = ipoint(W1.startPoint.x,W1.startPoint.y);
        vectorW1 = ipoint(W1.endPoint.x - W1.startPoint.x, W1.endPoint.y - W1.startPoint.y);
        //vectorW2 = ipoint(W2.endPoint.x - W2.startPoint.x, W2.endPoint.y - W2.startPoint.y);
    }else if (W1.endPoint.x == W2.startPoint.x && W1.endPoint.y == W2.startPoint.y)
    {
        crossPoint = ipoint(W1.endPoint.x,W1.endPoint.y);
        vectorW1 = ipoint(W1.startPoint.x - W1.endPoint.x, W1.startPoint.y - W1.endPoint.y);
        //vectorW2 = ipoint(W2.endPoint.x - W2.startPoint.x, W2.endPoint.y - W2.startPoint.y);
    }else if (W1.startPoint.x == W2.endPoint.x && W1.startPoint.y == W2.endPoint.y)
    {
         crossPoint = ipoint(W1.startPoint.x,W1.startPoint.y);
         vectorW1 = ipoint(W1.endPoint.x - W1.startPoint.x, W1.endPoint.y - W1.startPoint.y);
         //vectorW2 = ipoint(W2.startPoint.x - W2.endPoint.x, W2.startPoint.y - W2.endPoint.y);
    }else if (W1.endPoint.x == W2.endPoint.x && W1.endPoint.y == W2.endPoint.y)
    {
         crossPoint = ipoint(W1.endPoint.x,W1.endPoint.y);
         vectorW1 = ipoint(W1.startPoint.x - W1.endPoint.x, W1.startPoint.y - W1.endPoint.y);
         //vectorW2 = ipoint(W2.startPoint.x - W2.endPoint.x, W2.startPoint.y - W2.endPoint.y);
    }
    //将激光雷达下的两个点旋转到W系下
    transPara.theta = theta;
    transPara.Tx = Tx;
    transPara.Ty = Ty;
    iPoint R1ToW;
    //iPoint R2ToW;
    TransformCoord(transPara,R1.startPoint,R1ToW);
    //TransformCoord(transPara,R2.startPoint,R2ToW);
    vectorR1.x = R1ToW.x - crossPoint.x;
    vectorR1.y = R1ToW.y - crossPoint.y;
    //判断是否在同一侧?
    if (vectorW1.x * vectorR1.x + vectorW1.y*vectorR1.y < 0)
    {
        //旋转角度差了180度,需要调转180度
        transPara.theta = theta + PI;
        transPara.Tx = (int)(Xw - cos(transPara.theta)*Xr + sin(transPara.theta)*Yr);
        transPara.Ty = (int)(Yw - sin(transPara.theta)*Xr - cos(transPara.theta)*Yr);
    }else{

    }
    //数据测试
    /* TransformCoord(transPara,R1.startPoint,R1ToW);
     cout<<"R1ToW.x "<<R1ToW.x<<"  R1ToW.y "<<R1ToW.y<<endl;
     TransformCoord(transPara,R1.endPoint,R1ToW);
     cout<<"R1ToW.x "<<R1ToW.x<<"  R1ToW.y "<<R1ToW.y<<endl;

     TransformCoord(transPara,R2.startPoint,R2ToW);
     cout<<"R2ToW.x "<<R2ToW.x<<"  R2ToW.y "<<R2ToW.y<<endl;

     TransformCoord(transPara,R2.endPoint,R2ToW);
     cout<<"R2ToW.x "<<R2ToW.x<<"  R2ToW.y "<<R2ToW.y<<endl;*/
    //进行一次验证,看看交点进行坐标变换之后是否接近匹配的点
   /* iPoint R = ipoint(Xr,Yr);
    iPoint R2W;
    TransformCoord(transPara,R,R2W);
    cout<<"R2W.x "<<R2W.x<<"  R2W.y "<<R2W.y<<endl;*/

}

void Coordinate::CoortransTest(){
    Coordinate coord;
    CoorTransPara coordtrans;
    coord.CalCoorTransPara(coordtrans,FieldLine1,FieldLine5,FieldLine2,FieldLine5);
    cout<<"theta : "<<coordtrans.theta*180/PI<<" Tx: "<<coordtrans.Tx<<"  Ty: "<<coordtrans.Ty<<endl;
}

void Coordinate::printRadarCoordtransPara(CoorTransPara coordtrans){
    cout<<"theta : "<<coordtrans.theta*180/PI<<" Tx: "<<coordtrans.Tx<<"  Ty: "<<coordtrans.Ty<<endl;
}


void Coordinate::TransformCoord(CoorTransPara transPara,iPoint R,iPoint& W){

    W.x = (int)(R.x*cos(transPara.theta) - R.y*sin(transPara.theta) );
    W.y = (int)(R.x*sin(transPara.theta) + R.y*cos(transPara.theta) );
    W.x = W.x + transPara.Tx ;
    W.y = W.y + transPara.Ty ;
}

这里写图片描述
这里写图片描述
这里写图片描述

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

SLAM学习笔记(四)定位 的相关文章

  • 基于docker搭建tx2的ROS2交叉编译环境

    基于docker搭建TX2的ROS2交叉编译环境 概述 ROS2官方文档有交叉编译相关说明 本文使用TX2最新官方镜像JetPack4 4版本 xff0c 自带ubuntu18 04 有现成的ubuntu18 04就可以使用apt get
  • ros2 nav2 行为树插件引擎原理和应用

    Nav2 行为树插件引擎原理和应用 本文由一个简单的例子作为切入点 xff0c 对Nav2行为树插件引擎的原理进行分析 文章目录 Nav2 行为树插件引擎原理和应用一个完整应用demoGroot行为树设计和监视器安装使用Groot实时监视行
  • 机器学习的挑战:黑盒模型正面临这3个问题

    导读 xff1a 本文将讲述可解释机器学习的研究背景 xff0c 介绍黑盒模型存在的问题和风险 xff0c 通过一些小故事让读者了解问题的严重性 作者 xff1a 索信达控股 邵平 杨健颖 苏思达 何悦 苏钰 来源 xff1a 大数据DT
  • ARM仿真器的SWD接法

    ARM仿真器的SWD接法 最近接了一个项目 xff0c 电路板上留有的代码下载接口是SWD接口 xff0c 手头上并没有专用的SWD下载器 xff0c 庆幸的是我手头有一个ARM仿真器 xff0c 在接口处写着 JTAG 43 SWD xf
  • C# winform窗体及其控件的自适应

    为了提升用户的体验 xff0c 窗体不能再固定其大小 xff08 用户不能随意改变窗体的大小 xff09 xff0c 所以要做到窗体适应电脑屏幕的分辨率 xff0c 窗体中的控件要跟随窗体的变化比例而变化 通过网上查找学习 xff0c 发现
  • 学校人力资源管理系统——E-R图

    分局E R图 根据需求分析该学校人力资源管理系统中实体包括 xff1a 教职工 xff0c 部门 xff0c 职称 xff0c 职务 xff0c 学籍经历 xff0c 奖惩 xff1b 局部E R图设计如下 xff1a 教职工 xff08
  • TVM编译与python环境配置

    提示 xff1a 仅记录一下本次成功安装的过程用于参考 目录 前言 一 源码下载 二 编译 1 安装依赖 2 安装llvm 3 开始编译 4 设置python环境 前言 记录一下tvm的编译流程与python环境安装 环境 xff1a ro
  • apache反向代理tomcat时x-forwarded-for为null的问题

    apache 在用ProxyPass时会自动在header中设置X Forwarded For X Forwarded Host和X Forwarded Server xff08 http httpd apache org docs 2 2
  • APP_CTL_HEAP_SZ 堆中没有足够的存储器可用来处理语句

    Caused by COM ibm db2 jdbc DB2Exception IBM CLI Driver DB2 NT SQL0973N 34 APP CTL HEAP SZ 34 堆中没有足够的存储器可用来处理语句 SQLSTATE
  • OpenCV颜色识别

    彩色模型 数字图像处理中常用的采用模型是RGB xff08 红 xff0c 绿 xff0c 蓝 xff09 模型和HSV xff08 色调 xff0c 饱和度 xff0c 亮度 xff09 xff0c RGB广泛应用于彩色监视器和彩色视频摄
  • vmware占用磁盘空间增加(ubuntu虚拟机占用空间小)

    vmware占用磁盘空间大 xff0c 但是用df h指令看ubuntu虚拟机占用的空间没有这么大 xff0c 可以试着用下面的三种方法清理vmware占用的空间 方法一 xff1a 使用vmware自带的工具就能收回占用的部分空间 那个工
  • 进临界区(关全局中断)是否会影响数据的接收?

    在嵌入式的编程中 xff0c 经常会使用嵌入式实时操作系统 xff0c 比如FreeRTOS xff0c RTT等 而在使用这些操作系统时 xff0c 会有一个临界区的概念 xff0c 一般操作是 1 xff0c 进入临界区 xff1b 2
  • source insight 4.0 护眼背景色设置

    1 xff0c 打开source insight 4 0 2 xff0c 选择options下的preferences 3 xff0c 选择window background xff0c 双击打开 xff1b 4 xff0c 在颜色中将色调
  • octet和byte

    在看BLE协议时 xff0c 看到了数据包格式的定义 packet format xff0c 定义如下 xff1a Preamble 1 octet Access Address 4 octets PDU 2 to 257 octets C
  • 如何解决SSL/TLS握手过程中失败的错误?

    Fixes for the SSL TLS Handshake Failed error for both internet users and site owners It s time for another technical art
  • 学校人力资源管理系统——逻辑结构设计

    E R 图向关系模型的转换 第一步 把六个实体类型转化成五个模式 xff1a 教职工 职工编号 xff0c 姓名 xff0c 性别 xff0c 出生年份 xff0c 学历 xff0c 民族 xff0c 婚姻状态 xff0c 政治面貌 xff
  • 无线持续攻击(wireless duration attack)

    抓空口包时发现一种奇怪的ack帧 duration位长度是32767us 看到omnipeek将它定义为wireless duration attack 看起来是路由器回复设备的ack 而设备也是发了一个奇怪的pspoll帧 节能位置1 乱
  • .bashrc文件在哪?

    linux的bashrc文件在 home目录下 xff0c 但是是一个隐藏bai文件 xff0c 在文件管理器里面du按Ctrl 43 H即可显示 显示为 bashrc xff0c 前zhi面小点儿表示隐藏文件 xff09 也可以直接利用t
  • Cotex-M内核双堆栈指针MSP和PSP

    MSP和PSP 的含义是Main Stack Pointer 和Process Stack Pointer 在逻辑地址上他们都是R13 xff1b 权威手册上说的很清楚PSP主要是在Handler的模式下使用 xff0c MSP主要在线程模
  • TCP/IP协议栈之LwIP-pbuf

    pbuf结构体就是一个描述协议栈中数据包的数据结构 xff1a Main packet buffer struct struct pbuf next pbuf in singly linked pbuf chain struct pbuf

随机推荐

  • Linux使用wpa_supplicant手动配置连接WiFi

    wpa supplicant是Linux BSD Mac OSX和Windows的WPA的服务 支持WPA和WPA2 IEEE 802 11i RSN xff0c 它适用于台式机 笔记本和嵌入式系统 xff0c Supplicant是在客户
  • 使用python快速将主机字节序转为网络字节序

    1 进入python环境 这里以win10自带的wsl win10子系统为操作环境进入Python命令行 2 引入网络字节序标准库 这里使用Python自带的socket库 3 将待转换的主机数据使用socket htons 或者socke
  • ∏这个是什么符号?

    是各项连乘的运算符号 读大写的 xff08 pai xff09 例如 xff1a i 61 1 xff08 符号下面 xff09 n xff08 符号上面 xff09 ai 符号右面 表示a1 a2 an 符号下面表示右面式子可变参量的下限
  • python获取图片的颜色信息

    span class pun style font family none font size 14px span h1 style font family none font size 24px padding 5px margin 5p
  • Python:TypeError: 'int' object is not callable

    一个函数的部分代码如下 xff1a python view plain copy def loadData len 61 dataSet len trainingSet extend dataSet len 3 4 testSet exte
  • FreeRTOS — 消息队列

    以下内容转载自安富莱电子 xff1a http forum armfly com forum php FreeRTOS 的一个重要的通信机制 消息队列 xff0c 消息队列在实际项目中应用较多 1 消息队列 1 1 消息队列的概念及其作用
  • 学校人力资源管理系统——物理结构设计

    新 建学校人力资源管理系统 数据库 1 创建相关表 1 1 创建部门信息表 部门信息表的创建代码如下 xff0c 部门信息表在SQL中的信息显示如图6 1所示 create table 部门信息表 部门编号 char 6 not null
  • python 安装serial模块

    想用Python来实现对串口的控制 xff0c 写好了脚本 xff0c 现在将这个脚本拿到另外一个电脑上去运行 xff1b 运行时提示错误 xff0c 说是没有安装serial模块 xff0c 于是乎安装 pip install seria
  • Doxygen使用教程(个人总结)

    简介Doxygen 一 xff0e 什么是Doxygen Doxygen 是一个程序的文件产生工具 xff0c 可将程序中的特定批注转换成为说明文件 通常我们在写程序时 xff0c 或多或少都会写上批注 xff0c 但是对于其它人而言 xf
  • STM32F401 I2S(full duplex)全双工示例代码

    USER CODE BEGIN Header 64 file main c 64 brief Main program body This notice applies to any and all portions of this fil
  • 一、认识与学习Linux中的BASH 之 1.1 什么是bash

    1 1 什么是bash 1 1 1 什么是bash bash全称为The Bourne Again shell xff0c 是Bourne Shell的扩展 xff0c 是基于GUN构架发展出来的语言 xff0c 有很灵活和强大的编程接口
  • 阿里云ECS服务器环境搭建(1) —— ubuntu 16.04 图形界面的安装

    阿里云ECS服务器环境搭建 xff08 1 xff09 ubuntu 16 04 图形界面的安装 1 背景 在我们购买阿里云ECS服务器之后 xff0c 默认的系统环境是很干净的 xff0c 我购买的是ubuntu16 04 xff0c 远
  • Python+pandas+每天股票涨了多少

    第一步 xff1a 得到某支股票历年来的交易数据 方法见 xff1a https blog csdn net zwy 0309 article details 108217342 在此 xff0c 我使用以下脚本得到股票 xff08 代码
  • 2021-06-02

    在ROS中仿真模型中添加gps传感器 获取gps传感器模型包为自己的机器人添加gps传感器将gps之中的经度纬度坐标转化为自己地图中的坐标 1 获取gps传感器模型包 link http wiki ros org hector gazebo
  • Dockerfile如何编写(指令详解)

    本文个人博客地址 xff1a https www leafage top posts detail 21525V8AP Dockerfile Dockerfile 描述了组装镜像的步骤 xff0c 其中每条指令都是单独执行的 除了FROM指
  • 关于Home Lab的搭建——硬件选择篇(迷你主机)(一)

    关于Home Lab 这个名词出自哪里 xff0c 我也不清楚 不过 xff0c 可以这样来理解Home Lab xff0c Home Lab是一台作为实验使用的电脑 xff0c 试验的内容多数是关于计算机网络的搭建 系统安装 测试 xff
  • Adaboost基本二分类算法

    最早类型的Adaboost是由Yoav Freund和Robert E Schapire提出的 xff0c 一种用于二分类的boosting集成学习方法 也是李航 统计学习方法 中所介绍的Adaboost 它将一系列弱分类器的线性组合 xf
  • Springboot 项目金蝶中间件AAS-9.0启动报错 javax.persistence.Table.indexes()[Ljavax/persistence/Index 问题解决

    Springboot 项目金蝶中间件AAS 9 0启动报错 java lang NoSuchMethodError javax persistence Table indexes Ljavax persistence Index问题解决方法
  • CMakeLists配置(常用的)

    一 xff1a 最小组成 cmake 最小版本需求 cmake minimum required VERSION 2 8 project 名字 project MyEsp32AllCode 可执行文件生成 add executable PR
  • SLAM学习笔记(四)定位

    原创博客 xff1a http blog csdn net renshengrumenglibing viewmode 61 contents 机器人定位的目的是为了知道 自己在什么地方 xff0c 目前 xff0c 机器人定位的方法可以分