基于STM32、OV2640及ESP8266的无线图传

2023-11-17

一、简介:

        本文利用STM32F407单片机、OV2640摄像机模块以及ESP8266 WIFI模块,并基于C#编写的TCP上位机服务,来实现图像的无线传输。

        本文受启发于博客:ESP8266+STM32F407+OV7670实现图片传输,在此感谢该文作者。与该文不同的是,本文采用的摄像机模块是0V2640,传输的数据是压缩之后的jpeg格式的图像数据,而不是像上文博主那样,将RGB565数据直接传输到上位机。此外,本文存在和上文博主同样的问题,即采用串口传输方式,数据传输速率过低,实际应用中,发现3秒左右才能够传出一帧320*240的图片。本文接下来对整个图传功能中使用到的模块一一进行详细介绍。

二、DCMI+OV2640摄像头

        在整个图传项目中,使用到的最核心的模块就是OV2640模块, 关于该模块的介绍以及详细的驱动,可以参考文章:STM32F4驱动OV2640摄像头,该文详细介绍了OV2640模块、DMCI接口及整个OV2640的驱动。此处进行简要介绍:

        STM32F4驱动OV2640采用的是DCMI接口及DMA直接存储器访问对于DMA的相关介绍可以参考文章:STM32:DMA。整个驱动流程是:STM32单片机通过DCMI接口,获取OV2640摄像头采集到的图像数据,并通过提前配置好的DMA数据流,将数据传输到LCD或内部数组。如下图所示,是通过DMA配置,将DCMI采集到的图像数据传输到LCD显示屏的效果:

        关于LCD显示屏的介绍及详细驱动,可以参考博文:  STM32: LCD显示。这样,首先通过OV2640及LCD屏幕,将摄像头模块采集到的数据显示在屏幕上。

         该部分的源码: OV2640驱动,虽然我们将OV2640采集到的图像成功显示在了LCD屏幕之上,但是,我们最终的目的是将图像数据利用ESP8266模块通过WIFI传输到上位机或网页中,因此,我们还需要ESP8266模块。

三、ESP8266

         ESP8266是比较常见的WIFI模块,该模块有三种不同的工作模式,即softAP 模式station 模式softAP + station 共存模式。(SoftAP:即无线接入点,是一个无线网络的中心节点,通常使用的无线路由器就是一个无线接入点;Station:即无线终端,是一个无线网络的终端端。)

        本文我们将ESP8266作为客户端,并将其传输模式设置为透传,让其连接位于电脑的TCP上位机服务器,然后将OV2640采集的图像数据通过单片机传输给ESP8266模块,并采用WIFI发送给上位机。ESP8266的配置过程如下:

  • AT+RESTORE                                                      #恢复出厂设置
  • AT+CWMODE=1                                                  #设置ESP8266工作模式为STA
  • AT+RST                                                                #复位
  • AT+CWJAP="路由器账号","密码"                         #连接路由器
  • AT+CIPMODE=1                                                  #设置透传模式
  • AT+CIPSTART="TCP","192.168.6.117",8266      #连接TCP服务器(上位机)
  • AT+CIPSEND                                                       #开启透传

        此处要注意,本文的ESP8266是通过AT指令进行配置的,因此要保证ESP8266已经烧录了AT固件库,一般网上买的ESP8266模块默认会烧录AT固件库,如若没有,可以自行进行烧录。

四、工作原理

        基本的模块介绍已经完成,通过模块介绍,我们也可以发现,无线图传模块的工作原理是:首先我们利用STM32和OV2640模块,采集图像数据,然后,我们配置好ESP8266,让其连接上位机服务器,然后,我们通过串口,将STM32采集到的图像数据传输给ESP8266,由于ESP8266配置的是透传模式,因此其会将STM32通过串口发送过来的数据原封不动的通过WIFI发送给上位机,上位机在将这些图像数据解析为图像显示出来就可以了,如下图所示:

         上文中,我们介绍OV2640模块时,将图像显示在LCD屏幕上,但是,我们真正的目的,是将数据通过ESP8266模块传输给上位机。其实这两者本质上是一样的,一个是将数据通过DMA传输给LCD屏幕,而另外一个则是将数据传输给串口(因为ESP8266和STM32是通过串口连接的)

核心传输代码如下:

//处理JPEG数据
//当采集完一帧JPEG数据后,调用此函数,切换JPEG BUF.开始下一帧采集.
void jpeg_data_process(void)
{
	if(ov2640_mode)//只有在JPEG格式下,才需要做处理.
	{
		if(jpeg_data_ok==0)	//jpeg数据还未采集完?
		{	
			DMA_Cmd(DMA2_Stream1, DISABLE);//停止当前传输 
			while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}// 等待DMA2_Stream1可配置  
			jpeg_data_len=jpeg_buf_size-DMA_GetCurrDataCounter(DMA2_Stream1);// 得到此次数据传输的长度
      
			jpeg_data_ok = 1;    // 数据已经采集完成,等待被处理
		}
		if(jpeg_data_ok==2)	//上一次的jpeg数据已经被处理了
		{			
			DMA2_Stream1->NDTR=jpeg_buf_size;	
			DMA_SetCurrDataCounter(DMA2_Stream1,jpeg_buf_size);//传输长度为jpeg_buf_size*4字节
			DMA_Cmd(DMA2_Stream1, ENABLE); //重新传输
			jpeg_data_ok=0;						//标记数据未采集
		}
	}
} 

//jpeg模式
void jpeg_test(void)
{ 
  u32 i,jpgstart,jpglen;
  u8 headok=0;	
	u8 *p;
	u8 effect=0,saturation=2,contrast=2;
	u8 size=3;		  
	u8 msgbuf[15];	//消息缓存区 
	
	//uart4初始化
	LTE_uart3_init(115200);
	LCD_Clear(WHITE);
    POINT_COLOR=RED; 
	LCD_DisplayString(30,60,24,"ALIENTEK STM32F4");
	LCD_DisplayString(30,90,24,"OV2640 JPEG Mode");
	
    OV2640_JPEG_Mode(); // JPEG模式
	
	My_DCMI_Init();			//DCMI配置
	DCMI_DMA_Init((u32)&jpeg_buf,jpeg_buf_size,DMA_MemoryDataSize_Word,DMA_MemoryInc_Enable);//DCMI配置 输出到数组
 	OV2640_OutSize_Set(jpeg_img_size_tbl[size][0], jpeg_img_size_tbl[size][1]); 
	DCMI_Start(); 		//启动传输  
	delay_ms(500);
	while(1)
	{
		  if(jpeg_data_ok==1)  // 已经采集完成一帧图像,开始处理数据
		  {
					p=(u8*)jpeg_buf; 
					LCD_DisplayString(30,150,24,"Sending JPEG data...");
                    jpglen=0;	//设置jpg文件大小为0
					headok=0;	//清除jpg头标记				
		  for(i=0; i<jpeg_data_len*4; i++)
          {
						//查找OXFF,OXD8和0XFF,0XD9,获取jpg文件大小
						if((p[i]==0XFF)&&(p[i+1]==0XD8)){ 
							  jpgstart=i;
							  headok=1;	//标记找到jpg头(FF D8)
						}
						if((p[i]==0XFF)&&(p[i+1]==0XD9)&&headok)//找到头以后,再找FF D9
						{
							  jpglen=i-jpgstart+2;
								break;
						}
          } 
					
					if(jpglen) // 正常的jpeg数据
					{
						 p+=jpgstart;
						 for(i=0;i<jpglen;i++)	//发送整个jpg文件
						 {
								while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);	//循环发送,直到发送完毕  		
                                USART_SendData(USART3, p[i]); 
						 }

					}
					jpeg_data_ok = 2;	//标记jpeg数据处理完了,可以让DMA去采集下一帧了.
					delay_ms(2000);
	   	}
	}
}

        上述核心代码其实是两个函数,函数jpeg_data_process()在帧中断中被调用,也就是说,每次采集完一帧图像,该函数都会被调用。在该函数中,主要是修改标志jpeg_data_ok 为1,以便另外一个函数jpeg_test()可以对这一帧数据进行处理,所谓的处理在此处其实就是将数据通过串口发送给ESP8266ESP8266模块会将数据发送给上位机,并由上位机解析然后显示。

五、TCP服务上位机

        ESP8266在拿到STM32通过串口传输的图像数据之后,会将其发送给上位机,那么ESP8266和上位机之间是如何通讯的呢?是通过TCP/IP协议

        本文使用C#语言,基于TCP/IP协议,写了一个简单的上位机服务,该服务接受ESP8266的连接,并将其发送过来的数据编码为图像进行显示。由于软件写的很简单,因此很多功能并没有进行扩充实现,如其只支持一个设备的图传,后续可以进行升级改进。软件界面如下所示:

        该软件的实现思路非常简单,因此其功能也比较粗狂,bug较多。

        软件整体包含两条主要的线程以及一个数据缓冲容器(生产者消费者模式)。在服务器启动之后,软件开启监听服务,监听ESP8266的连接请求,并开启一个消费线程,用于从缓冲容器中获取图像数据(此时应该没有数据),在服务与ESP8266建立连接之后,就开始接收来自ESP8266的图像数据,此时,创建一个数据生产线程,将服务器接收到的数据存放到缓冲容器中,这样,这两个线程一个专门负责将接收到的数据放到缓冲容器中,一个专门负责从缓冲容器中获取数据并将其解码为图像在界面显示。

上位机核心代码:

        /// <summary>
        /// 接收客户端发送的图像数据,并放到缓冲容器中。
        /// </summary>
        /// <param name="proxsocket"></param>
        public void ReceiveClientMessage(object socket)
        {
            int imageCount = 0;
            //服务器端与客户端之间用于通讯的socket
            Socket proxSocket = socket as Socket;

            //开辟用来存储客户端发送来的数据的控件
            byte[] dataClient = new byte[640 * 240];
            proxSocket.ReceiveTimeout = 1000 * 300;   // 设置接收数据时的阻塞时间为15秒钟
            //接收客户端数据
            while (serverStart)    
            {
                StringBuilder imageData = new StringBuilder();
                try
                {
                    while (imageCount < 5)
                    {
                        int countRev = proxSocket.Receive(dataClient, 0, dataClient.Length, SocketFlags.None);
                        string revDate = StringUtils.ToHexStrFromByte(dataClient, countRev);
                        if (revDate.Length>0)
                        {
                            imageData.Append(revDate);
                            imageCount++;
                            AppendToMessage(revDate);
                        }
                    }
                    jpegQueue.Add(imageData.ToString());
                    imageCount = 0;
                }
                catch (SocketException e)
                {
                    if (e.ErrorCode == 10060)
                    {
                        continue;
                    }
                    else
                    {
                        //客户端非正常退出。
                        AppendToMessage(string.Format("客户端:{0}非正常退出。", proxSocket.RemoteEndPoint.ToString()));
                        return; //线程终结
                    }
                }

            }
        }

        /// <summary>
        /// 从容器中获取图形数据,并解析为图像显示
        /// </summary>
        private void createImg()
        {
            string imgData = "";
            while (serverStart)
            {
                string imgListData = jpegQueue.Take();
                imgData = imgData + imgListData;
                while (imgData.IndexOf("FF D8")!=-1)
                {
                    int startIndex = imgData.IndexOf("FF D8");
                    int endIndex = imgData.IndexOf("FF D9");
                    if (endIndex != -1)
                    {
                        string jpeg = imgData.Substring(startIndex,endIndex+5-startIndex);
                        imgData = imgData.Substring(endIndex+5);
                        Bitmap imageBitmap = StringUtils.GetJpegImage(jpeg.Replace(" ", ""));
                        if (imageBitmap != null)
                        {
                            Image img = Image.FromHbitmap(imageBitmap.GetHbitmap());
                            if (this.JpgImage.InvokeRequired)
                            {
                                JpgImage.Invoke(new Action<Image>(s =>
                                {
                                    JpgImage.Image = s;
                                }), img);
                            }
                            else
                            {
                                this.JpgImage.Image = img;
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        break;
                    }

                }
            }
        }

        图像数据的解析也非常简单,根据JPEG图像的特点,其开头为FFD8,结尾为FFD9,我们通过查找这两个标志位,其中间的数据就是整帧的图像数据,我们将其这些数据转化位Bitmap位图进行显示就可以了。显示效果如下图:

         上图中可以看出,OV2640采集到的图像数据,最终经过ESP8266发送到了上位机,并成功显示出来,只是受限于串口速率,大概3秒才会传输完一帧数据,在实际使用时,也可以发现,上位机数据缓冲容器时常都是空的,数据生产线程受限于串口速率,导致数据的生产远远小于数据的消耗,表现出来就是几秒才会刷新一帧数据。

六、结束:

        本文主要基于STM32、OV2640以及ESP8266完成图像的网络传输,本文受启发并参考了博文:ESP8266+STM32F407+OV7670实现图片传输,在此对该文作者表示深深的感谢。

        本文下位机图像数据采集以及上位机图像数据解析源码如下:

无线图传下位机源码https://download.csdn.net/download/sssxlxwbwz/85251144

无线图传上位机源码: https://download.csdn.net/download/sssxlxwbwz/85251105

        

        

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

基于STM32、OV2640及ESP8266的无线图传 的相关文章

  • 优化 ARM Cortex M3 代码

    我有一个 C 函数 它尝试将帧缓冲区复制到 FSMC RAM 这些函数将游戏循环的帧速率降低至 10FPS 我想知道如何分析反汇编的函数 我应该计算每个指令周期吗 我想知道CPU把时间花在哪里 在哪个部分 我确信该算法也是一个问题 因为它的
  • STM32F4 通过软复位跳转到引导加载程序,无需 BOOT0 和 BOOT1 引脚

    我问这个问题是因为可以在这里找到类似问题的答案 通过应用程序跳转到 STM32 中的引导加载程序 即从用户闪存在引导模式下使用引导 0 和引导 1 引脚 用户 JF002 JF002回答 当我想跳转到引导加载程序时 我在其中一个备份寄存器中
  • 使用 MQTT 代理对 ESP8266 Wemos D1 Mini 进行 SSL 证书验证

    我有一个树莓派 3 其操作系统为 raspbianstretch 我已经按照本教程在树莓派上安装并完全配置了 MQTT 代理 https www digitalocean com community tutorials how to ins
  • HAL 锁定和解锁函数如何使用以及为什么?

    我试图理解另一位程序员编写的代码 它使用了I C http en wikipedia org wiki I C2 B2C通信以将数据写入 STM32 微控制器的 EEPROM 一般来说 我理解他的代码是如何工作的 但我不明白他为什么使用HA
  • ESP8266 烧录 (关于BearPi扩展Wifi模块的烧录方式)

    简介 ESP 12F 模块是BearPI IOT购买的一个套餐所带的扩展模块 用来接通网络 但是默认电路不支持重新烧录 下面就是可支持重新烧录的方式 ESP 12F 电路原理图 如上图 GPIO15 gt GND gt 高电平 GPIO2
  • 跟着野火学FreeRTOS:第一段(任务定义,切换以及临界段)

    在裸机系统中 系统的主体就是 C P U CPU CP U 按照预先设定的程序逻辑在 m a i n
  • STM32的HAL中实现单按、长按和双按功能

    我正在尝试实现单击 双击和长按功能来执行不同的功能 到目前为止 我已经理解了单击和长按的逻辑 但我不知道如何检测双击 至于代码 我使用计数器实现了单击和长按 但代码仅停留在第一个 if 条件上 bool single press false
  • STM32F207 I2C 测试失败

    我正在使用 STM32F207 微控制器在 STM3220G EVAL 板上学习嵌入式开发 我尝试通过连接同一芯片上的两个 I2C2 和 I2C3 模块并发送 接收字符来测试 I2C 接口 这是我当前编写的代码 使用 mdk arm 5 i
  • 无法使用 OpenOCD 找到脚本文件

    我正在尝试按照本教程将 OpenOCD 与我的 ST 发现板一起使用 https japaric github io discovery README html https japaric github io discovery READM
  • 库函数点亮Led

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 提示 这里可以添加本文要记录的大概内容 例如 随着人工智能的不断发展 机器学习这门
  • 核心耦合内存在 STM32F4xx 上可执行吗?

    尝试从 STM32F429s CCM 运行代码 但每当我命中 CCM 中的第一条指令时 我总是会遇到硬故障 并且 IBUSERR 标志被设置 该指令有效且一致 STM32F4xx 是否可能不允许从 CCM 执行 数据访问效果良好 alios
  • STM32 Nucleo 上的上升沿中断多次触发

    我正在使用 STM32 NUCLEO F401RE 微控制器板 我有一个扬声器 经过编程 当向上 向下推操纵杆时 可以按设定的量改变频率 我的问题是 有时 通常 当向上 向下推动操纵杆时 频率会增加 减少多次 这意味着 ISR 正在执行多次
  • 通过JTAG恢复STM32 MCU磨掉的标记

    我有一块可能带有 STM32 MCU 的板 我想为该板制作定制固件 因为库存板有很多问题 不幸的是 电路板制造商很友善地磨掉了所有标记 有没有办法通过 jtag 获取设备 系列 ID 并将其交叉引用到型号 我能找到的一切都是关于获取芯片的唯
  • 嵌入式 C++11 代码 — 我需要 volatile 吗?

    采用 Cortex M3 MCU STM32F1 的嵌入式设备 它具有嵌入式闪存 64K MCU固件可以在运行时重新编程闪存扇区 这是由闪存控制器 FMC 寄存器完成的 所以它不像a b那么简单 FMC 获取缓冲区指针并将数据刻录到某个闪存
  • STM32 上的位置无关代码 - 指针

    我已成功在 STM32 上构建并运行位置无关的代码 向量表和 GOT 已修补 一切正常 但我对这样的代码有问题 double myAdd double x return x 0 1 double ptrmyAdd double myAdd
  • STM32内部时钟

    我对 STM32F7 设备 意法半导体的 Cortex M7 微控制器 上的时钟系统感到困惑 参考手册没有充分阐明这些时钟之间的差异 SYSCLK HCLK FCLK 参考手册中阅读章节 gt RCC 为 Cortex 系统定时器 SysT
  • 使用 STM32F0 ADC 单独读取不同的输入

    STM32F072CBU 微控制器 我有多个 ADC 输入 并且希望单独读取它们 STMcubeMX 生成样板代码 假设我希望按顺序读取所有输入 但我无法弄清楚如何纠正这个问题 这篇博文 http blog koepi info 2015
  • 使用 SPIFFS 加载文件时出现问题 (ERR_CONTENT_LENGTH_MISMATCH)

    好吧 这两天我一直在研究这个问题 但我仍然觉得我一无所获 我最近开始使用SPIFFS 文件系统 for Arduino开发于呼扎 ESP8266像FSBrowser ino例如 虽然它在分离代码方面非常出色 但随着我的代码不断增长 它在稳定
  • STM32 传输结束时,循环 DMA 外设到存储器的行为如何?

    我想问一下 在以下情况下 STM32 中的 DMA SPI rx 会如何表现 我有一个指定的 例如 96 字节数组 名为 A 用于存储从 SPI 接收到的数据 我打开循环 SPI DMA 它对每个字节进行操作 配置为 96 字节 是否有可能
  • stm32l0: 执行MI命令失败。使用 vFlashErase 数据包擦除闪存时出错

    我正在使用 Nucleo STM32L031 和 AC6 STM32 工作台 eclipse 我编写应用程序并进入调试模式 一切正常 直到我在应用程序中添加另一个功能 我注意到当我删除 评论 新函数 软件可以再次进入调试模式 但是当我添加

随机推荐

  • python爬虫系列X--小知识汇总

    X系列不针对专门技术 只是一些辅助 内容零散添加 1 为爬虫运行状态设置邮件提醒 使用python smtp email模块完成 from email mime text import MIMETextfrom email header i
  • 【第63篇】CSI-Net:统一的人体特征和姿态识别

    摘要 https arxiv org pdf 1810 03064 pdf 我们构建了CSI Net 一个统一的深度神经网络 DNN 来学习WiFi信号的表示 使用CSI Net 我们共同解决了两个身体特征问题 生物特征估计 包括身体脂肪
  • 【美国大学生数学建模比赛】2020C题(总结和原创参赛论文)百度云请自取

    最新想法 本学期选修了下大数据 发现其实本题的解法还涉及到数据库 大数据各个层次数据处理和分布式数据流blabla 而之前那几天美赛做的还停留在最基础的数据处理层 而且我现在觉得如果要做大的话不应该在这个层里面进行深度学习 前面的数据库处理
  • 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?实现 int sqrt(int x) 函数。

    今天我们来爬一爬楼梯 假设你正在爬楼梯 需要 n 阶你才能到达楼顶 每次你可以爬 1 或 2 个台阶 你有多少种不同的方法可以爬到楼顶呢 注意 给定 n 是一个正整数 示例 1 输入 2 输出 2 解释 有两种方法可以爬到楼顶 1 阶 1
  • 为啥 Python 运行速度这么慢 ?

    作者 Anthony Shaw 是 Python 软件基金会成员和 Apache 基金会成员 近来Python可谓人气骤升 这门编程语言用于开发运维 DevOps 数据科学 网站开发和安全 然而 它没有因速度而赢得任何奖牌 Java在速度方
  • javascript防抖(Debouncing)和节流阀(Throttling)

    中文原文链接 https jinlong github io 2016 04 24 Debouncing and Throttling Explained Through Examples 英文原文链接 https css tricks c
  • C++ 生命周期

    C 程序的生命周期要经过编码 Coding 预处理 Pre processing 编译 Compiling 和运行 Running 四个阶段 编码即coding阶段 这阶段主要是定义变量 写语句 实现各种数据结构 函数和类 预处理是 C C
  • Qt::带返回值的信号发射方式

    一般来说 我们发出信号使用emit这个关键字来操作 但是会发现 emit并不算一个调用 所以它没有返回值 那么如果我们发出这个信号想获取一个返回值怎么办呢 两个办法 1 通过出参形式返回 引用或者指针的方式带回 比如emit sig int
  • 【SHELL脚本】MYSQLDUMP备份数据库,含忽略数据表

    背景介绍 项目的数据库十分重要 必须保证数据不能丢失 项目组的数据库为mysql5 7 12 采用备份工具mysqldump 开发需求 备份指定多个数据库 部分数据库的部分数据表需要指定忽略 打包上传到go FastDFS文件管理器 下面为
  • jvm 内存分配

    1 任何对象都是以8字节为粒度进行对齐的 2 类属性按照如下优先级进行排列 长整型和双精度类型 8字节 整型和浮点型 4字节 字符和短整型 2字节 字符类型和布尔类型 1字节 最后时引用类型 3 不同类型继承关系类的成员不能混合排列 首先按
  • 程序员究竟还需要读书么?

    近来看了2篇和读书有关的文章 一篇提到Joel讲现在程序员不太读书了 主要靠在网上找各种参考资料 一篇则是马总说的 成功与情商有关 与读书多少关系不大 一定程度上这两个观点都有点道理 可以靠StackOverflow com和搜索引擎找到各
  • 1 FFmpeg从入门到精通-FFmpeg简介

    1 FFmpeg从入门到精通 FFmpeg简介 2 FFmpeg从入门到精通 FFmpeg工具使用基础 3 FFmpeg从入门到精通 FFmpeg转封装 4 FFmpeg从入门到精通 FFmpeg转码 5 FFmpeg从入门到精通 FFmp
  • 一个人开发APP系列之实战1 制作APP产品启动图标

    声明 写这个博客系列也是为了清晰思路 新手写的不好 请大神们指导指导 建议想学的还是先去android develops官网看看相关资料吧 好了 不闲扯了 进入正题 今天的目的是使用Android Studio自带的工具Image Asse
  • TencentOS-tiny 功耗管理 (二十 二)- tickless(低功耗)

    一 功耗管理 tickless 概述 TencentOS tiny的tickless机制提供了一套非周期性时钟的方案 在系统无需systick驱动调度的情况下 停掉systick 初级功耗管理方案下 因为还有系统systick的存在 因此系
  • python机器人编程——差速AGV机器、基于视觉和预测控制的循迹、自动行驶(下篇)

    目录 一 前言 二 基于轨迹与路面重心偏离度误差的预测自动差速小车循迹控制策略 三 轨迹图像的处理要点 四 本篇部分核心控制策略python代码 五 结论 一 前言 基于最近的测试 得到了一种粗略控制的算法 其控制效果适合单线路和急转弯的情
  • DevExpress控件手册

    https www evget com article 2018 7 17 28180 html 手册是全英文的 有chm和pdf两种格式 winform手册有两百来兆 内容的确是很详细了 每个控件还有入门的详细例子 建议下载CHM格式的
  • 【AUTOSAR】CCP协议的代码分析与解读(二)----CCP协议格式和命令代码

    CCP协议介绍 CCP的全称是CAN Calibration Protocol CAN标定协议 是基于CAN总线的ECU标定协议规范 CCP协议遵从CAN2 0通信规范 支持11位标准与29位扩展标识符 CCP通信方式 CCP协议采用主从通
  • 单链表的增删改查

    链表的增 改 查 删 public class LinkLIST int size 节点个数 NewNode head 头节点地址 class NewNode int val 存放具体数据 NewNode next 存下一个节点的地址 pu
  • python全排列库_python——全排列数的生成方式

    问题描述 输入整数N 1 lt N lt 10 生成从1 N所有整数的全排列 输入形式 输入整数N 输出形式 输出有N 行 每行都是从1 N所有整数的一个全排列 各整数之间以空格分隔 各行上的全排列不重复 输出各行遵循 小数优先 原则 在各
  • 基于STM32、OV2640及ESP8266的无线图传

    一 简介 本文利用STM32F407单片机 OV2640摄像机模块以及ESP8266 WIFI模块 并基于C 编写的TCP上位机服务 来实现图像的无线传输 本文受启发于博客 ESP8266 STM32F407 OV7670实现图片传输 在此