FreeRTOS学习记录

2023-05-16

FreeRTOS学习记录

  • 前言
  • FreeRTOS学习记录
  • 在STM32CubeMX中配置FreeRTOS

前言

本人小白,最近学习了FreeRTOS操作系统,打算做一点记录。
学习的过程中虽然做了点练习,不过都是跟着例程来的,大部分没什么记录必要,本文更多的是零零散散地记录我在学习过程中的一些疑惑与个人见解,可能会有错误还请指出。
这只是一个初学者的简单学习记录,并没有全面系统的知识介绍,学习的话还是要看对应的教程啦。

使用到的工具及版本:
FreeRTOS:V9.0.0

STM32CubeMX版本:6.3.0
HAL库:STM32CubeF4 Firmware Package V1.26.2
MDK-ARM:V5.32.0.0
开发板:野火的霸天虎开发板V2(主控芯片是STM32F407ZGT6)

参考的资料:
野火的《FreeRTOS内核实现与应用开发实战》
FreeRTOS入门手册_中文
FreeRTOS官网提供的介绍。

FreeRTOS学习记录

本文对port部分(移植层面)源码的探究查看的是FreeRTOSv9.0.0\FreeRTOS\Source\portable\RVDS\ARM_CM4_MPU,这是我所使用的开发工具和硬件决定的。其他工具或者硬件上的实现可能不一样。

任务会在什么情况下切换?
1、 我们自己编写的程序所引起的任务切换。比如我们自己调用taskYIELD(),或者我们调用的API函数里面包含了任务切换(这种时候往往是当前任务进入阻塞/挂起,又或者是有更高优先级的任务加入了就绪列表,API函数里面会在需要的时候去调用任务切换)。
2、 tick中断里面会触发任务切换。tick由内核的Systick产生,属于内核的定时器/计数器(其设计的本意可能就是供操作系统使用的,为操作系统提供时间度量,我猜的)。
注意: 抢占式调度上面两种情况都存在。协作式调度不存在第2种情况的切换(tick中断的切换),协作式调度中所有的切换都是“显式的”。
显而易见协作式调度比抢占式调度有着更高的CPU效率,毕竟不需要每个tick中断就跑去看看是不是要切换任务。但是它存在着高优先级中断可能得不到快速响应的风险,这取决于我们开发者的程序设计,得看我们是不是在合适的时机调用了任务切换,如果程序结构复杂的话我们可能得时时刻刻考虑是不是该在什么地方进行一次任务切换,这可太麻烦了,有的时候甚至不现实。
通过FreeRTOSConfig.h里面的configUSE_PREEMPTION(0是协作式调度,非0是抢占式调度)决定调度类型。
tick中断源码与任务切换源码
系统tick依赖于Cotex-M4的SysTick硬件中断资源,任务切换依赖于PendSV硬件中断资源(注:下图的SysTick及之前的中断是属于内核的,后面的是芯片厂商的)
在这里插入图片描述
来看看SysTick_Handler(systick中断函数)。

void SysTick_Handler(void)
{	
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
      if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
      {
    #endif  /* INCLUDE_xTaskGetSchedulerState */  
        xPortSysTickHandler();
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
      }
    #endif  /* INCLUDE_xTaskGetSchedulerState */
}

如果调度器此时压根还没开启,或者调用了vTaskEndScheduler( void ),那么这里的xPortSysTickHandler()并不会执行,系统节拍则不会增加(当然前提是宏INCLUDE_xTaskGetSchedulerState定义为1)。调度器如果挂起,系统时间依然会增加。
接下来看看xPortSysTickHandler()里面是啥。

void xPortSysTickHandler( void )
{
	/* The SysTick runs at the lowest interrupt priority, so when this interrupt
	executes all interrupts must be unmasked.  There is therefore no need to
	save and then restore the interrupt mask value as its value is already
	known - therefore the slightly faster vPortRaiseBASEPRI() function is used
	in place of portSET_INTERRUPT_MASK_FROM_ISR(). */
	vPortRaiseBASEPRI();
	{
		/* Increment the RTOS tick. */
		if( xTaskIncrementTick() != pdFALSE )
		{
			/* A context switch is required.  Context switching is performed in
			the PendSV interrupt.  Pend the PendSV interrupt. */
			portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
		}
	}
	vPortClearBASEPRIFromISR();
}

首先调用了vPortRaiseBASEPRI()把中断屏蔽,它的实现利用了Cotex-M4内核的BASEPRI register(这张图是从《STM32F4xx-Cortex_-M4内核参考手册》截的)。
在这里插入图片描述
然后调用的xTaskIncrementTick() 则是实现了:
1、系统tick加1(无论调度器是否挂起)
2、如果tick溢出,把延时列表和延时溢出列表交换
3、处理延时列表的事宜
4、如果是抢占式调度,会返回pdTRUE,这样接下来就会把PendSV中断标志位置位,进入PendSV中断服务完成任务切换。如果是协作式调度则返回pdFALSE,不会置位PendSV中断标志。

接下来看看PendSV_Handler(PendSV中断函数,用于任务切换)。
在这里插入图片描述
在这里插入图片描述
有关R14与R15(PC)寄存器的描述(我在网上找的)

R14称为子程序链接寄存器LR(Link Register),当执行子程序调用指令(BL)时,R14可得到R15(程序计数器PC)的备份。在每一种运行模式下,都可用R14保存子程序的返回地址,当用BL或BLX指令调用子程序时,将PC的当前值复制给R14,执行完子程序后,又将R14的值复制回PC,即可完成子程序的调用返回。

寄存器R15用作程序计数器(PC),在ARM状态下,位[1:0]为0,位[31:2]用于保存PC,在Thumb状态下,位[0]为0,位[31:1]用于保存PC。由于ARM体系结构采用了多级流水线技术,对于ARM指令集而言,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节程序状态寄存器。

一开始我只找了R14的描述,然后觉得很奇怪,上图中的程序怎么会跳到R14(PC的内容)所指的地址呢,不应该是PC+1吗(我只了解一点51内核,cortex-M内核还没怎么了解,以后有时间得看看它的内容),所以才查了PC寄存器的内容。
阅读这些汇编代码需要对照ARM与Thumb指令集说明(除非特殊需要,不然应该没什么人会去背这个吧)。可以在keil提供的“帮助”窗口查阅。
在这里插入图片描述
在这里插入图片描述
任务优先级与中断优先级
中断优先级用于硬件中断管理,属于微处理器内核的内容。cortex-M4的中断优先级数字越大优先级越低。
任务优先级用于调度器的任务管理,属于操作系统的内容。FreeRTOS中任务优先级数字越大优先级越高。
vTaskDelay相对延时与vTaskDelayUntil绝对延时
我试着写了一段代码来进行说明

void Task_1( void* parameter )
{
	/* 用于保存上次时间。调用后自动更新 */
	static portTickType PreviousWakeTime;
	...
	PreviousWakeTime = xTaskGetTickCount();	
	for( ;; )
	{
		...				/*假设此处可能切换成了更高优先级的任务并去执行,
						并假设执行该任务要花费5个tick才会把CPU释放给Task_1*/
		vTaskDelay(50)		or		vTaskDelayUntil(&PreviousWakeTime,50)	
	}	
}

我画了个非常潦草的图来说明Task_1的运行情况(这里假设Task_1处于运行状态的时间非常短,没有画出来)
在这里插入图片描述
可以看到用相对延时的话任务每次被唤醒的时间间隔可能是55个tick,也可能是50个tick,绝对延时则会让任务每次进入就绪的时间是确定的。
关于消息队列、信号量与互斥量
用于进程间通信或同步的手段。信号量与互斥量的创建利用了消息队列的数据结构。它们可以实现任务间的通信,本质上就是函数利用全局变量来对其他函数产生影响(进行通信)。它们可以让等待它们的任务进入阻塞状态。
事件位
相比起消息队列,它的结构更加简单。不能传递值,只传递事件标志。
任务通知
相比起上述的时间和消息队列,它更更简单,不需要创建该对象,也就不需要额外花费RAM空间,因为它是在任务控制块(TCB)里定义了uint32_t类型的变量(用来传递值)和uint8_t类型的变量(用来传递状态)来实现的,它的功能函数的实现也更加简单。(FreeRTOS V8.2.0 才开始支持的)
内存管理方案
heap_1.c:最简单的,只能申请内存,不能进行内存释放,申请内存的时间是一个常量。
heap_2.c:可删除内存。采用了一种最佳匹配算法,但是会产生内存碎片。
heap_3.c:简单地封装了标准 C 库中的 malloc()和 free()函数。此时FreeRTOSConfig.h中的configTOTAL_HEAP_SIZE 宏定义不起作用,使用启动文件里划分的堆空间。
heap_4.c:在heap_2.c的基础上多了合并相邻内存空间的功能。
heap_5.c:在heap_4.c的基础上把外扩RAM也纳入分配空间。
关于“stdint.readme”文件
在C语言的发展过程中会添加新的标准,所以会有C89、C99、C11标准。不同的编译器对标准的支持程度不一样,有的会支持新出的标准而有的则不会。FreeRTOS希望在不同的编译器下都可以编译,所以它没有用C99及C99之后的内容,除了C99引进的stdint.h。这个文件定义了一些整数类型和宏。
如果编译器不提供stdint.h的话,就把FreeRTOS/Source/include路径下的stdint.readme改成stdint.h并放到工程指定的头文件路径下吧。
关于协程
和任务(task)相似的东西,但是对RAM的要求很低,是为存储非常小的情况设计的,但是使用起来有更多的限制,现在用的很少,FreeRTOS官方虽然没有删除协程,但并不再打算更新这部分内容。
关于互斥量的优先级继承机制
一个用来减轻优先级反转危害的措施。当更高优先级的任务(A)要获取一个被低优先级任务(B)占用的互斥量时,A不可避免的要等待B,如果B的优先级临时提高到与A一样,可以避免优先级介于两者的任务这时候掺一脚(假设有任务C,优先级顺序A>C>B,没有优先级继承的话C可能会抢占B,导致A又要等B又要等C执行)。如果不想出现优先级反转,要硬实时之类的,应该是在一开始的设计阶段就要考虑。

在STM32CubeMX中配置FreeRTOS

原本我是计划学习μC/OS的,因为查学习路径的时候网上都推荐μC/OS,不过在使用STM32CubeMX的时候发现它提供了FreeRTOS中间件并可以快速配置,所以选择了先学习FreeRTOS。
STM32CubeMX中FreeRTOS的配置界面。
在这里插入图片描述
CMSIS是什么
CMSIS是ARM和一众厂商一起决定的 Cortex-M 处理器系列的通用接口,相当于大家围在一起制定了标准并提供了各种外设函数、实时操作系统和中间设备等在该标准下的通用接口的实现,使用通用接口的话,应用程序可以更简单地在不同厂商的Cortex-M处理器之间反复横跳(移植更方便),V2表示版本2。
版本选择不了,STM32CubeMX里面好像只能用新版本的FreeRTOS。
点击选项可以看见参数说明等。
在这里插入图片描述
创建任务
任务、队列等直接在STM32CubeMX里面就可以创建好,不必在编辑器里面写。
STM32CubeMX默认创建了一个defaultTask,这是一个啥都不做的任务,每次执行就阻塞1个tick。
我创建了两个任务
在这里插入图片描述
在这里插入图片描述
关于优先级
单从配置的名字看不出具体的优先级数字,只能看出优先级先后。我在cmsis_os2.h里面找到它的定义。

/// Priority values.
typedef enum {
  osPriorityNone          =  0,         ///< No priority (not initialized).
  osPriorityIdle          =  1,         ///< Reserved for Idle thread.
  osPriorityLow           =  8,         ///< Priority: low
  osPriorityLow1          =  8+1,       ///< Priority: low + 1
  osPriorityLow2          =  8+2,       ///< Priority: low + 2
  osPriorityLow3          =  8+3,       ///< Priority: low + 3
  osPriorityLow4          =  8+4,       ///< Priority: low + 4
  osPriorityLow5          =  8+5,       ///< Priority: low + 5
  osPriorityLow6          =  8+6,       ///< Priority: low + 6
  osPriorityLow7          =  8+7,       ///< Priority: low + 7
  osPriorityBelowNormal   = 16,         ///< Priority: below normal
  osPriorityBelowNormal1  = 16+1,       ///< Priority: below normal + 1
  osPriorityBelowNormal2  = 16+2,       ///< Priority: below normal + 2
  osPriorityBelowNormal3  = 16+3,       ///< Priority: below normal + 3
  osPriorityBelowNormal4  = 16+4,       ///< Priority: below normal + 4
  osPriorityBelowNormal5  = 16+5,       ///< Priority: below normal + 5
  osPriorityBelowNormal6  = 16+6,       ///< Priority: below normal + 6
  osPriorityBelowNormal7  = 16+7,       ///< Priority: below normal + 7
  osPriorityNormal        = 24,         ///< Priority: normal
  osPriorityNormal1       = 24+1,       ///< Priority: normal + 1
  osPriorityNormal2       = 24+2,       ///< Priority: normal + 2
  osPriorityNormal3       = 24+3,       ///< Priority: normal + 3
  osPriorityNormal4       = 24+4,       ///< Priority: normal + 4
  osPriorityNormal5       = 24+5,       ///< Priority: normal + 5
  osPriorityNormal6       = 24+6,       ///< Priority: normal + 6
  osPriorityNormal7       = 24+7,       ///< Priority: normal + 7
  osPriorityAboveNormal   = 32,         ///< Priority: above normal
  osPriorityAboveNormal1  = 32+1,       ///< Priority: above normal + 1
  osPriorityAboveNormal2  = 32+2,       ///< Priority: above normal + 2
  osPriorityAboveNormal3  = 32+3,       ///< Priority: above normal + 3
  osPriorityAboveNormal4  = 32+4,       ///< Priority: above normal + 4
  osPriorityAboveNormal5  = 32+5,       ///< Priority: above normal + 5
  osPriorityAboveNormal6  = 32+6,       ///< Priority: above normal + 6
  osPriorityAboveNormal7  = 32+7,       ///< Priority: above normal + 7
  osPriorityHigh          = 40,         ///< Priority: high
  osPriorityHigh1         = 40+1,       ///< Priority: high + 1
  osPriorityHigh2         = 40+2,       ///< Priority: high + 2
  osPriorityHigh3         = 40+3,       ///< Priority: high + 3
  osPriorityHigh4         = 40+4,       ///< Priority: high + 4
  osPriorityHigh5         = 40+5,       ///< Priority: high + 5
  osPriorityHigh6         = 40+6,       ///< Priority: high + 6
  osPriorityHigh7         = 40+7,       ///< Priority: high + 7
  osPriorityRealtime      = 48,         ///< Priority: realtime
  osPriorityRealtime1     = 48+1,       ///< Priority: realtime + 1
  osPriorityRealtime2     = 48+2,       ///< Priority: realtime + 2
  osPriorityRealtime3     = 48+3,       ///< Priority: realtime + 3
  osPriorityRealtime4     = 48+4,       ///< Priority: realtime + 4
  osPriorityRealtime5     = 48+5,       ///< Priority: realtime + 5
  osPriorityRealtime6     = 48+6,       ///< Priority: realtime + 6
  osPriorityRealtime7     = 48+7,       ///< Priority: realtime + 7
  osPriorityISR           = 56,         ///< Reserved for ISR deferred thread.
  osPriorityError         = -1,         ///< System cannot determine priority or illegal priority.
  osPriorityReserved      = 0x7FFFFFFF  ///< Prevents enum down-size compiler optimization.
} osPriority_t;

优先级个数超过32个,可见没有使用硬件优化任务查找(Cortex-M处理器提供了一个计算前导零的指令‘CLZ’可以优化优先级查找)。
在这里插入图片描述
关于Timebase Source
Timebase Source如果使用SysTick,那么在生成代码前会有这样的警告。
在这里插入图片描述
原因是使用HAL库的一些函数(比如延时)会依赖一个时钟源提供周期的节拍,这和操作系统的tick(心跳)是一样的道理,这里的Timebase Source是设定HA库函数L所依赖的时钟源,如果把时钟源设为内核的SysTick,相当于HAL库和操作系统共用一个“心脏”,如果HAL库的某个功能把“心脏”给停了那么操作系统会受到影响。
给HAL库换一个时钟源就好了,我这里用的TIM1。
在这里插入图片描述
顺便一提,HAL库用来记录节拍数的全局变量叫uwTick,FreeRTOS用来记录节拍数的全局变量叫xTickCount。
编写任务函数
创建好任务后产生代码,接下来写任务功能就好了,我这里就是简单的点灯,把freetros.c里的任务函数补充好。

/* USER CODE BEGIN Header_Task_LED_Red */
/**
  * @brief  Function implementing the TASK_LED_RED thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_Task_LED_Red */
void Task_LED_Red(void *argument)
{
  /* USER CODE BEGIN Task_LED_Red */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(LED_RED_GPIO_Port,LED_RED_Pin);
	osDelay(3000);
  }
  /* USER CODE END Task_LED_Red */
}

/* USER CODE BEGIN Header_Task_LED_Green */
/**
* @brief Function implementing the TASK_LED_GREEN thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Task_LED_Green */
void Task_LED_Green(void *argument)
{
  /* USER CODE BEGIN Task_LED_Green */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port,LED_GREEN_Pin);
	osDelay(1000);
  }
  /* USER CODE END Task_LED_Green */
}

现象
灯光颜色周期性地变化。
在这里插入图片描述

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

FreeRTOS学习记录 的相关文章

  • 关于基于标准库函数与基于HAL库函数的stm32编程方式的差异

    在之前的博客中 xff0c 我已经使用过通过标准库函数和HAL库函数对stm32进行编译工作 xff0c 在这篇博文里 xff0c 我将对之前的进行总结 关于标准库函数 由于stm32系列有着很多不同的芯片 xff0c 其所使用的寄存器也大
  • curl wget pip git-clone yum apt-get的区别

    在linux中 xff0c 会常用到这些命令进行文件下载 xff0c 软件安装以及url访问 xff0c 但总是分不清楚什么时候用什么命令去下载或者安装和访问 这里将这几个命令的用法和区别进行一个说明 xff0c 方便大家学习和记忆 1 首
  • CSS 三种样式

    本节我们要学习一下 CSS 样式的几种形式 xff0c 在实际应用中向 HTML 中引入 CSS 样式的方法有三种 xff0c 分别是行内样式 内部样式 外部样式 我们会依次学习这三种方式的优缺点以及应用场景 xff0c 本节我们先来讲一下
  • JavaFx-报错WindowsNativeRunloopThread

    问题 解决办法 需要卸载掉JDK1 8 并且将环境变量中的 34 JAVA HOME 34 指向改成JDK11的目录 点赞 收藏 关注 便于以后复习和收到最新内容 有其他问题在评论区讨论 或者私信我 收到会在第一时间回复 在本博客学习的技术
  • Gradle-JDK版本问题导致运行失败

    问题 解决办法 因为当前我们使用jdk8去运行Gradle 但是Gradle意思是必须使用11 43 的jdk版本 下面这个问题就是因为 我们默认是 改为 点赞 收藏 关注 便于以后复习和收到最新内容 有其他问题在评论区讨论 或者私信我 收
  • 权力的游戏,我是小股东,咋办?

    案例简述 xff1a 某初创业公司 xff0c 有A B两个大股东 xff0c 股份份额一样大 xff0c 另外还有一个小股东C A股东负责市场和销售 xff0c B股东负责研发和技术 xff0c B曾经是C的上司 xff0c 将C带入公司
  • Java-高版本没有jre的问题

    解决方案 jre 文件夹是可以用命令自动生成的 xff0c 在window环境中 xff0c 进入jdk目录所在的文件夹 xff0c 运行下面命令就会自动 生成jre文件夹 bin span class token punctuation
  • Java-ForkJoinPool(线程池-工作窃取算法)

    文章目录 概述工作窃取算法工作窃取算法的优缺点使用 ForkJoinPool 进行分叉和合并ForkJoinPool使用RecursiveActionRecursiveTask Fork Join 案例Demo 概述 Fork 就是把一个大
  • JavaFx-缺少JavaFX运行时组件,需要这些组件才能运行此应用程序

    问题 报错 缺少JavaFX运行时组件 需要这些组件才能运行此应用程序 解决办法 解决办法额外添加一个类似启动类的java文件 然后将需要启动的文件以class添加到launch里就行 span class token keyword pu
  • Mysql-解决Truncated incorrect DOUBLE value xxx

    问题 出现这种问题一般来说就是多表操作的时候 使用的字段类型不一致导致的 查询除外 我们来看下真实案例 在hd user表中parentId是binint类型 而在hd user increment copy1 96 表中parentId是
  • Mysql-解决创建存储函数This function has none of DETERMINISTIC

    问题 当二进制日志启用后 xff0c 这个变量就会启用 它控制是否可以信任存储函数创建者 xff0c 不会创建写入二进制日志引起不安全事件的存储函数 如果设置为0 xff08 默认值 xff09 xff0c 用户不得创建或修改存储函数 xf
  • JPA-ids for this class must be manually assigned before calling save (使用数据库的自增)

    问题 Spring Data JPA ids for this class must be manually assigned before calling save id的生成错误 xff0c 在调用 save 方法之前 xff0c 必须
  • Java-gradle编译忽略警告

    使用gradle打包的时候出现好多警告 如何忽略大部分的警告呢 使用如下配置即可 tasks span class token punctuation span span class token function withType span
  • JPA-排除实体类里不存在于数据库的字段

    在实体类与数据库表建立映射关系时添加 64 Table 注解 当表中不存在实体类中的某个属性的时候 就需要用到 64 Transient 注解 如果不好使那么在 64 Transient基础上在添加 64 Column updatable
  • SpringBoot-快速搭建一套JPA

    文章目录 结构Mavenapplication yml实体类daoservicecontroller测试 结构 Maven span class token tag span class token tag span class token
  • IntelliJ IDEA-Gradle-SpringBoot搭建

    前提条件 IntelliJ IDEA Gradle教学 Gradle 全局镜像配置和优先使用Maven 将Gradle进行安装和配置 创建项目 配置项目设置 指定自己的gradle的安装位置 以及仓库位置 用户主目录 用户主目录 Gradl
  • 我的喜马拉雅FM开播啦!

  • SpringBoot-JAP-JpaSpecificationExecutor详解

    文章目录 SpringBoot JAP JpaSpecificationExecutor详解使用方法接口介绍自定义工厂 SpringBoot JAP JpaSpecificationExecutor详解 JpaSpecificationEx
  • SwitchHosts-快速切换Hosts

    SwitchHosts是一个管理 快速切换Hosts小工具 xff0c 开源软件 xff0c 一键切换Hosts配置 xff0c 非常实用 xff0c 高效 其主要功能特性包括 xff1a 下载地址 https github com old
  • Java-新年抽奖-消息自动化发送脚本

    我们公司7点半开年会 然后大约8点半开始抽奖抢 使用腾讯会议的方式进行发关键字消息然后截图方式抽奖 然而我还在地铁上 手速慢的我只抽到了3等奖小米耳机一个 然后我回家后迫不及待第一时间赶紧使用java写一个机器人脚本 疯狂发消息 一言难尽啊

随机推荐

  • Java多线程-CompletableFuture(链式)

    线程池这个大家都知道 xff0c 是为了提高效率 xff0c 可以类比生活 xff0c 如果开个店 xff0c 需要几个员工 xff0c 正常的操作都是雇佣员工 xff0c 而不是每天使用临时工 xff0c 这样用完就解雇掉 xff0c 对
  • Java-Javassist(字节码修改)

    文章目录 开篇Javassist 常用类Javassist 的使用依赖代码示例 如何实现类似 AOP 的功能 开篇 说起 AOP 小伙伴们肯定很熟悉 xff0c 无论是 JDK 动态代理或者是 CGLIB 等 xff0c 其底层都是通过操作
  • Java多线程-Pip管道

    管道的意思 就是向一个管子一样从一端到另一端 只支持单方向的数据传输 需要注意的不能在同一个线程使用管道否则会导致死锁的情况 发生和接收必须在不同线程 通过使用管道 xff0c 实现不同线程间的通信 xff0c 而无需借助于临时文件之类的东
  • 新版本代码自动生成(MybatisPlus-generator) 代码示例+问题解决

    虽然MybatisPlus官网上已经给出了新版本代码生成器的核心依赖和核心代码 xff0c 但对于没接触过的小伙伴还是比较困难上手 x1f62d xff0c 本文将展现如何使用MybatisPlus generator快速生成代码 目录 1
  • 虚拟机如何使用共享文件夹传文件

    项目场景 xff1a 在使用VMware平台 xff0c ubuntu操作系统时 xff0c ftp文件传输一直报错 问题描述 xff1a 尝试了多种 xff0c 更改电脑设置 xff0c 甚至重装虚拟机 xff0c 始终如下图报错 解决方
  • 强化学习入门DQN详解

    Deep Q Network 参考资料 xff1a B站莫烦 xff1a https www bilibili com video BV13W411Y75P spm id from 61 333 337 search card all cl
  • 某项目因为多次流标导致实际项目时间严重压缩,我该咋办?

    问题 xff1a 某政府项目 xff0c 三个月前就开始招标 xff0c 因各种原因 xff0c 流标三次 xff0c 导致时间拖太长 原计划一期工期三个月 43 xff0c 1月底上线 xff0c 但因为招投标影响直到一个月前签订了合同
  • ROS创建工作空间及功能包流程总结整理(python)

    ROS创建工作空间及功能包流程总结整理 xff08 python xff09 参考资料 xff1a B站赵虚左 xff1a https www bilibili com video BV1Ci4y1L7ZZ p 61 19 amp vd s
  • ROS自定义发布消息类型

    ROS自定义发布消息类型 xff1a 在 ROS 通信协议中 xff0c 数据载体是一个较为重要组成部分 xff0c 在上一案例中 xff0c ROS 中通过 std msgs 封装了一些原生的数据类型 比如 String Int32 In
  • ROS服务通信:自定义数据文件以及服务端和客户端代码编写流程及步骤详解

    ROS服务通信具体实现流程 demo xff1a 实现两个整型数相加求和 xff0c 客户端发送两个整型数 xff0c 服务端对其求和 服务通信也需要自定义服务数据类型 xff0c 即自定义srv文件 xff0c 该过程和自定义msg文件非
  • ROS TF静态坐标变换实现

    ROS TF静态坐标变换实现 法一 xff1a 编码实现 发布方代码实现 xff1a 创建功能包并添加依赖 catkin create pkg tf static roscpp rospy std msgs tf2 tf2 ros tf2
  • ROS:Gazebo导入自定义环境

    Gazebo导入自定义环境 之前的案例gazebo中导入的是一个空世界empty world xff0c 这里会介绍如何导入房屋数目等自定义的环境 xff08 1 xff09 启动 gazebo 打开构建面板 xff0c 绘制仿真环境 xf
  • ROS导航实现:SLAM建图(slam_gmapping)与保存(map_server)

    导航实现 xff1a SLAM建图 先安装相关的ROS功能包 安装 gmapping 包 用于构建地图 sudo apt install ros lt ROS版本 gt gmapping 安装地图服务包 用于保存与读取地图 sudo apt
  • ROS导航实现:amcl定位

    ROS导航实现 xff1a amcl定位 xff08 1 xff09 首先编写启动amcl的launch文件 xff0c 这里建议复制粘贴模板 xff0c 再修改相关的参数即可 xff0c 步骤如下 xff1a 主目录下进入amcl文件 r
  • ROS导航实现之路径规划

    导航实现之路径规划 move base 功能包提供了基于动作 action 的路径规划实现 xff0c move base 可以根据给定的目标点 xff0c 控制机器人底盘运动至目标位置 xff0c 并且在运动过程中会连续反馈机器人自身的姿
  • 创建个人网站(github pages)并将站点一键托管到Github

    创建个人网站 xff08 github pages xff09 并将站点一键托管到Github 内容 xff1a 使用网站生成器mkdocs将markdown文件生成wiki站点并挂载到github的流程总结 亮点 xff1a 个人网站一键
  • 视觉SLAM十四讲(第2版)总结

    最近看完了 视觉SLAM十四讲 xff08 第2版 xff09 xff1a 从理论到实践 xff08 高翔等著 xff09 xff0c 原书分两部分 xff0c 先介绍了数学基础 xff0c 然后介绍了具体的SLAM实践 xff0c 非常适
  • 我的公众号 - 豆芽儿 软件研发人才生长社区

    为你系统分享敏捷开发 项目管理 需求分析 软件设计 UML 中层领导力 CMMI IT职场 ACP 软考 PMP等 高大上 的实用知识 xff0c 帮助你进阶为高端人才 xff01
  • Openblas 下载和使用方法

    Openblas 下载及使用 环境 xff1a 平台 xff1a Ubuntu 20 04 xff0c Orin xff1a Arm Cortex A78AE v8 2 64 bit 步骤 xff1a 1 去github 下载openbla
  • FreeRTOS学习记录

    FreeRTOS学习记录 前言FreeRTOS学习记录在STM32CubeMX中配置FreeRTOS 前言 本人小白 xff0c 最近学习了FreeRTOS操作系统 xff0c 打算做一点记录 学习的过程中虽然做了点练习 xff0c 不过都