PX4学习笔记—通过串口发送自定义数据

2023-05-16

最近因为项目需要实现一个通过pixhawk串口收发自定义数据的功能。搜索发现,博客上大神们FantasyJXF、FreeApe的博文已经详细介绍了通过pixhawk串口读取自定义数据,这部分功能实现后就可以将自己开发或者px4暂不支持的传感器嵌入到px4的代码中;考虑有些传感器是触发式的需要不断向传感器发送命令数据才可以返回测试数据,这篇博文添加了通过串口发送自定义数据功能,主要介绍一下在调试过程中遇到的坑。。。

首先参考大神FantasyJXF的博文,复现了telem2串口的数据读取功能,过程很顺利。在测试串口发送代码时就相当不顺利了—_—~,

下面介绍工具,开始选择/dev/ttyS2对应的TELE2实现串口二次开发功能。经过测试TELE2的RX引脚可以正常收数据,而TX引脚不能正常发送数据,可能被其他地方调用,改用SERIAL4串口/ttyS6。

           连接硬件如图所示,连接飞控的SERIAL4端口与模块的TTL端口,SERIAL4端口从左至右的接口依次为:+5V(红色)、TX#4(绿色)、RX#4(黄色)、TX#5(棕色)、RX#5(灰色)、GND(黑色)。

下面来一一阐述遇到的坑:

1、坑1—串口配置问题

首先直接在循环里,利用write()函数通过SERIAL4串口发送数据,形式与read()函数相同。

           send_data[0]=0x08;

           send_data[1]=0x09;

           send_data[2]=0x0A;

           send_data[3]=0x0B;

           send_data[4]=0x0C;

           write(serv_uart,&send_data,5);//发送数据

           结果如下图所示。

发现存在问题,线程开启后,只发出一条数据,而后只有read后才会write数据。根据与frsky_telemetry.c文件对比,它在uart_init()函数中添加配置串口选项O_NONBLOCK。

int serial_fd = open(uart_name, O_RDWR | O_NOCTTY| O_NONBLOCK);

该选项意思是去掉阻塞等待,如不添加该选项,在进入线程主函数serv_sys_uart_thread_main()函数的while循环里,如果没有接收到数据,则read(serv_uart,&data,1);会一直处于读的状态,占用了串口所以发送不出去。添加完该选项之后,启动线程,会一直通过串口发送数据。

2、坑2—线程优先级问题

测试后发现,串口每次只会发送第一个字节,如上图,并且影响到了串口的接收,接收数据会发生错误,考虑是直接在循环里面添加的write函数,发送的频率太快。所以将数据改成用for循环一次发送一个字节。并且将整个线程通过读取系统时间设置成了10Hz。(事后证明这个方法很占用CPU时间)

测试过程中还发现了死机的情况,发现是将新的线程的优先级设置的太高了造成的,优先级设置成了SCHED_PRIORITY_MAX – 5,与看门狗是一个级别,系统会优先调用该线程,该线程还一致占用着串口的中断,会导致系统死机。采取的策略是降低新建线程的优先级,根据Firmware->src->modules->platform->px4_tasks.h文件中定义了其他进程的优先级:

#pragma once

#include <px4_tasks.h>

/*      SCHED_PRIORITY_MAX    */

#define SCHED_PRIORITY_FAST_DRIVER           SCHED_PRIORITY_MAX

#define SCHED_PRIORITY_WATCHDOG             (SCHED_PRIORITY_MAX - 5)

#define SCHED_PRIORITY_ACTUATOR_OUTPUTS     (SCHED_PRIORITY_MAX - 15)

#define SCHED_PRIORITY_ATTITUDE_CONTROL     (SCHED_PRIORITY_MAX - 25)

#define SCHED_PRIORITY_SLOW_DRIVER          (SCHED_PRIORITY_MAX - 35)

#define SCHED_PRIORITY_POSITION_CONTROL     (SCHED_PRIORITY_MAX - 40)

/*      SCHED_PRIORITY_DEFAULT    */

#define SCHED_PRIORITY_LOGGING              (SCHED_PRIORITY_DEFAULT - 10)

#define SCHED_PRIORITY_PARAMS               (SCHED_PRIORITY_DEFAULT - 15)

/*      SCHED_PRIORITY_IDLE    */

例如,GPS是SCHED_PRIORITY_SLOW_DRIVER  (SCHED_PRIORITY_MAX - 35),位置控制是SCHED_PRIORITY_POSITION_CONTROL     (SCHED_PRIORITY_MAX - 40),所以将新建的线程的优先级设置为最小,暂定为SCHED_PRIORITY_DEFAULT。再次测试串口发送正常了。

3、坑3—Pixhawk亮紫色灯,快闪

将新建线程添加到系统自启动文件中后(见下一节),Pixhawk上电一开始是正常的蓝色灯慢闪,而后转成紫色灯快闪,懵逼。。。

查找Firmware->msg->led_control.msg,里面定义了LED等是有紫色的,然后全局搜索COLOR_PURPLE,发现在Firmware->src->modules->commander->commander.cpp文件中,有如下代码:

bool overload = (cpuload_local->load > 0.80f) || (cpuload_local->ram_usage > 0.98f);

if (overload_start == 0 && overload) {

                 overload_start = hrt_absolute_time();

          } else if (!overload) {

                  overload_start = 0;

          }

         if (overload && ((hrt_absolute_time() - overload_start) > overload_warn_delay)) {

                            led_mode = led_control_s::MODE_BLINK_FAST;

                            led_color = led_control_s::COLOR_PURPLE;}

根据overload的定义发现在cpu的利用率超过0.8的时候,会将led灯设置成紫色快闪。

打开QGC终端,输入top命令,尼玛占用了50%的cpu!!!

而后观察数据收发量庞大的mavlink线程才不到5%,自己写的程序肯定是有问题的,整个c文件的代码基本上是按照px4中常用的函数写的,一般不会有什么问题,只有自己之前添加的10Hz判断是其他线程没有采用过的,抱着试试的心理将10Hz判断的代码去掉,新建线程的cpu占用率降为1.24%,pixhawk上电之后不再闪紫色的灯,不过1.24%依然比较高,后续会不断优化代码。

然后将新建线程添加到自主启动脚本文件中去。

最后附上代码。

//头文件包含
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
#include <drivers/drv_hrt.h>
#include <string.h>
#include <systemlib/err.h>
#include <systemlib/systemlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <uORB/topics/serv_sys_uart.h>
#include <uORB/topics/input_rc.h>
#include <px4_tasks.h>
#include <poll.h>
#include <px4_posix.h>
//外部声明serv_sys_uart_main主函数
__EXPORT int serv_sys_uart_main(int argc, char *argv[]);


static bool thread_should_exit = false; /*Ddemon exit flag*///定义查看进程存在标志变量
static bool thread_running = false;  /*Daemon status flag*///定义查看进程运行标志变量
static int daemon_task;//定义进程变量

//定义线程主函数
int serv_sys_uart_thread_main(int argc, char *argv[]);
//静态声明函数
static int uart_init(const char * uart_name);//串口初始化函数,形参为串口路径
static int set_uart_baudrate(const int fd, unsigned int baud);//设置串口波特率函数
static void usage(const char *reason);//进程提示函数
//设置串口波特率函数
int set_uart_baudrate(const int fd, unsigned int baud)//配置不全,仿照GPS配置尝试
{
    int speed;
    //选择波特率
    switch (baud) {
        case 9600:   speed = B9600;   break;
        case 19200:  speed = B19200;  break;
        case 38400:  speed = B38400;  break;
        case 57600:  speed = B57600;  break;
        case 115200: speed = B115200; break;
        default:
            warnx("ERR: baudrate: %d\n", baud);
            return -EINVAL;
    }
    //实例化termios结构体,命名为uart_config
    struct termios uart_config;
 
    int termios_state;
    /* fill the struct for the new configuration */
    tcgetattr(fd, &uart_config);// 获取终端参数
    /* clear ONLCR flag (which appends a CR for every LF) */
    uart_config.c_oflag &= ~ONLCR;// 将NL转换成CR(回车)-NL后输出。
    /* no parity, one stop bit */
    uart_config.c_cflag &= ~(CSTOPB | PARENB);
    /* set baud rate */
    if ((termios_state = cfsetispeed(&uart_config, speed)) < 0) {
        warnx("ERR: %d (cfsetispeed)\n", termios_state);
        return false;
    }

    if ((termios_state = cfsetospeed(&uart_config, speed)) < 0) {
        warnx("ERR: %d (cfsetospeed)\n", termios_state);
        return false;
    }
    // 设置与终端相关的参数,TCSANOW 立即改变参数
    if ((termios_state = tcsetattr(fd, TCSANOW, &uart_config)) < 0) {
        warnx("ERR: %d (tcsetattr)\n", termios_state);
        return false;
    }

    return true;
}

//串口初始化函数,传入形参为"/dev/ttyS2"
int uart_init(const char * uart_name)
{
    int serial_fd = open(uart_name, O_RDWR | O_NOCTTY| O_NONBLOCK);//调用Nuttx系统的open函数,形参为串口文件配置模式,可读写,
    /*Linux中,万物皆文件,打开串口设备和打开普通文件一样,使用的是open()系统调用*/
    // 选项 O_NOCTTY 表示不能把本串口当成控制终端,否则用户的键盘输入信息将影响程序的执行
    if (serial_fd < 0) {
        err(1, "failed to open port: %s", uart_name);
        return false;
    }
    return serial_fd;
}
//进程提示函数,用来提示可输入的操作
static void usage(const char *reason)
{
    if (reason) {
        fprintf(stderr, "%s\n", reason);
    }

    fprintf(stderr, "usage: serv_sys_uart {start|stop|status} [param]\n\n");
    exit(1);
}
//主函数入口
int serv_sys_uart_main(int argc, char *argv[])
{
    if (argc < 2) {
        usage("missing command");
    }
    //输入为start
    if (!strcmp(argv[1], "start")) {
        if (thread_running) {//进程在运行
            warnx("already running\n");//打印提示已经在运行
            return 0;//跳出代码
        }
        //如果是第一次运行
        thread_should_exit = false;
        //建立名为serv_sys_uart进程SCHED_PRIORITY_MAX - 55,
        daemon_task = px4_task_spawn_cmd("serv_sys_uart",
                         SCHED_DEFAULT,
                         SCHED_PRIORITY_DEFAULT,
                         1000,
                         serv_sys_uart_thread_main,
                         (argv) ? (char * const *)&argv[2] : (char * const *)NULL);//正常命令形式为serv_sys_uart start /dev/ttyS2
        return 0;//跳出代码
    }
    //如果是stop
    if (!strcmp(argv[1], "stop")) {
        thread_should_exit = true;//进程标志变量置true
        return 0;
    }
    //如果是status
    if (!strcmp(argv[1], "status")) {
        if (thread_running) {
            warnx("running");
            return 0;

        } else {
            warnx("stopped");
            return 1;
        }

        return 0;
    }
    //若果是其他,则打印不支持该类型
    usage("unrecognized command");
    return 1;
}

int serv_sys_uart_thread_main(int argc, char *argv[])
{
    //正常命令形式为serv_sys_uart start /dev/ttyS2 
    if (argc < 2) {
        errx(1, "need a serial port name as argument");
        usage("eg:");
    }
    /*将/dev/ttyS2赋值给argv[1],进而赋值给uart_name*/
    const char *uart_name = argv[1];
    warnx("opening port %s", uart_name);
    
    /*
     * TELEM1 : /dev/ttyS1
     * TELEM2 : /dev/ttyS2
     * GPS    : /dev/ttyS3
     * NSH    : /dev/ttyS5
     * SERIAL4: /dev/ttyS6
     * N/A    : /dev/ttyS4
     * IO DEBUG (RX only):/dev/ttyS0
     */

    /*配置串口*/
    int serv_uart = uart_init(uart_name);//初始化串口路径-
    if(false == serv_uart)return -1;
    if(false == set_uart_baudrate(serv_uart,57600)){//设置串口波特率为57600
        printf("set_uart_baudrate is failed\n");
        return -1;
    }
    printf("uart init is successful\n");

    /*进程标志变量*/
    thread_running = true;//进程正在运行

    /*初始化数据结构体 */
    struct serv_sys_uart_s servdata;//实例化serv_sys_uart变量,该变量是自己定义的变量
    memset(&servdata, 0, sizeof(servdata));//初始化servdata变量

    /* 公告主题 */
    orb_advert_t serv_uart_pub = orb_advertise(ORB_ID(serv_sys_uart), &servdata);

    /*定义接收话题变量*/
    uint8_t state;
    uint8_t data;
    uint8_t buffer[8];//串口接收缓冲数组
    int already_send1=0;
    int already_send2=0;
    int already_send3=0;
    bool updated = false;
    int rc_sub_fd = orb_subscribe(ORB_ID(input_rc));//订阅input_rc消息
    struct input_rc_s rc_botton;                    //实例化遥控器通道变量
    memset(&rc_botton, 0, sizeof(rc_botton));       //初始化遥控器通道变量

    /*更新计时器变量*/
    //static uint64_t last_time = 0;
    //static uint64_t cur_time = 0;
    //last_time=hrt_absolute_time();//先更新一下时间戳

    /*定义串口事件阻塞结构体及变量*/
    px4_pollfd_struct_t fds[] = {
    	{ .fd = serv_uart,   .events = POLLIN },
    };
    int error_counter = 0;

    while(!thread_should_exit){

    	//cur_time=hrt_absolute_time();//更新事件,事实证明这么做不可以,占用了CPU50%的利用率
    	//if((cur_time-last_time)<100000) continue;//时间少于100000微秒,即0.1s
    	orb_check(rc_sub_fd, &updated);

    	/*先订阅遥控器的值,加入遥控器拨杆变化判断*/
    	if (updated) {
    		orb_copy(ORB_ID(input_rc), rc_sub_fd, &rc_botton);
    		/*
    		PX4_INFO("rc_botton=:\t%d\t%d\t%d\n",
    		    				rc_botton.values[2],
    							rc_botton.values[6],
    							rc_botton.values[7]);
    		*/
    		/*根据遥控器的值发送协议*/
    		//rc_botton.values[7]控制运服对接,下位-1094-nothing、上位-1934-输入运服对接0x10
    		//rc_botton.values[8]控制放置回收,下位-1094-放置命令0x11、中位-1514-nothing、上位-1934-回收命令0x21
    		uint8_t send_data[8];//定义数据发送数组
    		send_data[0]=0x01;
    		send_data[1]=0x00;
    		send_data[2]=0x01;
    		send_data[3]=0x00;
    		send_data[4]=0x00;
    		send_data[5]=0x00;
    		send_data[6]=0x00;
    		if(rc_botton.values[7]<1500)//放置命令,同时启动服务系统
    		{
    		    send_data[7]=0x12;//启动服务系统
    		    send_data[7]=0x11;//开始放置
    		    if(already_send1<5)
    		    {
    		    	for(int i=0;i<8;i++)
    		    	{
    		    		write(serv_uart,&send_data[i],1);//一个字节一个字节发送
    		    	}
    		    	already_send1++;//发送五次
    		    }
    		}
    		else if(rc_botton.values[7]<1700)
    		{
    		    //do nothing
    		    already_send1=0;
    		    already_send2=0;
    		}
    		else
    		{
    		    send_data[7]=0x21;//开始回收
    		    if(already_send2<5)
    		    {
    		    	for(int i=0;i<8;i++)
    		    	{
    		    		write(serv_uart,&send_data[i],1);//一个字节一个字节发送
    		    	}
    		    	already_send2++;
    		    }
    		}

    		if(rc_botton.values[6]>1500)//运服对接
    		{
    		    send_data[7]=0x10;//运服对接
    		    if(already_send3<5)
    		    {
    		    	for(int i=0;i<8;i++)
    		    	{
    		    		 write(serv_uart,&send_data[i],1);//一个字节一个字节发送
    		    	}
    		    	already_send3++;
    		    }

    		 }
    		 else
    		 {
    		    already_send3=0;
    		 }
    	}

    	int poll_ret = poll(fds,1,10);//阻塞等待10ms
    	if (poll_ret == 0)
    	{
    		/* this means none of our providers is giving us data */
    	    printf("No receive data for 10ms\n");
    	} else if (poll_ret < 0)
    	{
    	   /* this is seriously bad - should be an emergency */
    	   if (error_counter < 10 || error_counter % 50 == 0)
    	   {
    		   /* use a counter to prevent flooding (and slowing us down) */
    		   printf("ERROR return value from poll(): %d\n", poll_ret);
    	   }
    	       error_counter++;
    	}
    	else
    	{
    	   if (fds[0].revents & POLLIN)
    	   {
    		   /*接收服务系统发过来的消息*/
    		   read(serv_uart,&data,1);//读取串口数据
    		   if(data == 0x01)
    		   {//找到帧头0x01
    			   buffer[0] = 0x01;
    			   for(int i = 1;i <8;i++)
    			   {
    				   read(serv_uart,&data,1);//读取后面的数据
    				   buffer[i] = data;
    				   //printf("buffer=%d\n",buffer[i]);//将消息打印出来
    		       }
    		   }
        	   for(int j=0;j<8;j++)
        	   {
        		   servdata.datastr[j]=buffer[j];
        	   }
        	   state = buffer[7];
        	   servdata.data=state;
        	   //strncpy(servdata.datastr,buffer,8);// 复制字符串Buffer中前4个数字到Datastr中
        	   //servdata.data = atoi(servdata.datastr);//将字符串转换成整形数据
        	   printf("servdata.data=%d\n",servdata.data);//将消息打印出来
        	   orb_publish(ORB_ID(serv_sys_uart), serv_uart_pub, &servdata);//发布话题
    	   }
    	}
    	//last_time = hrt_absolute_time();
    }
    //如果标志位置flase应该退出进程
    warnx("exiting");
    thread_running = false;
    close(serv_uart);

    fflush(stdout);
    return 0;
}

 

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

PX4学习笔记—通过串口发送自定义数据 的相关文章

  • tty_read和tty_write

    一 tty read 对于tty read这个函数 xff0c 很多标志我也没有弄得太清楚 xff0c 但是问题不大 xff0c 以后有机会在看 我觉得重点是看数据怎么从cdc驱动到通过线路规划到tty xff0c 再从tty到用户空间 标
  • 深度学习 - 模型调优经历(1)

    模型调优经历 xff08 1 xff09 背景遇到问题思路解决办法 背景 样本规模及划分 bullet 二分类问题 xff0c 正负样本 1 1 xff0c 特征数 xff1a 20
  • Android SDK下载安装及配置教程

    让大家很方便的不用翻墙不用代理地就完成Android开发环境的搭建 总结起来 xff0c Android开发环境搭建可以分为以下四步 xff1a 第一步 安装JDK xff1b 略 第二步 安装Eclipse xff1b 略 第三步 下载并
  • (DFS)深度优先搜索算法详解

    背景 DFS 英文全称为 xff08 Depth First Search xff09 xff0c 中文简称深度优先搜索算法 xff0c 其过程为沿着每一个可能的路径向下进行搜索 xff0c 直到不能再深入为止 xff0c 并且每一个节点只
  • ovs-ofctl

    文章目录 64 toc ovs ofctl语法COMMANDSOpenFlow Switch Management Commands OpenFlow Switch Flow Table CommandsGroup Table Comman
  • 【牛客网华为机试】HJ46 截取字符串

    题目 描述 输入一个字符串和一个整数k xff0c 截取字符串的前k个字符并输出 本题输入含有多组数据 输入描述 xff1a 1 输入待截取的字符串 2 输入一个正整数k xff0c 代表截取的长度 输出描述 xff1a 截取后的字符串 示
  • 【牛客网华为机试】HJ50 四则运算

    题目 描述 输入一个表达式 xff08 用字符串表示 xff09 xff0c 求这个表达式的值 保证字符串中的有效字符包括 0 9 43 xff0c 且表达式一定合法 输入描述 xff1a 输入一个算术表达式 输出描述 xff1a 得到计算
  • 【机器学习实战 Task1】 (KNN)k近邻算法的应用

    1 背景 1 1 k近邻算法的概述 xff08 1 xff09 k近邻算法的简介 k 近邻算法是属于一个非常有效且易于掌握的机器学习算法 xff0c 简单的说就是采用测量不同特征值之间距离的方法对数据进行分类的一个算法 xff08 2 xf
  • 【Python量化分析100例】Day1-使用Tushare获取数据

    1 背景 Tushare平台是目前使用python学习量化投资比较好用的而且是免费的一个数据获取平台 主要实现对金融数据从数据采集 清洗加工 到 数据存储的过程 xff0c 能够为金融分析人员提供快速 整洁 和多样的便于分析的数据 xff0
  • python报错:TypeError: Cannot interpret ‘<attribute ‘dtype‘ of ‘numpy.generic‘objects>‘as a data type

    原因 xff1a pandas和matplotlib版本不匹配 方案1 conda更新一下所有包 conda update n base conda 方案2 pip 更新最新版pandas pip install pandas upgrad
  • 【阿里云天池算法挑战赛】零基础入门NLP - 新闻文本分类-Day2-数据读取与数据分析

    一 赛题解析 阿里云天池算法挑战赛 零基础入门NLP 新闻文本分类 Day1 赛题理解 202xxx的博客 CSDN博客 二 数据读取 下载完成数据后推荐使用anaconda xff0c python3 8进行数据读取与模型训练 首先安装需
  • 【阿里云天池算法挑战赛】零基础入门NLP - 新闻文本分类-Day3-基于机器学习的文本分类

    一 赛题解析 阿里云天池算法挑战赛 零基础入门NLP 新闻文本分类 Day1 赛题理解 202xxx的博客 CSDN博客 二 数据读取与数据分析 阿里云天池算法挑战赛 零基础入门NLP 新闻文本分类 Day2 数据读取与数据分析 202xx
  • 【清华大学】2021元宇宙研究报告

    关于元宇宙的详细介绍 xff1b 来源 xff1a 软件定义世界 xff08 SDX xff09
  • MAC OS M1 安装MySQL

    xff08 1 xff09 进入mysql官网下载mysql http www mysql com downloads xff08 2 xff09 选择对应下载版本 xff08 3 xff09 选择直接下载 xff08 4 xff09 下载
  • PX4开源飞控位置控制解析

    位置控制的总体思路为串级PID控制算法 xff0c 内环为对速度的PID控制 xff0c 外环为对位置的比例控制 xff0c 被控对象为四旋翼无人机 xff0c 被控量为四旋翼无人机输出的推力矢量和 xff0c 将测量到的位置与速度进行反馈
  • ONOS意图框架

    1 意图基本概念 Intent是用于描述应用需求的不可变模型对象 xff0c ONOS核心根据其改变网络行为 在最低级别上 xff0c 可以用以下方式描述意图 即意图的组成 xff1a 1 Network Resource xff1a 一组
  • prometheus-4种metric类型说明

    前提了解 prometheus中存储的数据都是时序型 xff0c 其数据模型都是如下 xff1a metric name label 61 value value timestamp 下文中说的数据类型只是客户端的封装 prometheus
  • ROS2 中常用坐标系

    ROS2 中常用坐标系 frame id xff1a 用来告诉你 xff0c 发布的数据是来自哪一个坐标系的 在使用ROS进行定位导航等操作时 xff0c 我们经常会遇到各种坐标系 每种坐标系都有明确的含义 理论上坐标系的名称可以是随意的
  • 国密SM2算法

    目录 1 前言 2 基础参数 3 密钥对生成 4 签名算法 4 1 预处理1 4 2 预处理2 4 3 生成签名 4 4 签名验证 4 5 签名验证原理 5 参考资料 1 前言 比原链的智能合约支持国密算法的函数 SM2是国密标准的椭圆曲线
  • STM32——ARM与STM32之间的联系

    ARM与STM32之间的联系 stm32是基于ARM内核的一种控制器 xff0c 是包含与被包含的关系 ARM xff08 STM32 xff09

随机推荐

  • VTK坐标转换

    VTK坐标转换
  • 软件工程师校招面试救急包

    LeetCode牛人总结 xff08 手撕代码前看看 xff0c 抱佛脚 xff09 https github com labuladong fucking algorithm blob master README md 剑指offer x
  • unix环境高级编程——UNIX体系架构

    本期主题 xff1a unix环境高级编程 UNIX体系架构 文件IO 0 初始UNIX1 系统调用2 库函数2 1 C语言的运行库 3 shell 0 初始UNIX 这里略过unix的历史不讲 xff0c 网上有比较详细的资料 我们可以将
  • CVPR2019:无监督深度追踪

    本文提出了一种无监督的视觉跟踪方法 与使用大量带注释数据进行监督学习的现有方法不同 xff0c 本文的CNN模型是在无监督的大规模无标签视频上进行训练的 动机是 xff0c 强大的跟踪器在向前和向后预测中均应有效 xff08 即 xff0c
  • 各种智能优化算法比较与实现(matlab版)

    各种智能优化算法比较与实现 xff08 matlab版 xff09 一 方法介绍 1免疫算法 xff08 Immune Algorithm xff0c IA xff09 1 1算法基本思想 免疫算法是受生物免疫系统的启发而推出的一种新型的智
  • 我与人工智能的故事

    本文作者 xff1a 诸葛越 前 言 人工智能的三次浪潮 2018年年初 xff0c 招聘季正如火如荼地进行 xff0c 而 数据科学家 和 算法工程师 绝对算得上热门职业 人工智能 机器学习 深度学习 建模 卷积神经网络 等关键词 xff
  • ovn-architecture

    参考 文章目录 1 Name2 Description2 1 Information Flow in OVN OVN中的信息流向 2 2 Chassis Setup2 3 Logical Networks2 4 Life Cycle of
  • IDEA创建maven项目添加jar包依赖出错

    Problem1 xff1a 由于网络原因无法下载jar包 解决方法 xff1a 在maven的settings xml文件的 lt mirrors gt 标签中配置阿里镜像 lt mirror gt lt id gt nexus aliy
  • 判断一个字符串是否为回文字符串

    题目 输入一个字符串 xff0c 判断该字符串中除去空格之后的字符串是否为回文字符串 要求 xff1a 不可使用 Java 已实现的方法替换空格 xff0c 不可消耗额外的空间 代码实现 此处为判断方法的实现 public static b
  • Spring中的 JdbcTemplate和声明式事务控制

    Spring中的 JdbcTemplate和声明式事务控制 JdbcTemplate概述 JdbcTemplate的作用 xff1a 他就是用于和数据库交互的 xff0c 实现CRUD操作 如何创建该对象 在dao的实现类中定义并用set方
  • SpringMVC(一)

    SpringMVC xff08 一 xff09 SpringMVC的基本概念 三层架构 表现层业务层持久层 MVC模型 Model xff08 模型 xff09 xff1a 通常就是指我们的数据模型 xff0c 一般情况下用于封装数据 Vi
  • SpringMVC(二)

    SpringMVC xff08 二 xff09 响应数据和结果视图 返回值分类 xff1a 字符串voidModelAndView 对象 xff1a 是 spring 提供的一个对象 xff0c 可以用来调整具体的 JSP 视图 span
  • SpringMvc(三)

    SpringMvc xff08 三 xff09 SSM 整合可以使用多种方式 xff0c 一般会选择 XML 43 注解 的方式 整合的思路 xff1a 搭建整合环境先把spring 的配置搭建完成再使用 spring 整合SpringMV
  • 工厂方法模式(Factory Method)--多态工厂的实现

    工厂方法模式 xff08 Factory Method xff09 多态工厂的实现 定义 xff1a 定义一个用于创建对象的接口 xff0c 让子类决定实例化哪一个类 xff0c 工厂方法使一个类的实例化延迟到其子类 类图 xff1a 外链
  • 无人机自主定位导航避障VINS+fast_planner实测~

    厦大研一研究的一个项目 xff0c 将项目开发用到的技术和难点在这记录一下 常更新 xff0c 先把框架写好 xff0c 有空的时候就过来更新 xff0c 要是有漏的或者有错误的地方 xff0c 请大佬指点 因为采用的是TX2 xff0c
  • rs_D455相机内外参标定+imu联合标定

    IMU标定 lt launch gt lt node pkg 61 34 imu utils 34 type 61 34 imu an 34 name 61 34 imu an 34 output 61 34 screen 34 gt lt
  • GVINS论文简明解读

    VIN与GNSS融合的必要性 VIN系统只工作在局部坐标系下 x y z yaw不可观 里程计存在不可避免的漂移 而GNSS系统可提供无漂移的全局定位 VIN与GNSS融合的难点 不同于cmaera与imu此类的外参标定 GNSS坐标与VI
  • onos2.5.2编译安装

    onos编译安装 Ubuntu18 04 1 前置下载安装 1 1 前置包安装 参考docker file sudo apt get install y ca certificates zip python python3 git bzip
  • C++和C的区别(汇总)

    1 C是面向过程的语言 xff0c 而C 43 43 是面向对象的语言 2 C和C 43 43 动态管理内存的方法不一样 xff0c C是使用malloc free函数 xff0c 而C 43 43 除此之外还有new delete关键字
  • PX4学习笔记—通过串口发送自定义数据

    最近因为项目需要实现一个通过pixhawk串口收发自定义数据的功能 搜索发现 xff0c 博客上大神们FantasyJXF FreeApe的博文已经详细介绍了通过pixhawk串口读取自定义数据 xff0c 这部分功能实现后就可以将自己开发