树莓派4B+ROS+RealSense T265室内定位替代光流开源方案

2023-05-16

 

硬件机载端:树莓派4B 4/8G 、T265、RPLIDAR-A2

配套开发环境:

树莓派系统Ubuntu 20.04.3 LTS

RealSense SDK 2.0

ROS系统版本:noetic+realsense-ros

多平台远程登陆软件:nomachine(win10、mac、安卓、ubuntu等)

有两种方案实现t265位姿数据,本方案通过修改宏定义T265_STATE_CAPTURE_ENABLE实现

1、可直接利用SDK函数中的rs-pose获取位姿数据,参考链接如下:

rs-pose (intelrealsense.com)

2、利用官方提供的realsense-ros包中自带的demo启动roslaunch realsense2_camera rs_t265.launch,通过订阅节点发布的"/camera/odom/sample"话题获取位姿数据

传输浮点数据需有用到的数据转换函数(大小端通用)

#include <iostream>

#include "datatf.h"

using namespace std;

union

{

unsigned char floatByte[4];

float floatValue;

}FloatUnion;

/***************************************************************************************

@函数名:void Float2Byte(float *FloatValue, unsigned char *Byte, unsigned char Subscript)

@入口参数:FloatValue:float值

     Byte:数组

       Subscript:指定从数组第几个元素开始写入

@出口参数:无

功能描述:将float数据转成4字节数据并存入指定地址

@作者:无名小哥

@日期:2020年01月17日

****************************************************************************************/

void Float2Byte(float *FloatValue, unsigned char *Byte, unsigned char Subscript)

{

FloatUnion.floatValue = (float)2;

if(FloatUnion.floatByte[0] == 0)//小端模式

{

FloatUnion.floatValue = *FloatValue;

Byte[Subscript]     = FloatUnion.floatByte[0];

Byte[Subscript + 1] = FloatUnion.floatByte[1];

Byte[Subscript + 2] = FloatUnion.floatByte[2];

Byte[Subscript + 3] = FloatUnion.floatByte[3];

}

else//大端模式

{

FloatUnion.floatValue = *FloatValue;

Byte[Subscript]     = FloatUnion.floatByte[3];

Byte[Subscript + 1] = FloatUnion.floatByte[2];

Byte[Subscript + 2] = FloatUnion.floatByte[1];

Byte[Subscript + 3] = FloatUnion.floatByte[0];

}

}

/***************************************************************************************

@函数名:void Byte2Float(unsigned char *Byte, unsigned char Subscript, float *FloatValue)

@入口参数:Byte:数组

     Subscript:指定从数组第几个元素开始写入

       FloatValue:float值

@出口参数:无

功能描述:从指定地址将4字节数据转成float数据

@作者:无名小哥

@日期:2020年01月17日

****************************************************************************************/

void Byte2Float(unsigned char *Byte, unsigned char Subscript, float *FloatValue)

{

FloatUnion.floatByte[0]=Byte[Subscript];

FloatUnion.floatByte[1]=Byte[Subscript + 1];

FloatUnion.floatByte[2]=Byte[Subscript + 2];

FloatUnion.floatByte[3]=Byte[Subscript + 3];

*FloatValue=FloatUnion.floatValue;

}

传输浮点数据需有用到的数据转换函数(大小端通用)

#include <iostream>

#include "datatf.h"

using namespace std;

union

{

unsigned char floatByte[4];

float floatValue;

}FloatUnion;

/***************************************************************************************

@函数名:void Float2Byte(float *FloatValue, unsigned char *Byte, unsigned char Subscript)

@入口参数:FloatValue:float值

     Byte:数组

       Subscript:指定从数组第几个元素开始写入

@出口参数:无

功能描述:将float数据转成4字节数据并存入指定地址

@作者:无名小哥

@日期:2020年01月17日

****************************************************************************************/

void Float2Byte(float *FloatValue, unsigned char *Byte, unsigned char Subscript)

{

FloatUnion.floatValue = (float)2;

if(FloatUnion.floatByte[0] == 0)//小端模式

{

FloatUnion.floatValue = *FloatValue;

Byte[Subscript]     = FloatUnion.floatByte[0];

Byte[Subscript + 1] = FloatUnion.floatByte[1];

Byte[Subscript + 2] = FloatUnion.floatByte[2];

Byte[Subscript + 3] = FloatUnion.floatByte[3];

}

else//大端模式

{

FloatUnion.floatValue = *FloatValue;

Byte[Subscript]     = FloatUnion.floatByte[3];

Byte[Subscript + 1] = FloatUnion.floatByte[2];

Byte[Subscript + 2] = FloatUnion.floatByte[1];

Byte[Subscript + 3] = FloatUnion.floatByte[0];

}

}

/***************************************************************************************

@函数名:void Byte2Float(unsigned char *Byte, unsigned char Subscript, float *FloatValue)

@入口参数:Byte:数组

     Subscript:指定从数组第几个元素开始写入

       FloatValue:float值

@出口参数:无

功能描述:从指定地址将4字节数据转成float数据

@作者:无名小哥

@日期:2020年01月17日

****************************************************************************************/

void Byte2Float(unsigned char *Byte, unsigned char Subscript, float *FloatValue)

{

FloatUnion.floatByte[0]=Byte[Subscript];

FloatUnion.floatByte[1]=Byte[Subscript + 1];

FloatUnion.floatByte[2]=Byte[Subscript + 2];

FloatUnion.floatByte[3]=Byte[Subscript + 3];

*FloatValue=FloatUnion.floatValue;

}

机载端代码如下:

#include <ros/ros.h>

#include <serial/serial.h>

#include <std_msgs/String.h>

#include <std_msgs/Bool.h>

#include <std_msgs/Empty.h>

#include <geometry_msgs/Pose.h>

#include <geometry_msgs/PoseStamped.h>

#include <geometry_msgs/Vector3.h>

#include <nav_msgs/Odometry.h>

#include <tf2/LinearMath/Quaternion.h>

#include <librealsense2/rs.hpp>

#include "datatf.h"

#define T265_STATE_CAPTURE_ENABLE   1

static uint8_t NCLink_Head[2]={0xFC,0xFF};//数据帧头

static uint8_t NCLink_End[2] ={0xA1,0xA2};//数据帧尾

uint8_t nclink_databuf[100];//待发送数据缓冲区

serial::Serial com;

geometry_msgs::Pose current_position;

geometry_msgs::Pose target_position;

geometry_msgs::Vector3 currrent_velocity;

std_msgs::Bool current_position_update_flag;

std_msgs::Bool target_position_update_flag;

void NCLink_Send_Currrent_State(float userdata1  ,float userdata2,

        float userdata3  ,float userdata4,

        float userdata5  ,float userdata6,

                                float userdata7  ,float userdata8,

                                float userdata9  ,float userdata10,

                                float quality    ,

                                uint8_t byte0,

                                uint8_t byte1,

                                uint8_t byte2,

                                uint8_t byte3,

                                uint8_t byte4,

                                uint8_t byte5,

                                uint8_t byte6,

                                uint8_t byte7,

                                uint8_t update_flag,uint8_t msg_id)

{

    uint8_t sum=0,_cnt=0,i=0;

    nclink_databuf[_cnt++]=NCLink_Head[0];

    nclink_databuf[_cnt++]=NCLink_Head[1];

    nclink_databuf[_cnt++]=msg_id;

    nclink_databuf[_cnt++]=0;

        

    Float2Byte(&userdata1,nclink_databuf,_cnt);//position.x

    _cnt+=4;

    Float2Byte(&userdata2,nclink_databuf,_cnt);//position.y

    _cnt+=4;

    Float2Byte(&userdata3,nclink_databuf,_cnt);//position.z

    _cnt+=4;

    Float2Byte(&userdata4,nclink_databuf,_cnt);//velocity.x

    _cnt+=4;

    Float2Byte(&userdata5,nclink_databuf,_cnt);//velocity.y

    _cnt+=4;

    Float2Byte(&userdata6,nclink_databuf,_cnt);//velocity.z

    _cnt+=4;

    Float2Byte(&userdata7,nclink_databuf,_cnt);//quaternion.x

    _cnt+=4;

    Float2Byte(&userdata8,nclink_databuf,_cnt);//quaternion.y

    _cnt+=4;

    Float2Byte(&userdata9,nclink_databuf,_cnt);//quaternion.z

    _cnt+=4;//28

    Float2Byte(&userdata10,nclink_databuf,_cnt);//quaternion.w

    _cnt+=4;//32

    Float2Byte(&quality,nclink_databuf,_cnt);//quality

    _cnt+=4;//32

    nclink_databuf[_cnt++]=byte0;

    nclink_databuf[_cnt++]=byte1;

    nclink_databuf[_cnt++]=byte2;

    nclink_databuf[_cnt++]=byte3;

    nclink_databuf[_cnt++]=byte4;

    nclink_databuf[_cnt++]=byte5;

    nclink_databuf[_cnt++]=byte6;

    nclink_databuf[_cnt++]=byte7;

    nclink_databuf[_cnt++]=update_flag;

    nclink_databuf[3] = _cnt-4;

    for(i=0;i<_cnt;i++) sum ^= nclink_databuf[i]; 

    nclink_databuf[_cnt++]=sum;

    nclink_databuf[_cnt++]=NCLink_End[0];

    nclink_databuf[_cnt++]=NCLink_End[1];

    com.write(nclink_databuf,_cnt);

    //ROS_INFO("%d",_cnt);

}

void serial_write_callback(const std_msgs::String::ConstPtr& msg)

{

    ROS_INFO_STREAM("writing to serial port"<<msg->data);

    com.write(msg->data);

}

#ifdef T265_STATE_CAPTURE_ENABLE 

void t265_callback_internal(const geometry_msgs::PoseStamped::ConstPtr& msg)

{

    ROS_INFO_STREAM("t265_callback_internal");

    NCLink_Send_Currrent_State(msg->pose.position.x,

                               msg->pose.position.y,

                               msg->pose.position.z,

                               currrent_velocity.x,

                               currrent_velocity.y,

                               currrent_velocity.z,

                               msg->pose.orientation.x,

                               msg->pose.orientation.y,

                               msg->pose.orientation.z,

                               msg->pose.orientation.w,

                               100.0f,0x01,

                               0,1,2,3,4,5,6,7,

                               0x0D);

}

#endif

void t265_callback_external(const nav_msgs::Odometry::ConstPtr& msg)

{

    ROS_INFO_STREAM("t265_callback_external"); 

    NCLink_Send_Currrent_State(msg->pose.pose.position.y,

                               msg->pose.pose.position.x,

                               msg->pose.pose.position.z,

                               msg->twist.twist.linear.y,

                               msg->twist.twist.linear.x,

                               msg->twist.twist.linear.z,

                               -msg->pose.pose.orientation.y,

                               msg->pose.pose.orientation.z,

                               -msg->pose.pose.orientation.x,

                               msg->pose.pose.orientation.w,

                               100.0f,0x01,

                               0,1,2,3,4,5,6,7,

                               0x0D);

}

int main(int argc,char** argv)

{

    ros::init(argc,argv,"serialport");

    ros::NodeHandle n;

    ros::Subscriber serial_write_sub=n.subscribe("serial_write",1000,serial_write_callback);

    ros::Publisher serial_read_pub=n.advertise<std_msgs::String>("serial_write",1000);

    ros::Subscriber t265_sub_external=n.subscribe("/camera/odom/sample",1000,t265_callback_external);

#ifdef T265_STATE_CAPTURE_ENABLE   

    ros::Subscriber t265_sub_innernal=n.subscribe("/t265/odom/sample",1000,t265_callback_internal);

    ros::Publisher t265_pub=n.advertise<geometry_msgs::PoseStamped>("/t265/odom/sample",1000); 

    rs2::pipeline pipe;

    rs2::config cfg;

    cfg.enable_stream(RS2_STREAM_POSE,RS2_FORMAT_6DOF);

    pipe.start(cfg);

#endif

    try

    {

        com.setPort("/dev/serial0");//("/dev/ttyUSB0");("/dev/ttyAMA0");

        com.setBaudrate(921600);

        serial::Timeout to=serial::Timeout::simpleTimeout(1000);

        com.setTimeout(to);

        com.open();

    }

    catch (serial::IOException& e)

    {

        ROS_ERROR_STREAM("unable to open port");

        return -1;

    }

    if(com.isOpen())

    {

        ROS_INFO_STREAM("serial port is initialized");

    }

    else return -1;

    ros::Rate loop_rate(100);

    while(ros::ok())

    {

        if(com.available())

        {

            ROS_INFO_STREAM("read from serial port\n");

            std_msgs::String result;

            result.data=com.read(com.available());

            ROS_INFO_STREAM("read: "<<result.data);

            serial_read_pub.publish(result);

        }

        ros::spinOnce();

        loop_rate.sleep();

#ifdef T265_STATE_CAPTURE_ENABLE  

        auto frames=pipe.wait_for_frames();

        auto f=frames.first_or_default(RS2_STREAM_POSE);

        auto pose_data=f.as<rs2::pose_frame>().get_pose_data();

        //rs2_pose pose_data;

        geometry_msgs::PoseStamped pmsg;

        pmsg.pose.position.x=current_position.position.x=-pose_data.translation.x;

        pmsg.pose.position.y=current_position.position.y=-pose_data.translation.z;

        pmsg.pose.position.z=current_position.position.z=pose_data.translation.y;

        currrent_velocity.x=-pose_data.velocity.x;

        currrent_velocity.y=-pose_data.velocity.z;

        currrent_velocity.z=pose_data.velocity.y;

        pmsg.pose.orientation.x=pose_data.rotation.x;

        pmsg.pose.orientation.y=pose_data.rotation.y;

        pmsg.pose.orientation.z=pose_data.rotation.z;

        pmsg.pose.orientation.w=pose_data.rotation.w;

        t265_pub.publish(pmsg);

        ROS_INFO("translation:%f %f %f",

        pose_data.translation.x,

        pose_data.translation.y,

        pose_data.translation.z);

        ROS_INFO("velocity:%f %f %f",

        pose_data.velocity.x,

        pose_data.velocity.y,

        pose_data.velocity.z);

        ROS_INFO("quad:%f %f %f %f",

        pose_data.rotation.x,

        pose_data.rotation.y,

        pose_data.rotation.z,

        pose_data.rotation.w);

#endif        

    }

}

飞控端解析代码如下:

void NCLink_Data_Prase_Process_Lite(uint8_t *data_buf,uint8_t num)//飞控数据解析进程

{

  uint8_t sum = 0;

  for(uint8_t i=0;i<(num-3);i++)  sum ^= *(data_buf+i);

  if(!(sum==*(data_buf+num-3)))    return;//判断sum

if(!(*(data_buf)==NCLink_Head[1]&&*(data_buf+1)==NCLink_Head[0]))         return;//判断帧头

if(!(*(data_buf+num-2)==NCLink_End[0]&&*(data_buf+num-1)==NCLink_End[1])) return;//帧尾校验  

if(*(data_buf+2)==0X0A)                             //地面站控制移动数据

  {

    ngs_sdk.move_mode=*(data_buf+4),

ngs_sdk.mode_order=*(data_buf+5);

    ngs_sdk.move_distance=(uint16_t)(*(data_buf+6)<<8)|*(data_buf+7);;

    ngs_sdk.update_flag=true;

ngs_sdk.move_flag.sdk_front_flag=false;

ngs_sdk.move_flag.sdk_behind_flag=false;

ngs_sdk.move_flag.sdk_left_flag=false;

ngs_sdk.move_flag.sdk_right_flag=false;

ngs_sdk.move_flag.sdk_up_flag=false;

ngs_sdk.move_flag.sdk_down_flag=false;

if(*(data_buf+4)==SDK_FRONT)

{

ngs_sdk.move_flag.sdk_front_flag=true;

ngs_sdk.f_distance=ngs_sdk.move_distance;

}

else if(*(data_buf+4)==SDK_BEHIND) 

{

ngs_sdk.move_flag.sdk_behind_flag=true;

ngs_sdk.f_distance=-ngs_sdk.move_distance;

}

else if(*(data_buf+4)==SDK_LEFT)  

{

ngs_sdk.move_flag.sdk_left_flag=true;

ngs_sdk.f_distance=-ngs_sdk.move_distance;

}

else if(*(data_buf+4)==SDK_RIGHT)

{

ngs_sdk.move_flag.sdk_right_flag=true;

ngs_sdk.f_distance=ngs_sdk.move_distance;

}

else if(*(data_buf+4)==SDK_UP)

ngs_sdk.move_flag.sdk_up_flag=true;

ngs_sdk.f_distance=ngs_sdk.move_distance;

}

else if(*(data_buf+4)==SDK_DOWN) 

{

ngs_sdk.move_flag.sdk_down_flag=true;

ngs_sdk.f_distance=-ngs_sdk.move_distance;

}

NCLink_Send_Check_Flag[8]=1;

Pilot_Status_Tick();

  }

else if(*(data_buf+2)==0X0C)

  {

Guide_Flight_Lng =((int32_t)(*(data_buf+4)<<24)|(*(data_buf+5)<<16)|(*(data_buf+6)<<8)|*(data_buf+7));

Guide_Flight_Lat =((int32_t)(*(data_buf+8)<<24)|(*(data_buf+9)<<16)|(*(data_buf+10)<<8)|*(data_buf+11));

Guide_Flight_Cnt++;;

Guide_Flight_Flag=1;

Pilot_Status_Tick();

}

else if(*(data_buf+2)==0X0D)

{

Byte2Float(data_buf,4,&current_state.position_x);

Byte2Float(data_buf,8,&current_state.position_y);

Byte2Float(data_buf,12,&current_state.position_z);

Byte2Float(data_buf,16,&current_state.velocity_x);

Byte2Float(data_buf,20,&current_state.velocity_y);

Byte2Float(data_buf,24,&current_state.velocity_z);

current_state.position_x*=100.0f;

current_state.position_y*=100.0f;

current_state.position_z*=100.0f;

current_state.velocity_x*=100.0f;

current_state.velocity_y*=100.0f;

current_state.velocity_z*=100.0f;

Byte2Float(data_buf,28,&current_state.q[0]);

Byte2Float(data_buf,32,&current_state.q[1]);

Byte2Float(data_buf,36,&current_state.q[2]);

Byte2Float(data_buf,40,&current_state.q[3]);

float _q[4];

_q[0]=current_state.q[3]*(1.0f);

_q[1]=current_state.q[0]*(1.0f);

_q[2]=current_state.q[2]*(-1.0f);

_q[3]=current_state.q[1]*(1.0f);

current_state.q[0]=_q[0];

current_state.q[1]=_q[1];

current_state.q[2]=_q[2];

current_state.q[3]=_q[3];

quad_getangle(current_state.q,current_state.rpy);

if(current_state.rpy[2]<0.0f)   current_state.rpy[2]+=360.0f;

if(current_state.rpy[2]>360.0f) current_state.rpy[2]-=360.0f;

Byte2Float(data_buf,44,&current_state.quality);

current_state.update_flag=*(data_buf+48);

current_state.byte[0]=*(data_buf+49);

current_state.byte[1]=*(data_buf+50);

current_state.byte[2]=*(data_buf+51);

current_state.byte[3]=*(data_buf+52);

current_state.byte[4]=*(data_buf+53);

current_state.byte[5]=*(data_buf+54);

current_state.byte[6]=*(data_buf+55);

current_state.byte[7]=*(data_buf+56);

Pilot_Status_Tick();

  Get_Systime(&nclink_t);

}

}

飞控IMU与VIO融合代码如下:

uint16_t VIO_Sync_Cnt=5;

float K_ACC_VIO=1.0f,K_VEL_VIO=5.0f,K_POS_VIO=1.0f;

void  VIO_SLAM_INS_CF(void)

{

  Vector2f speed_delta={0};

float obs_err[2];

  if(current_state.update_flag==1)//存在数据光流更新时,20ms一次

  { 

opt_data.valid=1;

current_state.update_flag=0; 

OpticalFlow_Position.x=current_state.position_x;

OpticalFlow_Position.y=current_state.position_y;

OpticalFlow_Speed.x   =current_state.velocity_x;

OpticalFlow_Speed.y   =current_state.velocity_y;

OpticalFlow_Speed_Err.x=OpticalFlow_Speed.x-VIO_SINS.Speed[_EAST];

OpticalFlow_Speed_Err.y=OpticalFlow_Speed.y-VIO_SINS.Speed[_NORTH];

   

    OpticalFlow_Position_Err.x=OpticalFlow_Position.x-VIO_SINS.Pos_Backups[_EAST][VIO_Sync_Cnt];

    OpticalFlow_Position_Err.y=OpticalFlow_Position.y-VIO_SINS.Pos_Backups[_NORTH][VIO_Sync_Cnt];

OpticalFlow_Speed_Err.x=OpticalFlow_Speed.x-VIO_SINS.Vel_Backups[_EAST][VIO_Sync_Cnt];

    OpticalFlow_Speed_Err.y=OpticalFlow_Speed.y-VIO_SINS.Vel_Backups[_NORTH][VIO_Sync_Cnt];

OpticalFlow_Speed_Err.x=constrain_float(OpticalFlow_Speed_Err.x,-250,250);

OpticalFlow_Speed_Err.y=constrain_float(OpticalFlow_Speed_Err.y,-250,250);

  }

obs_err[0]=OpticalFlow_Speed_Err.x;

obs_err[1]=OpticalFlow_Speed_Err.y;

//三路反馈量修正惯导

correct[0].acc +=obs_err[0]* K_ACC_VIO*0.005f;//加速度矫正量

correct[1].acc +=obs_err[1]* K_ACC_VIO*0.005f;//加速度矫正

correct[0].acc=constrain_float(correct[0].acc,-50,50);

correct[1].acc=constrain_float(correct[1].acc,-50,50);

correct[0].vel  =obs_err[0]* K_VEL_VIO*0.005f;//速度矫正量

correct[1].vel  =obs_err[1]* K_VEL_VIO*0.005f;//速度矫正量

correct[0].pos  =obs_err[0]* K_POS_VIO*0.005f;//位置矫正量

correct[1].pos  =obs_err[1]* K_POS_VIO*0.005f;//位置矫正量

acc.x=-Origion_NamelessQuad._Acceleration[_EAST];//惯导加速度沿载体横滚,机头左侧为正

acc.y= Origion_NamelessQuad._Acceleration[_NORTH];//惯导加速度沿载体机头,机头前向为正

  VIO_SINS.Acceleration[_EAST] = acc.x+correct[0].acc;//惯导加速度沿载体横滚,机头左侧为正

  VIO_SINS.Acceleration[_NORTH]= acc.y+correct[1].acc;//惯导加速度沿载体机头,机头前向为正

  

speed_delta.x=(VIO_SINS.Acceleration[_EAST])*0.005f;

  speed_delta.y=(VIO_SINS.Acceleration[_NORTH])*0.005f; 

VIO_SINS.Position[_EAST]+=VIO_SINS.Speed[_EAST]*0.005f+0.5f*speed_delta.x*0.005f+pos.x+correct[0].pos;

VIO_SINS.Position[_NORTH] +=VIO_SINS.Speed[_NORTH] *0.005f+0.5f*speed_delta.y*0.005f+pos.y+correct[1].pos;

VIO_SINS.Speed[_EAST]+=speed_delta.x+correct[0].vel;

VIO_SINS.Speed[_NORTH] +=speed_delta.y+correct[1].vel;

for(uint16_t i=Num-1;i>0;i--)

{

VIO_SINS.Pos_Backups[_NORTH][i]=VIO_SINS.Pos_Backups[_NORTH][i-1];

VIO_SINS.Pos_Backups[_EAST][i]=VIO_SINS.Pos_Backups[_EAST][i-1];

VIO_SINS.Vel_Backups[_NORTH][i]=VIO_SINS.Vel_Backups[_NORTH][i-1];

VIO_SINS.Vel_Backups[_EAST][i]=VIO_SINS.Vel_Backups[_EAST][i-1];

}   

VIO_SINS.Pos_Backups[_NORTH][0]=VIO_SINS.Position[_NORTH];

  VIO_SINS.Pos_Backups[_EAST][0]=VIO_SINS.Position[_EAST]; 

  VIO_SINS.Vel_Backups[_NORTH][0]=VIO_SINS.Speed[_NORTH];

  VIO_SINS.Vel_Backups[_EAST][0]=VIO_SINS.Speed[_EAST];

from_vio_to_body_frame(VIO_SINS.Position[_EAST],VIO_SINS.Position[_NORTH],

  &OpticalFlow_SINS.Position[_EAST],&OpticalFlow_SINS.Position[_NORTH],

current_state.rpy[2]);

from_vio_to_body_frame(VIO_SINS.Speed[_EAST],VIO_SINS.Speed[_NORTH],

  &OpticalFlow_SINS.Speed[_EAST],&OpticalFlow_SINS.Speed[_NORTH],

current_state.rpy[2]);

}

 作者:无名创新 https://www.bilibili.com/read/cv14270245?spm_id_from=333.999.0.0 出处:bilibili

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

树莓派4B+ROS+RealSense T265室内定位替代光流开源方案 的相关文章

  • ROS学习(12)使用ROS创建自定义地图

    文章目录 前言一 新建环境二 创建编译功能包三 新建 world文件四 新建world启动文件五 更新启动文件六 建图 前言 上一篇使用的是柳树车库环境 xff0c 实现完整建图工作比较复杂 xff0c 所以准备新建一个简单点的环境 xff
  • ROS学习(13)自定义机器人的ROS导航

    文章目录 前言一 创建编译功能包二 代价地图配置三 基本局部规划器配置四 创建导航包的启动文件五 运行启动文件六 为导航功能包集设置rviz七 导航仿真 前言 上一篇针对我家户型 xff0c 完成了自定义环境的建图工作 本篇主要完成对导航功
  • ROS学习(开篇)Ubuntu16.04安装ROS Kinetic详细教程

    文章目录 前言一 添加ROS软件源 xff08 sources list xff09 二 添加密钥三 更新apt功能包列表四 安装ROS五 初始化 rosdep六 将ROS环境变量添加到 bashrc文件中七 安装rosinstall等工具
  • ROS学习(14)自定义四轮小车的ROS导航

    文章目录 前言一 创建编译功能包二 代价地图配置三 基本局部规划器配置四 创建导航包的启动文件五 导航仿真六 总结 前言 本篇为自定义四轮小车的ROS导航仿真 xff0c 与前面自定义机器人导航类似 该篇源码非原创 xff0c 特此说明 x
  • ROS学习(24)plugin插件

    文章目录 前言一 工作原理二 具体实现1 创建基类2 创建plugin类3 注册插件4 编译插件的动态链接库5 将插件加入ROS6 调用插件7 运行效果 前言 ROS中的插件就是可以动态加载的扩展功能类 ROS中的pluginlib功能包提
  • ROS学习(28)Web GUI

    文章目录 前言一 rosbridge suite元功能包二 roslibjs ros2djs ros3djs功能包三 tf2 web republisher功能包四 创建web应用五 使用web浏览器控制机器人 前言 ROS Web too
  • 参看了别人写的面试讲解

    转帖 ERP顾问的面试 新的一年就要开始了 xff0c 有不少的同行估计都在想着跳槽了 今天我就把自己的当面试官的感受给大家谈谈 xff0c 也许 xff0c 从中 xff0c 你可以掌握 ERP 实施顾问面试的技巧 在来年 xff0c 当
  • ROS2学习(1)ROS2简述

    文章目录 前言一 ROS1存在的问题二 什么是ROS21 ROS2的设计目标2 ROS2的系统架构3 ROS2的关键中间件 DDS4 ROS2中的通信模型5 ROS2的编译系统 前言 虽然众多开发者对ROS1进行了很多开发建设 xff0c
  • Qt之实现自定义控件的两种方式——提升法

    文章目录 前言一 需求二 实现1 新建项目2 自定义控件类3 提升4 效果 前言 可以通过Qt设计师拖拽原生控件进行界面开发 xff0c 但有时候原生控件不能满足项目需求 此时 xff0c 就需要实现自定义控件 Qt中实现自定义控件 xff
  • Qt之实现自定义控件的两种方式——插件法

    文章目录 前言一 需求二 实现1 新建项目2 自定义控件类3 编译插件4 拖拽使用 xff08 1 xff09 在designer exe中直接拖拽 xff08 2 xff09 在Qt Creator的设计师中直接拖拽 5 在项目中正常使用
  • Qt自定义控件——动态圆形进度条

    文章目录 前言一 需求二 实现1 自定义控件类2 提升3 效果 前言 本篇通过提升法实现一个动态圆形进度条 一 需求 自定义实现一个动态圆形进度条 xff0c 支持设置进度条颜色 目标值背景色 外边框背景色 中央圆环背景色 旋转角度及大小自
  • linux下可视化git工具git-cola安装与使用(SSH方式)

    一 git cola为何物 很多小伙伴 xff0c 特别喜欢使用TortoiseGit xff0c 该软件是做什么的 xff0c 就不用多说吧 奈何 xff0c TortoiseGit只有windows版 xff0c 这让在linux上开发
  • 智能优化算法:布谷鸟搜索算法-附代码

    智能优化算法 xff1a 布谷鸟搜索算法 附代码 文章目录 智能优化算法 xff1a 布谷鸟搜索算法 附代码1 算法原理2 算法结果3 参考文献4 Matlab代码 摘要 xff1a 谷鸟搜索算法 cuckoo search cs xff0
  • 基于布谷鸟优化的BP神经网络(预测应用) - 附代码

    基于布谷鸟优化的BP神经网络 xff08 预测应用 xff09 附代码 文章目录 基于布谷鸟优化的BP神经网络 xff08 预测应用 xff09 附代码1 数据介绍3 CS优化BP神经网络3 1 BP神经网络参数设置3 2 布谷鸟算法应用
  • 基于粒子群优化的BP神经网络(分类应用) - 附代码

    基于粒子群优化的BP神经网络 xff08 分类应用 xff09 附代码 文章目录 基于粒子群优化的BP神经网络 xff08 分类应用 xff09 附代码1 鸢尾花iris数据介绍2 数据集整理3 粒子群优化BP神经网络3 1 BP神经网络参
  • Arm Keil MDK v5.30版本官宣,快来下载!

    近日 xff0c Arm很高兴地宣布发布Arm Keil MDK v5 30 此版本新增了对Cortex M55处理器和CMSIS Build的支持 xff0c 更新包括Arm Compiler 6 14 xff0c CMSIS 5 7 0
  • ubuntu下访问串口

    前言 最近准备将windows上自动瞄准的程序移植到linux xff0c 第一步准备调试一下ubuntu下的串口 在网上搜到一个串口库 xff0c 于是就拿来调用 xff0c 最后调试成功 过程如下 xff1a 过程 1 下载Serial
  • 热备笔记实验

    早上突然断电 本来笔记本的插头就忘记插了 xff0c 电池没用多久就熄火 最纳闷的是接入电源后本机数据库竟然挂掉了 xff0c 嘿嘿 xff0c 正好试一试前几天应用的热备回复 以下是我的全程 C Documents and Setting
  • Android学习之AIDL添加Service权限

    参考 Android开发艺术探索 xff0c 书中提供了两种方法 第一种方法 xff1a 在onBind中验证 在服务端的AndroidManifest添加自定义权限 lt permission android name 61 span c
  • ADRC(自抗扰控制器)技术附Matlab代码框架

    自抗扰控制器 Auto Active Disturbances Rejec ion Controller ADRC 是韩京清学者提出的 xff0c 是一种继PID控制器后的一种新型的实用的控制技术 它不是一种独立的技术 xff0c 可以理解

随机推荐