- 2024-12-01
-
回复了主题帖:
[Follow me第二季第3期] [基础任务] Q-spi 和O-spi 读写速度测试 + DAC输出和性能测试
Jacktang 发表于 2024-12-1 16:17
虽然三用表精度不够,但效果已经到位了,谢谢分享
我还有个51单片机的示波器, 今天晚点我补充一下波形
-
发表了主题帖:
[Follow me第二季第3期] [进阶任务] 示例程序中新增命令打印信息
简介
quick_start 的menu菜单是一个非常棒的功能。 那么本章节将演示如何在示例程序中新增命令的打印信息
正文
根据程序的追踪menu_main.c 是程序的主菜单入口文件。我们可以观察到上述定义了很多的菜单。 它同时还包括了一些其他的菜单。
我们可以按下ctrl + 鼠标左键来点击对应的方法来跳转到具体的某个菜单实现。
我们可以发现, 菜单的打印其实就是每次把数据写入到缓冲区里, 然后打印到串口。 同时当前的任务等待按下空格然后退出。 所以我们可以仿照这种形式来完成一个属于我们自己的一个简易菜单来打印信息。
仿照上述的格式, 首先我们定义一个菜单的头文件
menu_text.h
#ifndef MENU_TEXT
#define MENU_TEXT
extern test_fn ns_display_hello_world (void);
#endif /* MENU_ETH_WWW_H_ */
和它的具体实现
menu_text.c
/*
* menu_text.c
*
* Created on: 2024年12月1日
* Author: 23391
*/
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "semphr.h"
#include "queue.h"
#include "task.h"
#include "common_init.h"
#include "common_utils.h"
#include "menu_text.h"
#define CONNECTION_ABORT_CRTL (0x00)
#define MENU_EXIT_CRTL (0x20)
static char_t s_print_buffer[BUFFER_LINE_LENGTH] = {};
#define MODULE_NAME "\r\n%d. Hello world!\r\n"
test_fn ns_display_hello_world (void)
{
int8_t c = -1;
print_to_console((void*)s_print_buffer);
sprintf (s_print_buffer, MODULE_NAME, g_selected_menu);
print_to_console((void*)s_print_buffer);
sprintf (s_print_buffer, MENU_RETURN_INFO);
while ((CONNECTION_ABORT_CRTL != c))
{
c = input_from_console ();
if ((MENU_EXIT_CRTL == c) || (CONNECTION_ABORT_CRTL == c))
{
break;
}
}
return (0);
}
那么之后在menu_main.c 中包含这个头文件,并且在menu菜单中多增加一行,把我们的方法放进去。
烧录并且查看实验现象。
[localvideo]eac2e63550f37de357b52e4d6f90d8f4[/localvideo]
-
加入了学习《FollowMe 第二季:3 - EK_RA6M5 开发板入门》,观看 EK-RA6M5 开发板入门
-
发表了主题帖:
[Follow me第二季第3期] [基础任务] Q-spi 和O-spi 读写速度测试 + DAC输出和性能测试
本帖最后由 御坂10032号 于 2024-12-1 06:13 编辑
简介
本章节我们来完成基础任务, 即QSPI 和 OSPI的配置以及读写测试, 和DAC的输出和精度测试。
任务1: Q-spi 和O-spi 读写速度测试
从下图我们可以看到,这块开发板板载了一块32MB的QSPI flash 和一块64MB的OSPI flash。接下来我们可以对其进行配置和读写测试。
在创建项目的时候如果我们选择是基于board的方式创建的话,那么针对当前开发板的所有的外设资源都会被正确的初始化。 我们可以在configuration.xml 中进行检查。
下图为QSPI的PIN配置
下图为OSPI的PIN配置
QUICK_Start 项目中提供了一份完整的QSPI和OSPI的对比测试。
OSPI的方法定义在ospi-test.h里, 而它的上层调用在menu_ext.c 里。
当程序调用测试方法之后, 会将OSPI的测试结果返回,然后进行QSPI的写测试,同时得到两者的时间, 读操作类似。所以我们可以在menu中来进行这个测试
输入 4, 进行对比测试。
输入最大的测试块大小。
下图为测试结果, 可以看出, 在64KB的读写测试中OSPI的速度明显要更胜一筹。无论是在读写的方面
任务2: DAC输出和性能测试
E2- studio 对RA系列的程序集成的非常好, 所有的功能等是处于可选的, 当你不选择生成的时候,这些对应外设的库文件并不会为你生成,但是当你初始化完PIN之后, 并且配置stack,那么这些库文件才会被生成到IDE里。
下面我将演示如何配置FSP生成DAC的库函数和PIN的初始化。
1- 在基于board的项目创建完毕后,点击configuration.yml 选择PIN
在上述PIN的地方初始化DAC0或者1, 但是在enable的时候会出现error,原因是这个PIN已经被使用为了ADC. 所以需要在ADC处将这个PIN给取消占用。
之后点击下面的Stacks选项
逐次点击, New Stack, Analog , DAC, 然后点击Generate Project content. 这样的话DAC的初始化配置已经完成了。 我们可以检查Ra 的 hal_data 内已经有了DAC的相关配置。
下图为DAC的相关库(FSP)
接下来打开src下的hal_entry写下我们的代码。代码如下(使其DAC从0 输出到 4095, 然后4095 到0)
#include "hal_data.h"
#include "r_dac.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
void dac0_initialize(void);
/*******************************************************************************************************************//**
* main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function
* is called by main() when no RTOS is used.
**********************************************************************************************************************/
void hal_entry(void)
{
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
/* Initialize DAC0 */
dac0_initialize();
uint16_t dac_value = 0; // Current DAC value
int step = 1; // Step direction (1 for increment, -1 for decrement)
/* Main loop */
while (1)
{
/* Write the current DAC value */
R_DAC_Write(&g_dac0_ctrl, dac_value);
/* Update the DAC value */
dac_value += step;
/* Check boundaries */
if (dac_value == 4095) // Maximum value for 12-bit DAC
{
step = -1; // Switch to decrementing
}
else if (dac_value == 0) // Minimum value
{
step = 1; // Switch to incrementing
}
/* Add a delay to control the update rate */
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
}
}
/*******************************************************************************************************************//**
* DAC0 Initialization
**********************************************************************************************************************/
void dac0_initialize(void)
{
/* Open DAC0 */
fsp_err_t err = R_DAC_Open(&g_dac0_ctrl, &g_dac0_cfg);
if (FSP_SUCCESS != err)
{
/* Handle error */
__BKPT(0);
}
/* Start DAC0 */
err = R_DAC_Start(&g_dac0_ctrl);
if (FSP_SUCCESS != err)
{
/* Handle error */
__BKPT(0);
}
/* Optional: Set the initial DAC value to 0 */
err = R_DAC_Write(&g_dac0_ctrl, 0);
if (FSP_SUCCESS != err)
{
/* Handle error */
__BKPT(0);
}
}
/*******************************************************************************************************************//**
* This function is called at various points during the startup process. This implementation uses the event that is
* called right before main() to set up the pins.
*
* @param[in] event Where at in the start up process the code is currently at
**********************************************************************************************************************/
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
if (BSP_WARM_START_RESET == event)
{
#if BSP_FEATURE_FLASH_LP_VERSION != 0
/* Enable reading from data flash. */
R_FACI_LP->DFLCTL = 1U;
/* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
* C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
}
if (BSP_WARM_START_POST_C == event)
{
/* C runtime environment and system clocks are setup. */
/* Configure pins. */
R_IOPORT_Open(&g_ioport_ctrl, g_ioport.p_cfg);
#if BSP_CFG_SDRAM_ENABLED
/* Setup SDRAM and initialize it. Must configure pins first. */
R_BSP_SdramInit(true);
#endif
}
}
#if BSP_TZ_SECURE_BUILD
FSP_CPP_HEADER
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable();
/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable()
{
}
FSP_CPP_FOOTER
#endif
进行编译和烧录,然后使用万用表测试P014
将万用表的 负极接到GND, 正极接到DAC的输出 P014.
视频效果如下所示
[localvideo]9176f38e2c1ae7b2f33928304561f6db[/localvideo]
代码如下
-
回复了主题帖:
[光学传感器] X-NUCLEO-53L4A3 飞行时间 (ToF) 传感器的其他应用
lugl4313820 发表于 2024-11-30 22:48
这个只能检测一个区域,检测多个区域的是其他的型号,当时我也是以为可以检测多个区域的。
我说怎么看代码都感觉好像是这样,但是也不敢确定
- 2024-11-30
-
发表了主题帖:
[光学传感器] X-NUCLEO-53L4A3 飞行时间 (ToF) 传感器的其他应用
本帖最后由 御坂10032号 于 2024-11-30 02:32 编辑
简介
本章节将介绍TOF传感器在其他方面上的应用。在上几个章节中我们使用TOF传感器成功的读取到了距离信息(包括多个zone的距离信息。)即可以检测到多个目标的距离信息。
那么如果背测的物体始终是处于TOF传感器的测试中心的话(TOF可以检测到物体), 那么TOF可以拿到每个Zone的距离值。 比如说被测平面不平整的话,那么每一个zone的距离信息都将不相同。 我们可以通过距离信息的判断来做一些有趣的应用。
具体的方法定义在下述截图中
我们可以从每次获取测试结果的 变量中来找到一共有几个区域, 以及区域中一共有多少个目标(包括当前区域的噪声和信号强度)。信噪比同样是一个衡量当前测量结果的重要指标。 即判断当前的测量结果是否可信。 我在另一家公司的TOF传感器的教学视频里,看到它们公司是信噪比如果大于6 的话即可确定当前的测试结果是可靠的。
那么如果我们可以获取到每一个Zone的距离的话(实际上在测量的时候, 并不是每次都能获取到多个zone的结果)。比如说3*3 . 那么我们可以拿这次的结果来构建一个矩阵
如下图所示:
我们可以从右侧的数据即zone 3 6 9, 和 1 4 7 做对比, 发现这一个平面的右侧数据是高于左侧的, 即中间的物体的形状最低。假设TOF传感器位于下图所示,结合上面的数据, 这个图形的某一个平面将如下图所示 (仅仅TOF 对应的平面)。
因此,我们可以将当此的数据进行保存, 同时和下一次的数据进行对比来得到下一次测量物体相对这次的形状或者位置的变化, 比如说旋转等。
但是遗憾的是,在我实现的过程中并没有能很好的处理好每个区域的距离信息。并且不清楚到底在什么情况下才能被检测到多个目标。 在我的测试中, 在多个物体的情况下,90%的时间都是显示的两个物体。 很少很少才有检测到多个zone。 效果如下所示。
[localvideo]5355b612e11cb9f17f1ac60e0a48c489[/localvideo]
总结
综上所述, 仅仅本次所有的测评的结果上来看, TOF的其他方便的应用空间还非常大。 我也看了其他坛友发的手势识别等也是一个应用的方向。但是由于个人的能力有限没办法完成的复刻手势识别。但是这次的评测可以看出,TOF传感器在测距方面上表现尤为出色!其相应速度和精度都是一大亮点。比如应用在物体检测和避障的方面。
- 2024-11-22
-
回复了主题帖:
【Follow me第二季第3期】 入门任务 + 搭建环境,下载调试示例程序,Blink,按键
秦天qintian0303 发表于 2024-11-22 21:15
Follow me第二季第3期和第四期同步进行了
活动多多, 今年参加两季了。没有参加第四季
-
回复了主题帖:
【Follow me第二季第3期】 开箱 + RA6M5
Jacktang 发表于 2024-11-22 07:32
好吧,在搭建开发环境的测试时把步骤说的清楚一下啊
哈哈, 在下一个帖子. 这个帖子只是一个开箱
- 2024-11-21
-
加入了学习《直播回放: FollowMe 3 与得捷一起解锁开发板的超能力》,观看 FollowMe 3 与得捷一起解锁开发板的超能力
-
发表了主题帖:
【Follow me第二季第3期】 入门任务 + 搭建环境,下载调试示例程序,Blink,按键
本帖最后由 御坂10032号 于 2024-11-22 00:37 编辑
简介
本章节为环境搭建教程,为完成任务做前置准备。e² studio 是面向瑞萨电子 MCU 的基于 Eclipse 的集成开发环境(IDE)。 除了 Eclipse 自己强大的代码编辑器外,e² studio 还提供许多扩展功能。e² studio 涵盖了从下载示例代码到调试的所有开发过程。
我们可以从下面的网站来进行访问和下载 (需要注册账号,并且登录)
下载完成之后对压缩包进行解压然后开始安装步骤
在这里选择支持的环境, 可以自己根据需要选择, 我这里直接偷懒全部选中
保持默认选项
等待安装完成
在安装过程中会提示安装多个软件, 直接接受协议安装即可。(不建议全部安装, 太慢了!)
安装完毕
下载调试示例程序 -BLINK 和 按键
1- 导入示例的项目 (项目可以从附送的小卡片上的网站上下载也可以从github上下载)
2 - 配置串口
注意此时的USB线需要插到Full speed usb上, 这样的话串口才可以接受到数据, 而在Debug的时候需要把线插到debug上。 如果你由两根线的话则可以这样接线。
点击build 即可编译当前的项目, 但是我这个IDE不知道为什么没有找到这个icon, 所有需要手动点击build 选项。
Debug选项则需要按以下选择。
调试界面如下所示:
下载代码之后,串口的显示选项将会多出来几个。
此时如果按照Follow me 直播中一样修改LED的占空比等数据的话,便可以通过按钮修改LED的闪烁频率和亮度等
此时入门任务已经完成。 效果如下所示
[localvideo]9c73a540e380c36c9dfe1b2c139aba25[/localvideo]
源码如下:
-
发表了主题帖:
【Follow me第二季第3期】 开箱 + RA6M5
简介
等待了这么久,快递终于是到了,这块板子被里三层外三层的包裹着。 箱子非常大, 到最后只拆剩下了一点点。
板子正面照
板子附送的线
这个板子是我所有带网口的板子中唯一一个附送了网线的板子, 点赞!在下一个章节中我们将搭建开发环境。
- 2024-11-20
-
回复了主题帖:
动手学深度学习(PyTorch版)- 【读书活动-心得分享】多层感知机的实现
Jacktang 发表于 2024-11-20 07:31
隐藏层大小为小于特征分类的最大值的情况一般会仓出现在什么情况下
老师的建议是, 比如你的输入Input 输入是 128, 那么你第一层的隐藏层的size 不建议太大。 可以自己测试, 然后来对比训练处模型的精度。 比如说你第一次的隐藏层大小为 16, 那么你觉得它不理想的话 可以调整成 32, 等等。 一般建议创建多个隐藏层,而不建议一个隐藏层太大
- 2024-11-19
-
发表了主题帖:
动手学深度学习(PyTorch版)- 【读书活动-心得分享】多层感知机的实现
简介
虽然读书活动结束了,但是真的想把这一本书里的东西学完。 之后也会继续更新这本书的内容。本章节学习了多层感知机。 多层感知机相对于单层感知机可以处理XOR问题。 每一层都具有每一层的权重和偏差。 第一层的输入数据, 输入到隐藏层。然后隐藏层对输入层的特征进行提取(可以指定隐藏层的大小)。然后将隐层的的特征作为下一层的输入。 到最后来获取到分类的数据。
我这里按照了书里的感知机运行了代码。通过调整隐藏层的大小获取到了不同的模型的训练曲线。
我们可以在上图看到,我这里一共截图了size 分别为 10 , 64 , 512 和 1024的隐藏层大小。 分别对比了不同的模型的训练曲线。
我们可以在上图看到如果隐藏层的层数增加(也不是绝对,512 和 1024 基本上没区别), 模型的训练正确度和测试正确度都比较平滑。 差别比较大的可以对比64 和 10 或者 10 和512. 我们发现除了损失,模型的精确度其实差不多。 对于损失函数而言我们可以发现 512 和 1024的损失基本上没区别。 但是 10 , 64,512 对比差距就比较大了。 通过上述我们发现一个规律。即:如果隐藏层的大小超过了某一个阈值即当前层无法为图像区别更多的特征(比如说一个图片根据任何的条件进行特征分类最多为10个特征, 但是这里隐藏层的长度为20). 那么隐藏层大小10 和20 将会没有区别。 但是如果隐藏层大小为小于特征分类的最大值的话。 那么损失函数的变化将会有所不同。
import torch
from torch import nn
from d2l import torch as d2l
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
num_inputs, num_outputs, num_hiddens = 784, 10, 1024
W1 = nn.Parameter(torch.randn(
num_inputs, num_hiddens, requires_grad=True) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
W2 = nn.Parameter(torch.randn(
num_hiddens, num_outputs, requires_grad=True) * 0.01)
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))
params = [W1, b1, W2, b2]
def relu(X):
a = torch.zeros_like(X)
return torch.max(X, a)
def net(X):
X = X.reshape((-1, num_inputs))
H = relu(X@W1 + b1) # 这里“@”代表矩阵乘法
return (H@W2 + b2)
loss = nn.CrossEntropyLoss(reduction='none')
num_epochs, lr = 10, 0.1
updater = torch.optim.SGD(params, lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)
d2l.predict_ch3(net, test_iter)
- 2024-11-18
-
发表了主题帖:
X-NUCLEO-53L4A3 飞行时间 (ToF) 传感器 [距离精度测试-不同传感器对比]
本帖最后由 御坂10032号 于 2024-11-18 19:59 编辑
简介
在本章节中我们将使用Tof传感器和常见的支持测距的传感器进行测距精度的对比。由于并非是完全精密的环境下,实验的结果仅供参考(但是也是可以通过测试来大概的评测出不同种类传感器的精度等)。
正文
本次设计的传感器一共有三个
1- 超声波测距模块
2- 安信可RD-03E雷达模块(精准测距固件)
3-Tof传感器53L4A3
上图中, 安信可的RD-03E使用的串口连接到串口工具。接线方式如下图所示
ESP32-C6的Oled屏幕和超声波测距代码如下所示
/**********************************************************************
程序名称/Program name : words_display_with_ultrasonic
团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
作者/Author : Dapenson
日期/Date(YYYYMMDD) : 2020/07/01
程序目的/Purpose :
使用OLED0.96 IIC 12864显示文字,并实时显示超声波传感器测量的距离
-----------------------------------------------------------------------
修订历史/Revision History
日期/Date 作者/Author 参考号/Ref 修订说明/Revision Description
-----------------------------------------------------------------------
其它说明:
***********************************************************************/
// 引入IIC通讯所需的Wire库文件
#include <Wire.h>
// 引入驱动OLED0.96所需的库
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // 设置OLED宽度,单位:像素
#define SCREEN_HEIGHT 64 // 设置OLED高度,单位:像素
// 自定义重置引脚,虽然教程未使用,但却是Adafruit_SSD1306库文件所必需的
#define OLED_RESET 4
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// 定义 I2C 引脚
#define OLED_SDA 7
#define OLED_SCL 6
// 定义超声波传感器的引脚
#define TRIGGER_PIN 5
#define ECHO_PIN 4
void setup()
{
// 初始化串口,用于调试
Serial.begin(115200);
Serial.println("Starting OLED Test");
// 使用 GPIO 6 和 GPIO 7 初始化 I2C
Wire.begin(OLED_SDA, OLED_SCL);
// 初始化OLED并设置其IIC地址为 0x3C
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
{
Serial.println("SSD1306 allocation failed");
for (;;)
; // 停止程序
}
// 清屏并设置默认显示内容
display.clearDisplay();
display.display();
// 设置超声波传感器的引脚模式
pinMode(TRIGGER_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
// 确保触发引脚初始为低
digitalWrite(TRIGGER_PIN, LOW);
}
void loop()
{
float distance = readUltrasonicDistance();
words_display(distance);
display.display();
}
void words_display(float distance)
{
// 清除屏幕
display.clearDisplay();
// 设置字体颜色,白色可见
display.setTextColor(WHITE);
// 设置字体大小
display.setTextSize(1);
// 设置光标位置
display.setCursor(0, 0);
display.print("TaichiMaker");
display.setCursor(0, 20);
display.print("time: ");
// 打印自开发板重置以来的秒数:
display.print(millis() / 1000);
display.print(" s");
display.setCursor(0, 40);
display.print("Distance: ");
display.print(distance);
display.print(" cm");
}
// 读取超声波传感器的距离
float readUltrasonicDistance()
{
// 发送超声波信号
digitalWrite(TRIGGER_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIGGER_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGGER_PIN, LOW);
// 读取回波时间
long duration = pulseIn(ECHO_PIN, HIGH);
// 将时间转换为距离(单位:厘米)
// 声速 343 m/s => 0.0343 cm/μs
// 距离 = (时间 * 声速) / 2
float distance = (duration * 0.0343) / 2;
return distance;
}
测试步骤
准备:
使用直尺在桌面上量出一个标准45CM的长度,然后使用刀片在桌子上刻上刻度。
测试:
分别使用 TOF传感器, 超声波传感器和雷达在刻度处对45CM处的挡板(纸片进行测距)并且得到数据
1- 使用超声波传感器
结果 44.54
2 - 使用TOF传感器
这里分为两种情况, 1 - 物体的表面不是黑色(即不吸光) 2- 物体的表面为黑色 (吸光)
反射物体表面不为黑色的测试结果(非常准确)
反射物体表面为黑色的测试结果(42.1 cm)
雷达的测试结果(我觉得专业的事情还是要让专业的传感器干,雷达也是重在参与。 36CM上下偏移)
总结
从这次测试结果上来看, TOF传感器的精度非常高, 在45CM的情况下,误差基本上可以忽略不记(测试中非常准确45CM)但是TOF传感器在反射物体为黑色的情况下,精度偏差的比较厉害。(421mm 对比 450MM)。 在实际的应用中,应该考虑到这种可能出现的误差情况。 比如说使用多个传感器来进行比对, 如果被测物体为黑色,则不使用TOF传感器。或者使用上图中的信号强度进行判断。 可以看到如果被测物体(发生光反射的物体)为非黑色的话,信号强度S 达到了32,但是如果为黑色的话,信号强度仅仅有8.48
- 2024-11-17
-
发表了主题帖:
X-NUCLEO-53L4A3 飞行时间 (ToF) 传感器 [SSD1306 显示距离, GUI软件测试]
本帖最后由 御坂10032号 于 2024-11-17 19:26 编辑
简介
在上一个章节中我开箱了 X-NUCLEO-53L4A3飞行时间 (ToF) 传感器, 也成功的烧写了Demo 和测试。但是由于我本身这次的测试目的是和其他的测距模块做对比, 比如雷达等。 它并不是十分方便的进行数据的显示。于是我翻箱倒柜的找了一下我的模块。 幸运的是手里正好有一个拓展版。上面板载了一个SSD1305 和一个ESP12-f 正好兼容Arduino 接口。于是我便把它简单的组装了一下。 使其将光照传感器的数据显示到SSD1306上. 那么这样的话就方便我来进行距离测试了。
拓展板正面
拓展板背面
组合在一起的图片
正文
由于这个拓展板使用的Arduino接口且SSD1306的通讯方式是I2C 因此只需要初始化下SCL和SDA就好。 TOF传感器的通讯方式也是I2C,但是我没有找到它的初始化代码在哪里。 所以我在系统初始化的时候直接初始化了I2C来用于屏幕的初始化。
整合起来也比较简单, 就是在Print_result 的时候调用SSD1306的显示函数来使用SSD的替换掉串口打印。
//static void print_result(RANGING_SENSOR_Result_t *Result)
//{
// uint8_t i;
// uint8_t j;
// for (i = 0; i < RANGING_SENSOR_MAX_NB_ZONES; i++)
// {
// printf("\nTargets = %lu", (unsigned long)Result->ZoneResult[i].NumberOfTargets);
// for (j = 0; j < Result->ZoneResult[i].NumberOfTargets; j++)
// {
// printf("\n |---> ");
// printf("Status = %ld, Distance = %5ld mm ",
// (long)Result->ZoneResult[i].Status[j],
// (long)Result->ZoneResult[i].Distance[j]);
// if (Profile.EnableAmbient)
// printf(", Ambient = %ld.%02ld kcps/spad",
// (long)Result->ZoneResult[i].Ambient[j],
// (long)decimal_part(Result->ZoneResult[i].Ambient[j]));
// if (Profile.EnableSignal)
// printf(", Signal = %ld.%02ld kcps/spad",
// (long)Result->ZoneResult[i].Signal[j],
// (long)decimal_part(Result->ZoneResult[i].Signal[j]));
// }
// }
// printf("\n");
//}
static void print_result(RANGING_SENSOR_Result_t *Result)
{
uint8_t j = 0;
uint8_t y_offset = 0;
char buffer[64];
ssd1306_Clear(&i2c1);
snprintf(buffer, sizeof(buffer), "Targets: %lu", (unsigned long)Result->ZoneResult[0].NumberOfTargets);
ssd1306_SetCursor(0, y_offset);
ssd1306_WriteString(buffer, Font_7x10, White);
y_offset += 10;
while (j < Result->ZoneResult[0].NumberOfTargets && y_offset < 64)
{
snprintf(buffer, sizeof(buffer), "D:%5ldmm S:%ld",
(long)Result->ZoneResult[0].Distance[j],
(long)Result->ZoneResult[0].Status[j]);
ssd1306_SetCursor(0, y_offset);
ssd1306_WriteString(buffer, Font_7x10, White);
y_offset += 10;
if (Profile.EnableAmbient)
{
snprintf(buffer, sizeof(buffer), "A:%ld.%02ldkcps",
(long)Result->ZoneResult[0].Ambient[j],
(long)decimal_part(Result->ZoneResult[0].Ambient[j]));
ssd1306_SetCursor(0, y_offset);
ssd1306_WriteString(buffer, Font_7x10, White);
y_offset += 10;
}
if (Profile.EnableSignal)
{
snprintf(buffer, sizeof(buffer), "S:%ld.%02ldkcps",
(long)Result->ZoneResult[0].Signal[j],
(long)decimal_part(Result->ZoneResult[0].Signal[j]));
ssd1306_SetCursor(0, y_offset);
ssd1306_WriteString(buffer, Font_7x10, White);
y_offset += 10;
}
j++;
}
ssd1306_UpdateScreen(&i2c1);
}
这样的话,当数据更新的时候便会在SSD1306上显示出来。
实际的效果如下:
[localvideo]c7b8e062db8a318361a4104a166adbc8[/localvideo]
需要注意的是, 这个传感器支持检测多个目标。但是目前我还没弄明白多个目标究竟是怎么检测的(我的意思是怎么会被识别为一个目标)。 在实际的测量环境中, 如果测量的长度比较短的话, 那么检测到的Target为1, 距离信息会显示在Target 1 的变量中. 如果超出某一个距离的时候,检测的target将会变成2,然后远距离目标的距离信息会显示在第二个target的距离变量里。 具体的效果可以查看上述视频。(具体的原理没有搞明白, 当然也有可能是根据距离的长短在代码中自动的调整target的排序, 也有可能是我SSD1306显示的问题)。
下图为VL53L4ED_GUI 软件检测到的目标信息。 这个上位机不好用, 不推荐使用。 建议根据镜花水月000大佬的帖子设置使用匿名助手来操作。
- 2024-11-06
-
回复了主题帖:
动手学深度学习(PyTorch版)- 【读书活动-心得分享】使用Softmax实现图像分类
Jacktang 发表于 2024-11-6 07:29
知道怎么使用torch的API,通过torch的内部定义的损失函数等等来训练模型,思路清晰,学习了
书中的原生实现的太难了. 看不懂
-
回复了主题帖:
X-NUCLEO-53L4A3 飞行时间 (ToF) 传感器 [开箱贴+ 资源整合 + 代码测试]
Jacktang 发表于 2024-11-6 07:27
竟然这个飞行时间传感器还具有ST官方的GUI工具,,这是可能的
我也是整理资料的时候看到的, 也不知道那个大佬就怎么找到的
-
回复了主题帖:
X-NUCLEO-53L4A3 飞行时间 (ToF) 传感器 [开箱贴+ 资源整合 + 代码测试]
lugl4313820 发表于 2024-11-6 10:43
这三个参数,我感觉是没有理解清楚,只知道一个距离。
你可以试试, 应该是可以设置成多目标检测的, 其他的大概都是环境的参数数据. 然后反映给状态来表明当前的测量的准确度
-
发表了主题帖:
X-NUCLEO-53L4A3 飞行时间 (ToF) 传感器 [开箱贴+ 资源整合 + 代码测试]
本帖最后由 御坂10032号 于 2024-11-6 06:29 编辑
简介
非常荣幸能够参加这次飞行时间传感器X-NUCLEO-53L4A3 测评。 本次测评的最终目标是使用飞行时间传感器和其他的市面上常见的测距雷达模块进行各方面的对比, 比如说
测距的精度和距离等。
开箱照片
由于之前没有使用过ST的官方的板子, 因此这次主要的资料的获取是根据这个包装盒上的ST的网站链接获取了。 花了好长时间下载完了下图的资料等。
原文是英文的, 上图经过了我的重命名。
解压上文的en.X-CUBE-TOF1 后便可以根据下图的截图找到当前板载的三个测试Demo
项目里提供了多种的工程环境,这里可以根据自己的环境进行选择。
我这里选择的是STM32CUBE-IDE
STM32CUBE-IDE的配置可以根据上图的顺序执行。 之后根据下图配置Debug 调试(下载)选项
之后我们点击下载Run new configuration 按钮便会将编译好的固件烧录到开发板中
飞行时间传感器简介
飞行时间(Time of Flight,ToF)传感器是一种通过测量光信号的飞行时间来确定物体与传感器之间距离的传感器。它发射一束光(通常是红外光或激光),光遇到物体后反射回传感器。传感器通过计算光从发射到返回的时间差,来确定目标的距离。
ToF传感器的工作原理基于光速和飞行时间的关系,即:距离 = (光速 / 飞行时间)/2
这里和那种常见的超声波模块对比就是 距离 = (声速 / 时间)/2
但是X-NUCLEO-53L4A3的精度和范围远远的超过了常见的超声波模块。 和普通的毫米波雷达。 测距的精度可以达到毫米级别 (下篇文章中测试) 。官方介绍它具有精确的绝对距离测量,不受目标反射率的影响(光的反射)
当我们将上述的代码烧录进入之后。 通过串口工具(波特率460800)打开的话。可以看到以下的信息。
我单独抽出来一个数据来介绍一下数据的格式
Targets = 1
|--->
Status = 0, Distance = 2175 mm , Ambient = 0.37 kcps/spad, Signal = 2.24 kcps/spad
没有找到具体的说明在哪里。 Target应该是检测到目标的数据量。 status应该是当前测试结果的状态。 Distance 为距离 Ambient 为环境光强度强度造成的噪声(我猜测的),Signal则为当前光的反射状态。
刚开始的时候烧录错了代码,然后查看了论坛其他大佬的评测贴。 发现竟然这个飞行时间传感器还具有ST官方的GUI工具。 等到下一个帖子里我们来复现一下GUI工具的测量和使用
附件(可能有用):
- 2024-11-05
-
发表了主题帖:
动手学深度学习(PyTorch版)- 【读书活动-心得分享】使用Softmax实现图像分类
简介
前几个章节我们实现了线性回归来对某一个数据值进行预测,本章节我们学习下如何使用softmax进行数据的分类。
这个章节的数学知识有点难, 我不是很懂具体的数学是怎么计算的, 但是大概要实现什么效果我还是可以理解的。 我就我自己的理解进行代码的分析。
trans = transforms.ToTensor()
mnist_train = torchvision.datasets.FashionMNIST(
root="../data", train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(
root="../data", train=False, transform=trans, download=True)
上述代码定义了一个数据集,即MNIST, 当执行上述的代码的时候会自动从http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/ 上下载对应的训练数据和测试数据
下载之后的训练数据集和测试数据集分别为
有图这个图像的数据只是为28 * 28 单通道。 所以每个图片的形状如下所示
之后定义了一个获取图像内所有的标签和显示图片的方法。
图像的标签数据其实在下载的时候就已经包含了。 这里不理解的是为什么这个Tshirt的和下载的时候的类型不一致
图像绘制的方法我这里也没有纠结, 因为看不懂是怎么绘制的。
之后我们可以加载小批量的测试数据进行数据的加载和展示。如果你使用的是pycharm 或者 dataspell, 记得勾选上述的文件为信任的 , 否则会出现图片无法绘制的异常
上图为信任模式下的正常绘制。 一共读取10 个数据, 两行 5 列。
后面的交叉熵和模型就开始有点听不懂了,于是对从0实现的softmax就没办法继续了。 之后我尝试了书里提供的使用pytorch实现的 softmax实现。
这里如果你使用的是pycharm 或者dataspell的话也会出现图片不加载的情况。 可以直接使用Jupyter来打开。
这里就很好理解了。 我只需要知道怎么使用torch的API即可, 我不需要去关注具体的算法实现。 然后通过torch的内部定义的损失函数等等来训练我的模型。
不过这里, 我全都是用CPU跑的, 我还尝试问GPT怎么转移到GPU上。但是没有成功。下图可以看到CPU的使用情况。E52666V3 十个核最高占用能跑到80%
通过下面的代码保存整个模型后,下次就不需要再训练了。
# 保存整个模型
torch.save(net, "softmax.pth")
模型大小大概33KB。
我们尝试加载这个模型然后随便找个图形来试一下是否能正常是被。
上图为一个chatgpt生成的28*28的图片。
它把我的T恤分类成包了。
加载训练数据的似乎没有问题。 不知道为什么没办法准确的识别除了训练和测试集外的数据。
import torch
from torch import nn
import torchvision.transforms as transforms
from PIL import Image
import matplotlib.pyplot as plt
# 定义Fashion-MNIST类别标签
def get_fashion_mnist_labels(labels):
"""返回Fashion-MNIST数据集的文本标签"""
text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
return [text_labels[int(i)] for i in labels]
# 1. 定义模型结构并加载参数
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))
net = torch.load("softmax.pth")
net.eval() # 将模型设置为评估模式
# 2. 定义图像预处理
transform = transforms.Compose([
transforms.Grayscale(), # 转换为灰度图像
transforms.Resize((28, 28)), # 调整大小为 28x28
transforms.ToTensor() # 转换为 tensor 并且归一化到 [0, 1]
])
# 3. 加载并预处理图像
image_path = "1.png" # 替换为你的图片路径
image = Image.open(image_path)
image = transform(image) # 应用预处理
image = image.unsqueeze(0) # 添加批量维度,使尺寸为 (1, 1, 28, 28)
# 4. 将图像传入模型进行预测
with torch.no_grad(): # 禁用梯度计算,节省内存
logits = net(image) # 获取输出的 logits
pred_idx = torch.argmax(logits, dim=1).item() # 找到概率最大的类别
pred_label = get_fashion_mnist_labels([pred_idx])[0] # 获取类别标签
# 5. 输出结果
print(f"预测类别: {pred_label}")
# 6. 显示图像和预测标签
plt.imshow(image.squeeze().numpy(), cmap="gray")
plt.title(f"预测类别: {pred_label}")
plt.axis("off")
plt.show()
鞋子的测试也错了, 不知道是因为我的图片不像一个鞋子还是怎么了
(上图一共训练了20轮)