ROS小车记录系列(二)IMU采集、过滤,与odom数据融合,发布新的odom话题

2023-05-16

(二)IMU采集、过滤,利用EKF将IMU与odom融合,发布新的odom话题

  • A、ROS采集节点
  • B、imu_tools过滤imu数据
  • C、使用 robot_pose_ekf 对imu和odom进行融合

____先说整体处理流程:底层使用STM32F4,采集MPU9250、编码器,通过串口在一个数据帧内将两个数据送入ROS;ROS采集节点将二者数据解析,对IMU发布为imu_data_raw话题,使用 imu_tools订阅过滤后再发布为imu_data_filtered,同时,采集节点将编码器数据航迹推演,发布为odom_raw;接着,使用 robot_pose_ekf订阅imu_data_filtered、odom_raw话题,融合后发布为odom_merger;最后,odom_merger话题数据类型为 geometry_msgs::PoseWithCovarianceStamped,而后续movebase需要类型为 nav_msgs/Odometry,前者是后者内容的一部分,需要简单转换下再发布为odom话题。在这过程中,多看wiki把各个数据类型具体意义搞清楚,数据对应上才能不出错,下面详细介绍我的实现步骤:
后面需要使用到串口和贝叶斯滤波器库,先安装下

sudo apt-get install ros-melodic-serial
sudo apt-get install ros-melodic-bfl

然后,为用户配置串口权限:

sudo gedit /etc/udev/rules.d/70-ttyUSB.rules
##输入:KERNEL=="ttyUSB*", OWNER="root", GROUP="root", MODE="0666" 

保存退出,不用重启电脑,配置完成。

A、ROS采集节点

采集节点是最繁琐步骤,因为要和底层打交道,先上代码,再具体结合代码说吧:


#include <ros/ros.h>
#include <serial/serial.h>
#include <std_msgs/String.h>
#include <std_msgs/Empty.h>
#include <sensor_msgs/Imu.h>
#include <nav_msgs/Odometry.h>
#include <sstream>
#include <tf/transform_broadcaster.h>

typedef union
{
    float  f;
    unsigned char u[4];
}Float4Byte;

signed short left_vel, right_vel;       //单位:rps
const float wheel_dist = 0.52;             //轮间距0.52m
const float circumference = 0.628;          //周长0.628m
const float linesNum = 1024;

serial::Serial ser;

void write_callback(const geometry_msgs::Twist& cmd_vel)
{

    left_vel = (cmd_vel.linear.x - cmd_vel.angular.z * wheel_dist / 2) / circumference;
    right_vel = (cmd_vel.linear.x + cmd_vel.angular.z * wheel_dist / 2) / circumference;

    ROS_INFO("I heard linear velocity: x-[%f],y-[%f],",cmd_vel.linear.x,cmd_vel.linear.y);
    ROS_INFO("I heard angular velocity: [%f]",cmd_vel.angular.z);
//    ser.write(msg->data);   //发送串口数据,用来控制底盘运动
}


unsigned int modbus_CRC(unsigned char *arr_buff, unsigned char len)
{
    unsigned short int crc=0xFFFF;
    unsigned char i, j, Data;
    for( j=0; j < len; j++)
    {
        crc=crc ^*arr_buff++;
        for ( i=0; i<8; i++)
        {
            if( ( crc&0x0001) >0)
            {
                crc=crc>>1;
                crc=crc^ 0xa001;
            }
            else
                crc=crc>>1;
        }
    }
    return crc;
}


int main (int argc, char** argv){
    ros::init(argc, argv, "serial_imu_node");
    ros::NodeHandle nh;
    ros::Subscriber IMU_write_pub = nh.subscribe("cmd_vel", 1000, write_callback);
    ros::Publisher imu_raw_pub = nh.advertise<sensor_msgs::Imu>("imu_data_raw", 1000);
    ros::Publisher odom_pub = nh.advertise<nav_msgs::Odometry>("odom_raw", 500);

    Float4Byte quaternion_q0, quaternion_q1, quaternion_q2, quaternion_q3;
//    Float4Byte vx, vy;  //单位:m/s
    float delta_dist, delta_speed, delta_x, delta_y, pos_x, pos_y; //单位:m
    signed short encoder_right = 0, encoder_left = 0;
    signed short angular_velocity_x, angular_velocity_y, angular_velocity_z;
    signed short linear_acceleration_x, linear_acceleration_y, linear_acceleration_z;

    geometry_msgs::Quaternion odom_quat;
    float delta_th = 0, dt = 0;
    int count = 0;
    unsigned short int crc;
    float th = 0;

    try {
        ser.setPort("/dev/ttyUSB0");
        ser.setBaudrate(460800);
        serial::Timeout to = serial::Timeout::simpleTimeout(1000);
        ser.setTimeout(to);
        ser.open();
    }
    catch (serial::IOException& e){
        ROS_ERROR_STREAM("Unable to open port ");
        return -1;
    }

    if(ser.isOpen()){
        ROS_INFO_STREAM("Serial Port initialized");
    }
    else{
        return -1;
    }


    ros::Time current_time = ros::Time::now();
    ros::Time last_time = ros::Time::now();
    ros::Rate loop_rate(200);

    while(ros::ok()){
        //处理从串口来的Imu数据
        //串口缓存字符数
        unsigned char  data_size;
        if(data_size = ser.available()) { //ser.available(当串口没有缓存时,这个函数会一直等到有缓存才返回字符数

            unsigned char tmpdata[data_size];
            current_time = ros::Time::now();

            //打包IMU数据
            sensor_msgs::Imu imu_data_raw;
            nav_msgs::Odometry odom;

            imu_data_raw.header.stamp = ros::Time::now();
            imu_data_raw.header.seq = count;
            imu_data_raw.header.frame_id = "base_link";

            imu_data_raw.orientation_covariance = {1000000.0, 0, 0,
                                                   0, 1000000, 0,
                                                   0, 0, 0.000001};
            imu_data_raw.angular_velocity_covariance = imu_data_raw.orientation_covariance;
            imu_data_raw.linear_acceleration_covariance = {-1,0,0,0,0,0,0,0,0};

            odom.header.stamp = ros::Time::now();
            odom.header.seq = count;
            odom.header.frame_id = "odom";
            odom.child_frame_id = "base_link";
            odom.pose.covariance = {0.001, 0, 0, 0, 0, 0,
                                    0, 0.001, 0, 0, 0, 0,
                                    0, 0, 1000000, 0, 0, 0,
                                    0, 0, 0, 1000000, 0, 0,
                                    0, 0, 0, 0, 1000000, 0,
                                    0, 0, 0, 0, 0, 1000};
            odom.twist.covariance = odom.pose.covariance;

            ser.read(tmpdata, data_size);
            if((tmpdata[0] == 0xA5) && (tmpdata[1] == 0x5A))
            {
                crc = modbus_CRC(tmpdata, 34);
                if((crc>>8 == tmpdata[35]) && (crc|0xFF == tmpdata[34]))
                {
                    quaternion_q0.u[0] = tmpdata[2]; quaternion_q0.u[1] = tmpdata[3]; quaternion_q0.u[2] = tmpdata[4];
                    quaternion_q0.u[3] = tmpdata[5];
                    quaternion_q1.u[0] = tmpdata[6]; quaternion_q1.u[1] = tmpdata[7]; quaternion_q1.u[2] = tmpdata[8];
                    quaternion_q1.u[3] = tmpdata[9];
                    quaternion_q2.u[0] = tmpdata[10]; quaternion_q2.u[1] = tmpdata[11]; quaternion_q2.u[2] = tmpdata[12];
                    quaternion_q2.u[3] = tmpdata[13];
                    quaternion_q3.u[0] = tmpdata[14]; quaternion_q3.u[1] = tmpdata[15]; quaternion_q3.u[2] = tmpdata[16];
                    quaternion_q3.u[3] = tmpdata[17];
                    linear_acceleration_x = (tmpdata[19] << 8) | tmpdata[18];
                    linear_acceleration_y = (tmpdata[21] << 8) | tmpdata[20];
                    linear_acceleration_z = (tmpdata[23] << 8) | tmpdata[22];
                    angular_velocity_x    = (tmpdata[25] << 8) | tmpdata[24];
                    angular_velocity_y    = (tmpdata[27] << 8) | tmpdata[26];
                    angular_velocity_z    = (tmpdata[29] << 8) | tmpdata[28];
                    encoder_right         = (tmpdata[31] << 8) | tmpdata[30];
                    encoder_left          = (tmpdata[33] << 8) | tmpdata[32];
//                    vx.f = (((tmpdata[30] << 8) | tmpdata[31]) + ((tmpdata[32] << 8) | tmpdata[33]))/1024 * 0.628;
//                    vy.f = 0;
//                    ROS_INFO("linear_acceleration_x: [%d], linear_acceleration_y: [%d], linear_acceleration_z: [%d]", \
//                            linear_acceleration_x, linear_acceleration_y, linear_acceleration_z);
//                    ROS_INFO("angular_velocity_x: [%d], angular_velocity_y: [%d], angular_velocity_z: [%d]", \
                            angular_velocity_x, angular_velocity_y, angular_velocity_z);
                    imu_data_raw.orientation.x = quaternion_q0.f;
                    imu_data_raw.orientation.y = quaternion_q1.f;
                    imu_data_raw.orientation.z = quaternion_q2.f;
                    imu_data_raw.orientation.w = quaternion_q3.f;
                    imu_data_raw.angular_velocity.x = ((float)(angular_velocity_x)/131.0)*3.1415/180.0;
                    imu_data_raw.angular_velocity.y = ((float)(angular_velocity_y)/131.0)*3.1415/180.0;
                    imu_data_raw.angular_velocity.z = ((float)(angular_velocity_z)/131.0)*3.1415/180.0;
                    imu_data_raw.linear_acceleration.x = ((float)(linear_acceleration_x)/16386.0)*9.80665;
                    imu_data_raw.linear_acceleration.y = ((float)(linear_acceleration_y)/16386.0)*9.80665;
                    imu_data_raw.linear_acceleration.z = ((float)(linear_acceleration_z)/16386.0)*9.80665;

//                    encoder_right = 50;
//                    encoder_left = 50;

                    dt = (current_time - last_time).toSec();
                    delta_th = imu_data_raw.angular_velocity.z  * dt;
                    delta_dist = (encoder_right + encoder_left)/linesNum * circumference / 2;
//                    delta_speed = delta_dist / dt;
                    delta_x = cos(delta_th) * delta_dist;
                    delta_y = -sin(delta_th) * delta_dist;
                    th += delta_th;
                    pos_x += (cos(th) * delta_x - sin(th) * delta_y);
                    pos_y += (sin(th) * delta_x + cos(th) * delta_y);
                    odom_quat = tf::createQuaternionMsgFromYaw(th);

                    ROS_INFO("th: %f, pos_x: %f, pos_y: %f", th, pos_x, pos_y);

                    odom.pose.pose.position.x = pos_x;
                    odom.pose.pose.position.y = pos_y;
                    odom.pose.pose.position.z = 0;
                    odom.pose.pose.orientation = odom_quat;
                    odom.twist.twist.linear.x = 0;
                    odom.twist.twist.linear.y = 0;
                    odom.twist.twist.angular.z = imu_data_raw.angular_velocity.z;

                    count++;
                    imu_raw_pub.publish(imu_data_raw); //imu_raw_pub 节点发布消息至imu_data_raw topic
                    odom_pub.publish(odom);
                }
            }
            last_time = current_time;
            ros::spinOnce();
        }
    }
}

____首先,明确下,从串口接收的数据协议:起始帧(0xA5 0x5A)、四元数(float)、三轴加速度计(float)、三轴陀螺仪(float)、左右轮编码器(short)、CRC校验码(标准modbus),发往串口数据:左右轮速度。float类型数据使用联合体传输,不用找博客看的云里雾里,代码一看就明白。
____从main函数看起,建立一个速度控制cmd_vel订阅,两个imu_data_raw、odom_raw发布,再定义一些变量(串口接收数据缓存、航迹推演过程变量)。节点和stm32使用串口通信,在try语句中尝试打开串口,具体串口设置见代码,接着将串口数据依据协议转换,注意imu_data_raw和odom有几个协方差矩阵,设置见代码。加速度计、陀螺仪数据单位为标准单位m/s2,rad/s,从原始数据转换为标准单位要依据IMU初始化设置,对应关系在这里,也可以直接查datasheet,我在初始化时FS_SEL、AFS_SEL都为0,转换过程见代码。航迹推演部分见链接博客,略不同的是,角速度我采样IMU数据,累加计算yaw角度后,转换为四元数发布进odom。到这里,发布imu、odom数据,完成采集、解析。

B、imu_tools过滤imu数据

____做过嵌入式的都知道,传感器的原始数据是不能直接使用的,需要进行标定、过滤,mpu9250标定在这不说了,有兴趣的以后我再写一篇,这里只讲数据过滤。imu过滤有两种方式,一种是在ros里过滤,二是直接在下位机里过滤后上传,比如下位机使用滑动滤波、卡尔曼这样,当然卡尔曼效果更好。可惜下位机卡尔曼的代码好些年没使用,找不到了…所以这部分过滤放ros里做了,直接使用的imu_tools。git一通扒拉,复制里面的imu_filter_madgwick文件夹到我们的ros工作空间源码目录,根目录catkin_make一下就能用了。
____在src/complementary_filter_ros.cpp中67行左右,有句代码修改如下,订阅我们自己的话题名。

   // Register IMU raw data subscriber.
  imu_subscriber_.reset(new ImuSubscriber(nh_, "/imu_data_raw", queue_size));

52行左右修改如下,发布过滤后的数据。

     // Register publishers:
  imu_publisher_ = nh_.advertise<sensor_msgs::Imu>("/imu_data_filtered", queue_size);

修改launch文件如下:

    <!-- ComplementaryFilter launch file -->
<launch>

  <node pkg="imu_complementary_filter" type="complementary_filter_node"
      name="complementary_filter_gain_node" output="screen">
    <param name="do_bias_estimation" value="true"/>
    <param name="do_adaptive_gain" value="true"/>
    <param name="use_mag" value="false"/>
    <param name="gain_acc" value="0.01"/>
    <param name="gain_mag" value="0.01"/>
    <param name="publish_debug_topics" value="false"/>
    <param name="publish_tf" value="false"/>
  </node>

  <node pkg="rplidar_ros" type="imu_encoder_com"
        name="imu_encoder_com_node" output="screen">
  </node>

</launch>

____做一些设置,记得关闭发布tf,顺手启动下采集节点。现在可以启动了,rostopic echo、rviz都可以查看过滤后的数据。launch文件里可以看到,实际上是可以地磁信息也放进去的,而mpu9250是带有地磁计的,可以从串口传进来送进去过滤,但是我在下位机计算四元数时已经把地磁信息加进去了,所以imu_tools这里没使用地磁。

C、使用 robot_pose_ekf 对imu和odom进行融合

robot_pose_ekf包的使用,主要是参考了这里,下载下来,catkin_make就可以,编译robot_pose_ekf包时候,可能出现错误:No package ‘orocos-bfl’ found,解决:

   sudo apt-get install ros-melodic-bfl.

然后按照博客里的设置修改下去,注意话题名称一定要对应上,还有就是TF树,在odom_estimation_node.cpp中,odom_broadcaster.sendTransform(StampedTransform(tmp, tmp.stamp, output_frame, base_footprint_frame))函数会发布一个odom到base_footprint的TF,在这我注释掉了不让他发布。 我的launch文件如下:

   <launch>

    <node pkg="robot_pose_ekf" type="robot_pose_ekf" name="robot_pose_ekf">
      <param name="output_frame" value="odom_combined"/>
      <param name="base_footprint_frame" value="base_footprint"/>
      <param name="freq" value="50.0"/>
      <param name="sensor_timeout" value="1.0"/>
      <param name="odom_used" value="true"/>
      <param name="imu_used" value="true"/>
      <param name="vo_used" value="false"/>
    </node>


</launch>

到这里,融合完成,这时候odom是PoseWithCovarianceStamped格式,需要自己转换成后面导航部分要求的格式Odometry,,网上找的都是python,比较简单就自己写了个cpp,同时发布一下TF:

//
// Created by smith on 7/24/20.
//

#include "ros/ros.h"
#include "std_srvs/Empty.h"
#include <geometry_msgs/PoseWithCovarianceStamped.h>
#include <nav_msgs/Odometry.h>
#include <tf/transform_broadcaster.h>

class OdomEKFTransform
{
    public:
    OdomEKFTransform()
        {
            pub_ = n_.advertise<nav_msgs::Odometry>("/odom", 100);
            sub_ = n_.subscribe("/robot_pose_ekf/odom_combined", 100, &OdomEKFTransform::callback, this);
        }

        void callback(const geometry_msgs::PoseWithCovarianceStamped& msg)
        {
            nav_msgs::Odometry odom;
            geometry_msgs::TransformStamped odom_trans;
            static tf::TransformBroadcaster odom_broadcaster;

            odom.header = msg.header;
            odom.header.frame_id = "odom";
            odom.pose = msg.pose;
            pub_.publish(odom);

            odom_trans.header.stamp = ros::Time::now();
            odom_trans.header.frame_id = "odom";
            odom_trans.child_frame_id = "base_footprint";
            odom_trans.transform.translation.x = odom.pose.pose.position.x;
            odom_trans.transform.translation.y = odom.pose.pose.position.x;
            odom_trans.transform.translation.z = 0.0;
            odom_trans.transform.rotation = odom.pose.pose.orientation;
            odom_broadcaster.sendTransform(odom_trans);
        }

    private:
        ros::NodeHandle n_;
        ros::Publisher pub_;
        ros::Subscriber sub_;
};

int main(int argc, char **argv)
{
    ros::init(argc, argv, "OdomEKF");
    OdomEKFTransform odomEKF;
    ros::Rate loop_rate(50);
    while(ros::ok()) {
        ros::spin();
    }
    return 0;
}

//最后一句,航迹推演放下位机去处理后,把坐标发上来,不要在ros做,可能自己水平不够,真是坑。。。
//odom发布频率,尽量高于40hz,太低了会影响cartographer定位效果,我用的80hz。–2021.7.10

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

ROS小车记录系列(二)IMU采集、过滤,与odom数据融合,发布新的odom话题 的相关文章

  • centos7系统提示no space left on device

    一 操作报错 no space left on device 但是查看系统磁盘占用空间 xff0c 却还有空闲 xff0c 说明是inodes占用满了 二 查看磁盘系统的inodes使用情况 三 要解决这问题 xff0c 只需找出 xff0
  • page_cleaner

    MySQL Error Log 中IO写入瓶颈的警告分析 在一台MySQL实例上频繁做大批量的写入测试 xff0c 无意中发现MySQL的errorlog中频繁出现如下的Note xff1a page cleaner 1000ms inte
  • mysql的存储函数与存储过程

    1 存储过程概述 我们前面所学习的 MySQL 语句都是针对一个表或几个表的单条 SQL 语句 xff0c 但是在数据库的实际操作中 xff0c 经常会有需要多条 SQL 语句处理多个表才能完成的操作 例如 xff0c 为了确认学生能否毕业
  • 逆变

    去年今日此门中 xff0c 人面桃花相映红 人面不知何处去 xff0c 桃花依旧笑春风 去年的今天 xff0c 刚高考完的我正处于迷茫与蹉跎之中 xff0c 想起那时候的我 xff0c 怀着此种状态 xff0c 想必也无可厚非吧 xff01
  • 使用SecureCRT+VNCViewer进行端口转发,修改端口映射

    1 设置本地端口转发属性 xff0c 设置成功后 xff0c 此时已经将服务器上的5901端口映射到windows本地的5901端口 2 打开本机VNCViewer进行远程连接的配置 3 打开该远程连接 xff0c 进行5000端口和999
  • 面试题目积累

    题目一 xff1a 如何配置寄存器 xff08 1 xff09 通过手册 一 找到要操作IO口的基地址 二 找到端口输入寄存器的地址偏移 三 找到输入数据寄存器中具体的端口数据位 2 操作IO口 一 找到基地址 二 找到偏移地址 xff0c
  • FreeRTOS学习笔记-Stream Buffer

    FreeRTOS学习笔记 Stream Buffer 概述关键函数课程示例StreamBuffer 创建 发送与接收StreamBuffer查询接收添加监控任务 xff0c 确定StreamBuffer大小 概述 关键函数 span cla
  • 色彩表示与编码

    图片中的代码 xff0c 依旧是RGB色值的表示 在计算机中 xff0c RGB的每个通道 xff0c 通常都以8位2进制空间来存储 xff0c 因此能对每个通道进行256阶分级 xff1a 以10进制数表示时 xff0c 范围为0 255
  • 程序猿小白的2016—不忘初心,继续奋斗

    回顾过去的一年 xff0c 酸甜苦辣各种滋味 这一年很不一样 xff0c 离开了大学校门 xff0c 在社会上也体验了一把 思想逐渐成熟起来 xff0c 2016已然成为过去 xff0c 却带给了自己很多难忘的经历 完美的毕业设计 作为一名
  • 流媒体传输协议浅析(二)UDP媒体传输

    一 引言 既然UDP天然适合流媒体场景 xff0c 为什么还存在TCP的流媒体协议 xff1f UDP的实时性 xff0c 低延迟 xff0c 又支持组播 xff0c 确实适合音视频场景 xff0c 但由于UDP是不稳定不可靠传输技术 xf
  • 流媒体传输协议浅析(三)可靠UDP传输方案

    一 引言 从流媒体的业务特征和TCP xff0c UDP各种特点 xff0c UDP在媒体传输方面具有很大优越性 xff0c 但UDP可靠性需要业务开发这投入大量的人力 xff1b 相反 tcp 技术成熟 xff0c 可以复用已稳定的htt
  • Android Studio 使用Lambda表达式「详细配置」

    前言 xff1a Lambda 表达式 xff0c 也可称为闭包 xff0c 它是推动 Java 8 发布的最重要新特性 Lambda 允许把函数作为一个方法的参数 xff08 函数作为参数传递进方法中 xff09 使用 Lambda 表达
  • 如何解决 Python 错误 NameError: name ‘X‘ is not defined

    Python NameError name is not defined 发生在我们试图访问一个未定义的变量或函数时 xff0c 或者在它被定义之前 要解决该错误 xff0c 需要确保我们没有拼错变量名并在声明后访问它 确保你没有拼错变量或
  • Ajax请求返回图片

    需求 xff1a 使用Ajax返回图片数据展示在Img标签上 前端Ajax请求 lt HTML标签 gt lt img id 61 34 ImagePic 34 alt 61 34 Base64 encoded image 34 width
  • 多读书,读好书

    古人云读书百变其义自现 xff0c 当今是个大数据时代 xff0c 各类书籍种类繁多 xff0c 我们不可能一一预览 xff0c 同时也不需要 也没时间一一细看 xff0c 我们需要的是多遍阅读经典书籍 xff0c 将会事半功倍 下面我将介
  • kendoGrid合并单元格

    kendoGrid默认API中并没有合并单元格的方法 xff0c 故自己借鉴网友的代码并做了改造 xff0c 下述代码及完成了kendoGrid中的行的合并 xff08 在 dataBound事件中完成 xff09 span class t
  • Git合并指定文件到其他分支

    1 合并某个分支上的指定commit span class token comment 在dev分支合并bugfix分支上的 ac0ca63 commit span git branch span class token operator
  • 有刷电机与无刷电机的区别,就是这么简单明了:

    一 有刷电机 xff1a 有刷电机是大家最早接触的一类电机 xff0c 例如很多电动小玩具 xff0c 或者很多家用的吹风机里面的电机都是有刷电机 有刷电机的主要结构就是定子 转子 电刷 xff0c 通过旋转磁场获得转动力矩 xff0c 从
  • ubuntu 完全干净的卸载docker

    1 删除某软件 及其安装时自动安装的所有包 sudo apt get autoremove docker docker ce docker engine docker io containerd runc 2 删除docker其他没有没有卸
  • shell命令—find

    find命令 span class token comment 删除 home fengshuiyue目录下一周前的目录 span fengshuiyue 64 ralc span class token operator gt span

随机推荐

  • shell命令—date

    date命令 span class token comment 获取当前时间 日期格式是 YYYY mm dd HH MM SS span span class token function date span span class tok
  • 大华硬盘录像机、网络摄像机、 网络硬盘录像机外网远程设置DDNS方法

    1 为了便于解释在下文介绍中 xff0c 硬盘录像机 网络摄像机 网络硬盘录像机统一称为 大华设备 2 外网最好是电信 如果不是 xff0c 那必须要确认客户的外网 IP 是唯一的 xff0c 不是与其他用户共用的 3 首先确保 大华设备
  • LibCurl HTTP部分详细介绍

    目录索引 xff1a 一 LibCurl基本编程框架 二 一些基本的函数 三 curl easy setopt函数部分选项介绍 四 curl easy perform 函数说明 xff08 error 状态码 xff09 五 libcurl
  • navicat连接oracle报错:ORA-12737 Instant Client Light:unsupported server character set ZHS16GBK

    今天使用Navicat连接Oracle数据库 xff0c 报了下面的这个错误 xff1a ORA 12737 Instant Client Light unsupported server character set ZHS16GBK 从这
  • VMWare报错"指定的文件不是虚拟磁盘"或“The file specified is not a virtual disk”

    今天打开原来创建的虚拟机 xff0c 突然报错 指定的文件不是虚拟磁盘 xff0c 如下图 xff1a 由于之前这个虚拟机创建了快照 xff0c 因此下面的解决方法是基于快照的 1 打开虚拟机的 vmx文件 xff0c 我的虚拟机名字为 U
  • Javascript模块加载框架——seajs

    最近看了一些开源web的项目 xff0c 发现其前台采用的框架seajs在编写JavaScript代码上很是方便 xff0c 现将学习的记录记于此 1 什么是JavaScript模块加载 为了解决不同javascript库里操作对象的命名冲
  • 2016年底总结

    一年又过去了 xff0c 在此简单说说这一年的收获和感受吧 一 说说考试 今年参加了两场考试 xff0c 一个是注册电气工程师 xff08 供配电 xff09 考试 xff0c 另外一个是一级建造师考试 两个考试均在9月份进行 xff0c
  • JS实现浏览器打印、打印预览

    目前正在做浏览器端采用JS方式实现打印这么一个功能 xff0c JS打印实现的方法很多 xff0c 但是兼容各个浏览器实现打印预览的功能有些棘手 xff0c 现将实现的内容及遇到的问题记录下来 xff0c 希望有大牛看到所提的问题后可以给予
  • STM32流水灯

    这个是根据51的基础上改的 一看就懂 直接在main c编辑就行 而不用去弄什么固件库 寄存器 这个是8个灯 然后设置A0 A7口为Output 推挽输出 就行 直接在user的main c中写就好 USER CODE BEGIN Head
  • PX4Ubuntu16.04环境搭建

    一 在虚拟机上安装一个新的ubuntu16 04系统 二 打开PX4的GITHUB主页 https github com PX4 Firmware 1 按照教程 这些脚本已经在干净的Ubuntu LTS 16 04和Ubuntu LTS 1
  • ucosII 信号量使用总结(举例讲解)

    概述 信号量用于 xff1a 1 控制共享资源的使用权 xff08 满足互斥条件 xff09 2 标志某时间的发生 3 使2个任务的行为同步 OSSemCreate 赋初值 OSSemCreate INT16U cnt xff0c cnt为
  • 用supervisor管理进程报错 “exit status 1 not expected”

    查看supervisor的日志发现报错 xff1a tail f var log supervisor supervisord log exited cyberwing domain numbercard exit status 1 not
  • Linux下core文件产生的一些注意问题

    前面转载了一篇文章关于core文件的产生和调试使用的设置 xff0c 但在使用有一些需要注意的问题 xff0c 如 在什么情况 才会正确地产生core文件 列出一些常见问题 xff1a 一 xff0c 如何使用core文件 1 使用core
  • windows10+ubuntu16.04双系统安装教程--UEFI安装方法

    本人github其他资料地址 xff1a https github com Bubble water deeplearning 一 ubuntu 1 1 ubuntu 系统镜像链接 1 2 刻录ubuntu 系统镜像 1 3 安装教程 往下
  • px4: v2的主板刷写v2的固件

    v2的主板刷写v2的固件 fengxuewei 64 fengxuewei Legion Y7000 2019 PG0 src Firmware changwei rc span class token function make span
  • C++语言HTTP协议解析器

    httpParser 项目地址 xff1a https github com yuesong feng httpParser C 43 43 版本的 HTTP 协议解析器 xff0c 可自动识别 request 与 response 请求
  • Docker push 命令

    https www jianshu com p 1c8b96cf1f13 Docker hub注册用户 到官网注册账号 xff1a https hub docker com 在本地Linux登录docker xff1a docker 64
  • docker 配置国内镜像地址

    https www cnblogs com cocoajin p 15513348 html 为docker配置国内镜像地址 xff0c 用于在pull镜像下载加速 1 创建配置文件daemon json 在目录 etc docker da
  • Dockerfile的使用

    dockerfile中的指令 构建镜像 docker build t 仓库地址 仓库名称 镜像名称 标签 在dockerfile目录下构建 文件名为Dockerfile FORM span class token comment 指定基础镜
  • ROS小车记录系列(二)IMU采集、过滤,与odom数据融合,发布新的odom话题

    xff08 二 xff09 IMU采集 过滤 xff0c 利用EKF将IMU与odom融合 xff0c 发布新的odom话题 A ROS采集节点B imu tools过滤imu数据C 使用 robot pose ekf 对imu和odom进