RT-Thread+STM32实现智能车目标识别系统的教程

嵌入式资讯精选 2020-05-14 00:00

引言


这篇文档主要介绍 RT-Thread 如何使用串口或者无线和 ROS 连接,会包含这么些内容:

第一部分:ROS 环境搭建

第二部分:RT-Thread rosserial 软件包

第二部分:RT-Thread 添加 USART2 和 PWM

第三部分:RT-Thread 使用 ESP8266 AT 固件联网


这里先介绍一下什么是 ROS?为什么要和 ROS 连接?

机器人操作系统 ROS (Robots Operating System) 最早是斯坦福大学的一个软件框架,现在不管是工业机器人,还是娱乐用的机器人都运行着 ROS。

图片来源网络,如有侵权请联系删除

一个机器人通常有很多个部件、传感器,为了保证机器人不会因为某一个传感器故障,导致整个系统瘫痪,所以采用了分布式的节点,利用不同节点之间的通讯收集传感器数据和控制指令,这篇文档后面会使用到的通讯协议就是 rosserial
和 ROS 连接的好处在于,一方面由 ROS 管理各个机器人节点更稳定,另一方面 ROS 现在已经有了非常多成熟的软件包,使用 ROS 就可以非常方便的为自己的机器人添加摄像头图像识别、激光雷达建图导航等高级功能。
不过这篇文档只会涉及 RT-Thread 和 ROS 建立基本的连接,实现小车的运动控制,之后可能会有后续文档介绍如何连接激光雷达建图,并进行全局路径规划。

这篇文章假定大家都已经会用 RT-Thread 的 env 工具下载软件包,生成项目上传固件到 stm32 上,并且熟悉 Ubuntu 的基本使用。


1 ROS 简介



这里的开发环境搭建其实是需要搭建 2 份,一份是小车上的 ARM 开发板 (树莓派,NanoPi 什么的),另一个则是自己的电脑,因为我们希望把电脑作为 ROS 从节点,连接到小车上的 ROS 主节点,不过开发板和电脑的 ROS 安装是一模一样的。


既然要和 ROS 连接,那么首先就得要有一个正常运行的 ROS。安装 ROS 其实非常简单,这里推荐使用 Ubuntu 18 (开发板推荐系统用 Armbian),因为官方对 Ubuntu 的支持优先级是最高的,安装教程也可以参照  官网: http://wiki.ros.org/melodic/Installation/Ubuntu
只需要输入下面的 4 行命令,就在 Ubuntu 上装好了 ROS。
1sudo sh -c 'echo "deb https://mirror.tuna.tsinghua.edu.cn/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
2sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
3sudo apt update
4sudo apt install ros-melodic-ros-base
上面我使用了清华大学的镜像源,这样从国内下载 ROS 会快很多,而且我只安装了 ROS 的基本软件包,没有安装图形化软件包 gviz,gazebo 什么的,因为后面也没有用到。

1.2 ROS 环境初始化

ROS 安装好之后还需要进行初始化,不过也是只有短短几行命令:
1sudo rosdep init
2rosdep update
3
4echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
5source ~/.bashrc

1.3 启动 ROS
启动 ROS 的话我们需要确保它是常驻后台运行的,所以我们可以使用 tmux:
1roscore

在 tmux 里启动了 ROS 主节点后,我们就可以 Ctrl + B D 退出了,而 ROS 主节点依旧在后台运行。

1.4 参考文献

  • Armbian:https://www.armbian.com/
  • ROS Melodic 安装:http://wiki.ros.org/melodic/Installation/Ubuntu


2 RT-Thread 串口连接 ROS


这一部分会介绍如何使用串口将运行着 RT-Thread 的 STM32 开发板和运行着 ROS 的 ARM 开发板连接,看起来差不多就是这样。

这里说明一下不同开发板的分工,STM32 运行着 RT-Thread 负责控制电机,接收传感器信息;ARM 运行着 ROS 负责进行全局控制,例如给小车发出前进的指令。

2.1 RT-Thread 配置

首先我们需要打开 usart2,因为 usart1 被 msh 使用了,保留作为调试还是挺方便的。

在 CubeMX 里我打开了 USART2,另外还打开了 4 路 PWM,因为我后面使用了 2 个电机,每个电机需要 2 路 PWM 分别控制前进和后退。
接下来还需要在 menuconfig 里面打开对应的选项,考虑到有的开发板默认的 bsp 可能没有这些选项,可以修改 board/Kconfig 添加下面的内容。
串口的配置:
 1menuconfig BSP_USING_UART
2    bool "Enable UART"
3    default y
4    select RT_USING_SERIAL
5    if BSP_USING_UART
6        config BSP_USING_UART1
7            bool "Enable UART1"
8            default y
9
10        config BSP_UART1_RX_USING_DMA
11            bool "Enable UART1 RX DMA"
12            depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
13            default n
14
15        config BSP_USING_UART2
16            bool "Enable UART2"
17            default y
18
19        config BSP_UART2_RX_USING_DMA
20            bool "Enable UART2 RX DMA"
21            depends on BSP_USING_UART2 && RT_SERIAL_USING_DMA
22            default n
23    endif

PWM 的配置:
 1menuconfig BSP_USING_PWM
2    bool "Enable pwm"
3    default n
4    select RT_USING_PWM
5    if BSP_USING_PWM
6    menuconfig BSP_USING_PWM3
7        bool "Enable timer3 output pwm"
8        default n
9        if BSP_USING_PWM3
10            config BSP_USING_PWM3_CH1
11                bool "Enable PWM3 channel1"
12                default n
13            config BSP_USING_PWM3_CH2
14                bool "Enable PWM3 channel2"
15                default n
16            config BSP_USING_PWM3_CH3
17                bool "Enable PWM3 channel3"
18                default n
19            config BSP_USING_PWM3_CH4
20                bool "Enable PWM3 channel4"
21                default n
22        endif
23    endif

这样我们在 env 下就可以看到有对应的配置了,

除此之外,我们还需要选择 rosserial 软件包:

可以看到上面默认的串口就是 USART2,这样我们就可以生成对应的工程了:

1pkgs --update
2scons --target=mdk5 -s
如果我们打开 Keil 项目,首先需要把 main.c 修改为 main.cpp,因为 rosserial 很多数据格式的定义都是用 C++ 写的,所以如果要使用 rosserial 库,我们先得把后缀改为 cpp,这样 Keil 就会用 C++ 编译器编译。

下面是 main.cpp 的内容,其实就是初始化了电机,然后发布了 2 个话题 (topic),一个是 /vel_x 告诉 ROS 当前小车的速度,一个是 /turn_bias 告诉 ROS 当前小车的旋转速度。同时又订阅了一个话题 /cmd_vel,用来接收从 ROS 发出的控制指令。
代码不是特别长,我也添加了一些注释,所以这里就不一行行分析了。
 1#include <rtthread.h>
2#include <rtdevice.h>
3#include <board.h>
4
5#include <ros.h>
6#include <std_msgs/Float64.h>
7#include <geometry_msgs/Twist.h>
8#include "motors.h"
9
10ros::NodeHandle  nh;
11MotorControl mtr(1234);   //Motor
12
13bool msgRecieved = false;
14float velX = 0, turnBias = 0;
15char stat_log[200];
16
17// 接收到命令时的回调函数
18void velCBconst geometry_msgs::Twist& twist_msg) 
19
{
20  velX = twist_msg.linear.x;
21  turnBias = twist_msg.angular.z;
22  msgRecieved = true;
23}
24
25//Subscriber
26ros::Subscriber<geometry_msgs::Twist> sub("cmd_vel", velCB );
27
28//Publisher
29std_msgs::Float64 velX_tmp;
30std_msgs::Float64 turnBias_tmp;
31ros::Publisher xv("vel_x", &velX_tmp);
32ros::Publisher xt("turn_bias", &turnBias_tmp);
33
34static void rosserial_thread_entry(void *parameter)
35
{
36    //Init motors, specif>y the respective motor pins
37    mtr.initMotors();
38
39    //Init node>
40    nh.initNode();
41
42    // 订阅了一个话题 /cmd_vel 接收控制指令
43    nh.subscribe(sub);
44
45    // 发布了一个话题 /vel_x 告诉 ROS 小车速度
46    nh.advertise(xv);
47
48    // 发布了一个话题 /turn_bias 告诉 ROS 小车的旋转角速度
49    nh.advertise(xt);
50
51    mtr.stopMotors();
52
53    while (1)
54    {
55      // 如果接收到了控制指令
56      if (msgRecieved) 
57      {
58        velX *= mtr.maxSpd;
59        mtr.moveBot(velX, turnBias);
60        msgRecieved = false;
61      }
62
63      velX_tmp.data = velX;
64      turnBias_tmp.data = turnBias/mtr.turnFactor;
65
66      // 更新话题内容
67      xv.publish( &velX_tmp );
68      xt.publish( &turnBias_tmp );
69
70      nh.spinOnce();
71    }
72}
73
74int main(void)
75
{
76    // 启动一个线程用来和 ROS 通信
77    rt_thread_t thread = rt_thread_create("rosserial",     rosserial_thread_entry, RT_NULL, 2048810);
78    if(thread != RT_NULL)
79    {
80        rt_thread_startup(thread);
81        rt_kprintf("[rosserial] New thread rosserial\n");
82    }
83    else
84    {
85        rt_kprintf("[rosserial] Failed to create thread rosserial\n");
86    }
87    return RT_EOK;
88}

另外还有对应的电机控制的代码,不过这个大家的小车不同,驱动应当也不一样,我这里由于小车电机上没有编码器,所以全部是开环控制的。

motors.h
 1#include <rtthread.h>
2
3class MotorControl {
4  public:
5    //Var
6    rt_uint32_t  maxSpd;
7    float moveFactor;
8    float turnFactor;
9
10    MotorControl(int fl_for, int fl_back,
11                 int fr_for, int fr_back);
12    void initMotors();
13    void rotateBot(int dir, float spd);
14    void moveBot(float spd, float bias);
15    void stopMotors();
16  private:
17    struct rt_device_pwm *pwm_dev;
18    //The pins
19    int fl_for;
20    int fl_back;
21    int fr_for;
22    int fr_back;
23    int bl_for;
24    int bl_back;
25    int br_for;
26    int br_back;
27};

motors.c
 1#include <rtthread.h>
2#include <rtdevice.h>
3#include "motors.h"
4
5#define PWM_DEV_NAME "pwm3"
6
7MotorControl::MotorControl(int fl_for, int fl_back,
8                           int fr_for, int fr_back) 
9{
10    this->maxSpd = 500000;
11    this->moveFactor = 1.0;
12    this->turnFactor = 3.0;
13
14    this->fl_for = fl_for;
15    this->fl_back = fl_back;
16
17    this->fr_for = fr_for;
18    this->fr_back = fr_back;
19}
20
21void MotorControl::initMotors() {
22    /* 查找设备 */
23    this->pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
24    if (pwm_dev == RT_NULL)
25    {
26        rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME);
27    }
28    rt_kprintf("pwm found %s device!\n", PWM_DEV_NAME);
29    rt_pwm_set(pwm_dev, fl_for, maxSpd, 0);
30    rt_pwm_enable(pwm_dev, fl_for);
31
32    rt_pwm_set(pwm_dev, fl_back, maxSpd, 0);
33    rt_pwm_enable(pwm_dev, fl_back);
34
35    rt_pwm_set(pwm_dev, fr_for, maxSpd, 0);
36    rt_pwm_enable(pwm_dev, fr_for);
37
38    rt_pwm_set(pwm_dev, fr_back, maxSpd, 0);
39    rt_pwm_enable(pwm_dev, fr_back);
40}
41
42// 小车运动
43void MotorControl::moveBot(float spd, float bias) {
44    float sL = spd * maxSpd;
45    float sR = spd * maxSpd;
46    int dir = (spd > 0) ? 1 : 0;
47
48    if(bias != 0)
49    {
50        rotateBot((bias > 0) ? 1 : 0, bias);
51        return;
52    }
53
54    if( sL < -moveFactor * maxSpd)
55    {
56        sL = -moveFactor * maxSpd;
57    }
58    if( sL > moveFactor * maxSpd)
59    {
60        sL = moveFactor * maxSpd;
61    }
62
63    if( sR < -moveFactor * maxSpd)
64    {
65        sR = -moveFactor * maxSpd;
66    }
67    if( sR > moveFactor * maxSpd)
68    {
69        sR = moveFactor * maxSpd;
70    }
71
72    if (sL < 0
73    {
74        sL *= -1;
75    }
76
77    if (sR < 0
78    {
79        sR *= -1;
80    }
81
82    rt_kprintf("Speed Left: %ld\n", (rt_int32_t)sL);
83    rt_kprintf("Speed Right: %ld\n", (rt_int32_t)sR);
84
85    if(dir)
86    {
87        rt_pwm_set(pwm_dev, fl_for, maxSpd, (rt_int32_t)sL);
88        rt_pwm_set(pwm_dev, fl_back, maxSpd, 0);
89        rt_pwm_set(pwm_dev, fr_for, maxSpd, (rt_int32_t)sR);
90        rt_pwm_set(pwm_dev, fr_back, maxSpd, 0);
91    }
92    else
93    {
94        rt_pwm_set(pwm_dev, fl_for, maxSpd, 0);
95        rt_pwm_set(pwm_dev, fl_back, maxSpd, (rt_int32_t)sL);
96        rt_pwm_set(pwm_dev, fr_for, maxSpd, 0);
97        rt_pwm_set(pwm_dev, fr_back, maxSpd, (rt_int32_t)sR);
98    }
99
100    rt_thread_mdelay(1);
101}
102
103
104// 小车旋转
105void MotorControl::rotateBot(int dir, float spd) {
106    float s = spd * maxSpd;
107    if (dir < 0
108    {
109        s *= -1;
110    }
111    if(dir)
112    {
113        // Clockwise
114        rt_pwm_set(pwm_dev, fl_for, maxSpd, (rt_int32_t)s);
115        rt_pwm_set(pwm_dev, fl_back, maxSpd, 0);
116        rt_pwm_set(pwm_dev, fr_for, maxSpd, 0);
117        rt_pwm_set(pwm_dev, fr_back, maxSpd, (rt_int32_t)s);
118    }
119    else
120    {
121        // Counter Clockwise
122        rt_pwm_set(pwm_dev, fl_for, maxSpd, 0);
123        rt_pwm_set(pwm_dev, fl_back, maxSpd, (rt_int32_t)s);
124        rt_pwm_set(pwm_dev, fr_for, maxSpd, (rt_int32_t)s);
125        rt_pwm_set(pwm_dev, fr_back, maxSpd, 0);
126    }
127    rt_thread_mdelay(1);
128}
129
130//Turn off both motors
131void MotorControl::stopMotors() 
132{
133    rt_pwm_set(pwm_dev, fl_for, maxSpd, 0);
134    rt_pwm_set(pwm_dev, fl_back, maxSpd, 0);
135    rt_pwm_set(pwm_dev, fr_for, maxSpd, 0);
136    rt_pwm_set(pwm_dev, fr_back, maxSpd, 0);
137}
一共只需要这么一点代码就可以实现和 ROS 的连接了,所以其实 ROS 也不是那么神秘,它就是因为简单好用所以才这么受欢迎的。
既然 RT-Thread 已经配置好了,下一步就是 ROS 的配置了。

2.2 ROS 配置

我们把上面 RT-Thread 的固件传到板子上以后,可以用一个 USB-TTL 一边和 STM32 控制板的 USART2 连接,另一边插到 ARM 控制板的 USB 口,接下来就可以建立连接了,在 ARM 板上输入命令:
1$ rosrun rosserial_python serial_node.py /dev/ttyUSB0
如果看到下面的输出,那就成功建立连接了:
1tpl@nanopineoplus2:~$ rosrun rosserial_python serial_node.py /dev/ttyUSB0
2[INFO] [1567239474.258919]: ROS Serial Python Node
3[INFO] [1567239474.288435]: Connecting to /dev/ttyUSB0 at 57600 baud
4[INFO] [1567239476.425646]: Requesting topics...
5[INFO] [1567239476.464336]: Note: publish buffer size is 512 bytes
6[INFO] [1567239476.471349]: Setup publisher on vel_x [std_msgs/Float64]
7[INFO] [1567239476.489881]: Setup publisher on turn_bias [std_msgs/Float64]
8[INFO] [1567239476.777573]: Note: subscribe buffer size is 512 bytes
9[INFO] [1567239476.785032]: Setup subscriber on cmd_vel [geometry_msgs/Twist]

2.3 ROS 控制小车

既然已经成功建立连接了,下一步就是写小车控制的代码了。
我们先初始化一个工作区间:
1$ mkdir catkin_workspace && cd catkin_workspace
2$ catkin_init_workspace


接下来创建一个软件包:
1$ cd src
2$ catkin_create_pkg my_first_pkg rospy

这样就会自动在 src 目录创建一个 ROS 软件包了。
我们在 catkin_workspace/src/my_first_pkg/src 目录下新建一个文件 ros_cmd_vel_pub.py:
 1#!/usr/bin/python
2
3import rospy
4from geometry_msgs.msg import Twist
5from pynput.keyboard import Key, Listener
6
7vel = Twist()
8vel.linear.x = 0
9
10def on_press(key):
11
12    try:
13        if(key.char == 'w'):
14            print("Forward")
15            vel.linear.x = 0.8
16            vel.angular.z = 0
17
18        if(key.char == 's'):
19            print("Backward")
20            vel.linear.x = -0.8
21            vel.angular.z = 0
22
23        if(key.char == 'a'):
24            print("Counter Clockwise")
25            vel.linear.x = 0
26            vel.angular.z = -0.8
27
28        if(key.char == 'd'):
29            print("Clockwise")
30            vel.linear.x = 0
31            vel.angular.z = 0.8
32
33        return False
34
35    except AttributeError:
36        print('special key {0} pressed'.format(key))
37        return False
38
39def on_release(key):
40    vel.linear.x = 0
41    vel.angular.z = 0
42
43    return False
44
45# Init Node
46rospy.init_node('my_cmd_vel_publisher')
47pub = rospy.Publisher('cmd_vel', Twist, queue_size=10)
48
49# Set rate
50rate = rospy.Rate(10)
51
52listener = Listener(on_release=on_release, on_press = on_press)
53
54while not rospy.is_shutdown():
55    print(vel.linear.x)
56    pub.publish(vel)
57    vel.linear.x = 0
58    vel.angular.z = 0
59    rate.sleep()
60
61    if not listener.running:
62        listener = Listener(on_release=on_release, on_press = on_press)
63        listener.start()

这就是我们的 python 控制程序了,可以使用键盘的 wasd 控制小车前进后退,顺时针、逆时针旋转。我们需要给它添加可执行权限:
1$ chmod u+x ./ros_cmd_vel_pub.py

这样就可以编译软件包了,在 catkin_worspace 目录下。

1$ catkin_make
2$ source devel/setup.bash


我们终于就可以启动程序从电脑上控制小车运动了:
1rosrun my_first_pkg ros_cmd_vel_pub.py

可以看到用 ROS 实现小车控制其实代码量并不算多,只需要在自己小车原有的代码上发布一些话题,告诉 ROS 小车当前的状态,并且订阅一个话题接收 ROS 的控制指令就可以了。

2.4 参考文献

  • ros-pibot :https://github.com/wuhanstudio/ros-pibot


3 RT-Thread 无线连接 ROS


3.1 rosserial 配置

其实无线连接和有线连接几乎是一模一样的,只不过是先用 ESP8266 使自己的控制板能连上网,然后用 tcp 连接和 ROS 通信,关于 RT-Thread 使用 ESP8266 上网的教程可以参照  官网: https://www.rt-thread.org/document/site/application-note/components/at/an0014-at-client/ ,非常详细了,我这里就不重复了。
确保开发板有网络连接后,我们就可以在 rosserial 里面配置为使用 tcp 连接:

我们只需要在上一部分的 main.cpp 里添加一行代码:

1// 设置 ROS 的 IP 端口号
2nh.getHardware()->setConnection("192.168.1.210"11411);
3
4// 添加在节点初始化之前
5nh.initNode();
开发板就能通过 tcp 连接和 ROS 通信了,非常方便。

3.2 ROS 配置

由于我们使用了 tcp 连接,所以 ROS 上自然也要开启一个服务器了,之前是使用的串口建立连接,现在就是使用 tcp 了:
1$ rosrun rosserial_python serial_node.py tcp

其他的代码完全不需要改变,这样我们就实现了一个 ROS 无线控制的小车了。

3.3 参考文献

  • RT-Thread 使用 ESP8266 上网:

    https://www.rt-thread.org/document/site/application-note/components/at/an0014-at-client/


4 总结


这里再总结一下,其实 RT-Thread 使用 rosserial 软件包和 ROS 建立连接非常简单,只需要在自己小车原有代码的基础上发布一些消息,告诉 ROS 小车当前的状态,以及订阅来自 ROS 的控制指令就可以了。


1.2020年第5期《单片机与嵌入式系统应用》电子刊新鲜出炉!

2.为什么星链和5G是互补共荣,互相不能替代的两个大项目?

3.嵌入式系统:大数据和行业应用之间的桥梁

4.ARM的免费IP战略,能否撼动RISC-V的根基?

5.解读工信部25号文:蜂窝网包打物联网,LoRa真要凉凉了?

6.说说两个冷门却又不冷门的预处理指令#pragma和#error!

免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

嵌入式资讯精选 掌握最鲜资讯,尽领行业新风
评论 (0)
  • 汽车导航系统市场及应用环境参照调研机构GII的研究报告中的市场预测,全球汽车导航系统市场预计将于 2030年达到472亿美元的市场规模,而2024年至2030年的年复合成长率则为可观的6.7%。汽车导航系统无疑已成为智能汽车不可或缺的重要功能之一。随着人们在日常生活中对汽车导航功能的日渐依赖,一旦出现定位不准确或地图错误等问题,就可能导致车主开错路线,平白浪费更多行车时间,不仅造成行车不便,甚或可能引发交通事故的发生。有鉴于此,如果想要提供消费者完善的使用者体验,在车辆开发阶段便针对汽车导航功能
    百佳泰测试实验室 2025-03-27 14:51 249浏览
  • WT588F02B是广州唯创电子推出的一款高性能语音芯片,广泛应用于智能家电、安防设备、玩具等领域。然而,在实际开发中,用户可能会遇到烧录失败的问题,导致项目进度受阻。本文将从下载连线、文件容量、线路长度三大核心因素出发,深入分析烧录失败的原因并提供系统化的解决方案。一、检查下载器与芯片的物理连接问题表现烧录时提示"连接超时"或"设备未响应",或烧录进度条卡顿后报错。原因解析接口错位:WT588F02B采用SPI/UART双模通信,若下载器引脚定义与芯片引脚未严格对应(如TXD/RXD交叉错误)
    广州唯创电子 2025-03-26 09:05 154浏览
  • 在当今竞争激烈的工业环境中,效率和响应速度已成为企业制胜的关键。为了满足这一需求,我们隆重推出宏集Panorama COOX,这是Panorama Suite中首款集成的制造执行系统(MES)产品。这一创新产品将Panorama平台升级为全面的工业4.0解决方案,融合了工业SCADA和MES技术的双重优势,帮助企业实现生产效率和运营能力的全面提升。深度融合SCADA与MES,开启工业新纪元宏集Panorama COOX的诞生,源于我们对创新和卓越运营的不懈追求。通过战略性收购法国知名MES领域专
    宏集科技 2025-03-27 13:22 238浏览
  • 文/陈昊编辑/cc孙聪颖‍2025 年,作为中国实施制造强国战略第一个十年计划的关键里程碑,被赋予了极为重大的意义。两会政府工作报告清晰且坚定地指出,要全力加速新质生产力的发展进程,推动传统产业全方位向高端化、智能化与绿色化转型。基于此,有代表敏锐提议,中国制造应从前沿技术的应用切入,逐步拓展至产业生态的构建,最终延伸到提升用户体验的维度,打出独树一帜、具有鲜明特色的发展牌。正是在这样至关重要的时代背景之下,于 AWE 2025(中国家电及消费电子博览会)这一备受瞩目的舞台上,高端厨房的中国方案
    华尔街科技眼 2025-03-25 16:10 97浏览
  • 在嵌入式语音系统的开发过程中,广州唯创电子推出的WT588系列语音芯片凭借其优异的音质表现和灵活的编程特性,广泛应用于智能终端、工业控制、消费电子等领域。作为该系列芯片的关键状态指示信号,BUSY引脚的设计处理直接影响着系统交互的可靠性和功能拓展性。本文将从电路原理、应用场景、设计策略三个维度,深入解析BUSY引脚的技术特性及其工程实践要点。一、BUSY引脚工作原理与信号特性1.1 电气参数电平标准:输出3.3V TTL电平(与VDD同源)驱动能力:典型值±8mA(可直接驱动LED)响应延迟:语
    广州唯创电子 2025-03-26 09:26 224浏览
  • 在智能语音产品的开发过程中,麦克风阵列的选型直接决定了用户体验的优劣。广州唯创电子提供的单麦克风与双麦克风解决方案,为不同场景下的语音交互需求提供了灵活选择。本文将深入解析两种方案的性能差异、适用场景及工程实现要点,为开发者提供系统化的设计决策依据。一、基础参数对比分析维度单麦克风方案双麦克风方案BOM成本¥1.2-2.5元¥4.8-6.5元信噪比(1m)58-62dB65-68dB拾音角度全向360°波束成形±30°功耗8mW@3.3V15mW@3.3V典型响应延迟120ms80ms二、技术原
    广州唯创电子 2025-03-27 09:23 212浏览
  • 六西格玛首先是作为一个量度质量水平的指标,它代表了近乎完美的质量的水平。如果你每天都吃一个苹果,有一间水果店的老板跟你说,他们所卖的苹果,质量达到六西格玛水平,换言之,他们每卖一百万个苹果,只会有3.4个是坏的。你算了一下,发现你如果要从这个店里买到一个坏苹果,需要805年。你会还会选择其他店吗?首先发明六西格玛这个词的人——比尔·史密斯(Bill Smith)他是摩托罗拉(Motorloa)的工程师,在追求这个近乎完美的质量水平的时候,发明了一套方法模型,开始时是MAIC,后来慢慢演变成DMA
    优思学院 2025-03-27 11:47 191浏览
  • 案例概况在丹麦哥本哈根,西门子工程师们成功完成了一项高安全设施的数据集成项目。他们利用宏集Cogent DataHub软件,将高安全设施内的设备和仪器与远程监控位置连接起来,让技术人员能够在不违反安全规定、不引入未经授权人员的情况下,远程操作所需设备。突破OPC 服务器的远程连接难题该项目最初看似是一个常规的 OPC 应用:目标是将高安全性设施中的冷水机(chiller)设备及其 OPC DA 服务器,与远程监控站的两套 SCADA 系统(作为 OPC DA 客户端)连接起来。然而,在实际实施过
    宏集科技 2025-03-27 13:20 137浏览
  • 在电子设计中,电磁兼容性(EMC)是确保设备既能抵御外部电磁干扰(EMI),又不会对自身或周围环境产生过量电磁辐射的关键。电容器、电感和磁珠作为三大核心元件,通过不同的机制协同作用,有效抑制电磁干扰。以下是其原理和应用场景的详细解析:1. 电容器:高频噪声的“吸尘器”作用原理:电容器通过“通高频、阻低频”的特性,为高频噪声提供低阻抗路径到地,形成滤波效果。例如,在电源和地之间并联电容,可吸收电源中的高频纹波和瞬态干扰。关键应用场景:电源去耦:在IC电源引脚附近放置0.1μF陶瓷电容,滤除数字电路
    时源芯微 2025-03-27 11:19 206浏览
  • ​2025年3月27日​,贞光科技授权代理品牌紫光同芯正式发布新一代汽车安全芯片T97-415E。作为T97-315E的迭代升级产品,该芯片以大容量存储、全球化合规认证、双SPI接口协同为核心突破,直击智能网联汽车"多场景安全并行"与"出口合规"两大行业痛点,助力车企抢占智能驾驶与全球化市场双赛道。行业趋势锚定:三大升级回应智能化浪潮1. 大容量存储:破解车联网多任务瓶颈随着​车机功能泛在化​(数字钥匙、OTA、T-BOX等安全服务集成),传统安全芯片面临存储资源挤占难题。T97-415E创新性
    贞光科技 2025-03-27 13:50 189浏览
  • 长期以来,智能家居对于大众家庭而言就像空中楼阁一般,华而不实,更有甚者,还将智能家居认定为资本家的营销游戏。商家们举着“智慧家居、智慧办公”的口号,将原本价格亲民、能用几十年的家电器具包装成为了高档商品,而消费者们最终得到的却是家居设备之间缺乏互操作性、不同品牌生态之间互不兼容的碎片化体验。这种早期的生态割裂现象致使消费者们对智能家居兴趣缺失,也造就了“智能家居无用论”的刻板印象。然而,自Matter协议发布之后,“命运的齿轮”开始转动,智能家居中的生态割裂现象与品牌生态之间的隔阂正被基于IP架
    华普微HOPERF 2025-03-27 09:46 156浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦