RT-Thread智能车目标识别系统连载教程——连接 ROS 小车控制(5)

一款手势识别控制的音乐播放器完整源码+说明(使用 RT-Thread 操作系统和中科蓝讯的 AB32VG1 开发板).zip 【资源说明】 1、该资源内项目代码都是经过测试运行成功,功能正常的情况下才上传的,请放心下载使用。 2、适用人群:主要针对计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、数学、电子信息等)的同学或企业员工下载使用,具有较高的学习借鉴价值。 3、不仅适合小白学习实战练习,也可作为大作业、课程设计、毕设项目、初期项目立项演示等,欢迎下载,互相学习,共同进步! 一款手势识别控制的音乐播放器源码+项目说明(使用 RT-Thread 操作系统和中科蓝讯的 AB32VG1 开发板,配合其他的模块).zip 立即下载

上期回顾:

RT-Thread智能车目标识别系统连载教程——手写体识别模型 (1)

RT-Thread智能车目标识别系统连载教程——训练卷积神经网络模型(2)

RT-Thread智能车目标识别系统连载教程——运行卷积神经网络模型(3)

RT-Thread智能车目标识别系统连载教程——Darknet 训练目标检测模型(4)

引言

这篇文档主要介绍 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(1, 2, 3, 4);   //Motor
12
13bool msgRecieved = false;
14float velX = 0, turnBias = 0;
15char stat_log[200];
16
17// 接收到命令时的回调函数
18void velCB( const 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, 2048, 8, 10);
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 的控制指令就可以了。

之后,还有一篇用 RT-Thread 和 ROS 连接,利用激光雷达生成的地图进行全局路径规划的文档,今天就到这里了,下期不见不散!

END

RT-Thread线上活动

1、【RT-Thread软件包应用开发赛】本次大赛的唯一要求就是在作品中使用RT-Thread及软件包开发相关应用,不限定硬件平台,自备硬件,代码和文档开源。共设18名奖励,一等奖还可获得价值3499元的RoboMaster S1一台!报名参赛请先仔细阅读以下参赛须知(点击即可跳转):

重磅!参加RT-Thread软件包应用开发赛,赢RoboMaster S1!

立即报名

2、RT-Thread能力认证考前线上培训,将于2019年10月21号正式开始,如果您有晋升、求职、寻找更好机会的需要,有深入学习和掌握RT-Thread的需求,请尽快垂询/报考!学生优惠价:168/人 

学生专属报名通道

能力认证官网链接:https://www.rt-thread.org/page/rac.html(在外部浏览器打开)

立即报名(非学生)

#题外话# 喜欢RT-Thread不要忘了在GitHub上留下你的STAR哦,你的star对我们来说非常重要!链接地址:https://github.com/RT-Thread/rt-thread

你可以添加微信17775983565为好友,注明:公司+姓名,拉进 RT-Thread 官方微信交流群

RT-Thread


让物联网终端的开发变得简单、快速,芯片的价值得到最大化发挥。Apache2.0协议,可免费在商业产品中使用,不需要公布源码,无潜在商业风险。

长按二维码,关注我们

点击“阅读原文”进入GitHub

【YOLOv11工业级实战】15. YOLOv11海洋监测实战:珊瑚礁健康评估(水下图像增强|机器人搭载) 摘要:本文针对珊瑚礁健康评估的海洋监测需求,基于YOLOv11提出解决方案,聚焦水下色偏、悬浮物干扰、珊瑚形态复杂三大难题。引用全球珊瑚礁监测网络(GCRMN)标准,采用CoralNet数据集,通过Jaffe-McGlamery物理模型引导增强与悬浮物去除算法,在浑浊水域(能见度<5m)实现87.3%的健康珊瑚识别率,藻类误判率低至7.2%。介绍了以BlueROV2水下机器人和Jetson AGX Orin为核心的部署方案,结合水下SLAM定位技术,实现珊瑚健康的实时评估与三维覆盖率计算。 阅读详情

相关推荐

TI IWR 6843 ISK 毫米波雷达开箱测试

TI IWR6843 ISK毫米波雷达上手体验,教程十分详细,对于新手很友好。

qq_57061492的博客 4032

RT-Thread智能车目标识别系统连载教程——训练卷积神经网络模型(2)

上期回顾:RT-Thread智能车目标识别系统连载教程——手写体识别模型 (1)这里会介绍如何训练图像领域应用非常广的卷积神经网络 (Convolutional Neural Netwo...

rtthreadiotos的博客 491

Go语言集成Ollama本地大模型:gollama库实战指南

在当今的AI应用开发中,大型语言模型(LLM)的集成已成为关键技术。其核心原理是通过API调用,将自然语言处理能力嵌入到各类应用中。从技术价值看,本地化部署的LLM解决了数据隐私、网络延迟和持续成本三大痛点,尤其适合处理敏感数据或对实时性要求高的场景。在工程实践中,开发者常使用专门的客户端库来简化与模型服务的交互,例如通过封装REST API、提供类型安全接口和流式处理支持,从而提升开发效率和代码健壮性。具体到Go语言生态,结合Ollama这一流行的本地大模型运行工具,可以实现完全离线、低延迟的AI功能集成

weixin_28728443的博客 604

RT-Thread智能车目标识别系统连载教程——手写体识别模型 (1)

前言这篇文档非常长所以我们会分成5篇来连载,因为机器学习并不是纯软件开发,简单地调用库函数 API,需要有一定的理论支撑,如果完全不介绍理论部分,可能就不知道为什么模型要...

FILLMOREad的博客 518

Cadence SIP Layout 简单教程-第一章

以摄像头模组软硬结合板为例,描述layout的整个完整过程,从而掌握基本技能。 第一章 准备工作 第一节 原理图不用说layout前需要绘制原理图,原理图不在本文讨论范围内,所以列为准备工作。 需要特别说明的是,绘制原理的最终目的是导出网络表,网络表中的重要参数footprint是让layout软件选择正确封装的关键,所以这里讲解一下原理图设置footprint的位置。在原理图中双击零件,...

whp1920的博客 1万+

第一天(点亮led灯+led灯闪烁)——Arduino uno R3 学习之旅

发光二极管(Light Emitting Diode,简称LED)是一种能够将电能转化为光能的固态的半导体器件。长脚为阳极短脚为阴极电流必须从长脚流入从短脚流出方可点亮LED##杜邦线杜邦线:是导线中的一种,杜邦线端部有两种接头形式:带针的一种称为公头,带孔的一种称为母头,如下图所示:说明:与电源相连接时,一般采用红色杜邦线,与地连接时采用黑色杜邦线。

qwsbcjendb的博客 1129

2022 RT-thread培训学习和心得(一)

RTT-Thread暑期学校痛苦四日游

qq_35452794的博客 1348

【ComfyUI】Wan 2.2 14B 首尾帧转视频 平滑过渡

本文介绍了基于 Wan2.2 ComfyUI 的视频生成工作流,通过预训练模型、提示词与参考图像的结合,实现高质量视频合成。工作流采用高低噪声模型与 LoRA 模块优化风格与细节,确保画面过渡平滑稳定。核心流程包括模型加载、图像输入、提示词编码、潜空间采样、解码与视频合成,最终生成动态转场视频。节点设计涵盖 CLIPTextEncode、KSamplerAdvanced 等关键模块,协同完成从文本到视频的全链路生成。正向提示词作为核心驱动力,直接影响视频的动作、镜头与画面变化。

Mr数据杨 1701

基于RT-Thread的CAN电机驱动板设计 (一)需求分析与硬件设计

本项目依托实验室机器人比赛,需要设计一个电机驱动板,控制8个CAN协议伺服电机。 PC上位机由串口通过485协议发送电机转矩指令到电机驱动板,电机驱动板对指令解码并通过CAN总线发送转矩控制指令。 需求分析 ...

张竞豪的博客 2009

5G Multicast/Broadcast Services(MBS) (七) MBS广播DRX

当处于RRC_IDLE或RRC_INACTIVE或RRC_CONNECTED 状态时,如果为 G-RNTI 配置了broadcast DRX,则允许MAC entity使用broadcast DRX 操作不连续地监听此G-RNTI的PDCCH;此 G-RNTI 的 drx-onDurationTimerPTM 或 drx-InactivityTimerPTM 正在运行的时间,也就是。long DRX周期drx-LongCycle-PTM和drx-StartOffset-PTM定义DRX周期开始的子帧。

asd199086的博客 391

【基础演练】Playwright 极简复习:作为 AI-RPA 底座的 Playwright 核心用法

摘要: 2026年,Playwright已从测试工具升级为AI-RPA标准执行底座,周下载量超3300万,被browser-use等AI Agent项目广泛采用。其核心架构通过Playwright Server实现多浏览器协议适配,支持远程连接与高并发隔离(BrowserContext)。自动等待机制显著提升稳定性,但高频交互场景可能需直接使用CDP协议。Playwright凭借跨浏览器兼容性、轻量级隔离和微软官方支持,成为测试、RPA和AI Agent领域的事实标准,未来将主导对话式自动化市场。

ZDQ58818的博客 236

RT-Thread智能车目标识别系统连载教程——运行卷积神经网络模型(3)

上期回顾:这一部分会介绍模型训练好之后要如何使用,也就是模型的推断过程 (Inference)3.1 Python 导入模型并运行我们先用 python 加载模型,看看用...

FILLMOREad的博客 1094

[QMT量化交易小白入门]-七十三、主力资金动向:板块与个股资金流数据API(量化python代码解析)

本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。

木头大左的博客 1111

开源|智能车目标识别系统连载教程—RT-Thread连接ROS摄像头小车控制(6)

上期回顾:RT-Thread智能车目标识别系统连载教程——手写体识别模型 (1)RT-Thread智能车目标识别系统连载教程——训练卷积神经网络模型(2)RT-Thread智能车目标识别...

rtthreadiotos的博客 1000

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

开源|RT-Thread 搭配 ROS 实现目标检测小车完结篇

往期回顾:引言这应当是 RT-Thread 搭配 ROS 做摄像头小车的最后一篇文档了,这篇文档会把之前的内容汇聚起来,实现一个能目标检测的小车。先总结一下之前几篇文档的...

FILLMOREad的博客 2633

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

【文章回看】公众号系列文章合辑

感谢大家的关注,在这里提前祝您五一劳动节快乐~本期我们特别筛选了公众号历史推送中部分的精彩内容,欢迎大家回看!目前公众号内容包括但不限于(由于内容太多只能筛选部分系列内容,有其他需要的小...

FILLMOREad的博客 817

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

嵌入式使用RTOS到底是不是大势所趋?

嵌入式设备网络化、功能复杂化的趋势,使越来越多的、过去可以用裸奔实现的嵌入式产品,产生了应用操作系统的需求。芯片成本的连续下降,以及cpu性能和内存资源...

Peter的专栏 1005

paddle lite 嵌入式linux_【嵌入式AI入门日记】将 AI 模型移植到 RTThread 上

本期我们分享的主题是如何将 AI 模型部署到嵌入式系统中。 嵌入式关联 AIAI落地一直是一个很红火的前景和朝阳行业。我的好奇心也比较旺盛,所以关于任何嵌入式和 AI 相关的都是想尝一尝。本系列文章将带你一步一步把 AI 模型部署在嵌入式平台,移植到 RT-Thread 操作系统上,实现你从菜鸟到起飞的第一步甚至第 n 步!开发环境:后续开发过程将基于 STM32H743ZI-Nucl...

weixin_39605296的博客 648

Magicodes.WeiChat——版本发布历史

购买地址:https://item.taobao.com/item.htm?id=520205558575 您可以在新标签页打开此图,以查看原始图片。 Magicodes.WeiChat为湖南心莱信息科技有限公司Magicodes系列产品之一,已获得软件著作权证书。 VNext 重构支付模块,独立支付模块 发布小程序SDK 重构支付回调模块,统一支付回调并且支持微信回调和支付宝回调逻辑的合并 ...

weixin_34268753的博客 362

Python网络爬虫识记

第一章:爬虫介绍 什么是爬虫: 爬虫是一个模拟人类请求网站行为的程序。可以自动请求网页、并把数据抓取下来,然后使用一定的规则提取有价值的数据。 爬虫应用场景: 搜索引擎(百度或谷歌等) 伯乐在线。 惠惠购物助手。 数据分析。 抢票软件等。 为什么用Python写爬虫: PHP:PHP是世界是最好的语言,但他天生不是做这个的,而且对多线程、异步支持不是很好,并发处理能力弱。爬虫是工具性程序,对速度和效率要求比较高。 Java:生态圈很完善,是Python爬虫最大的竞争对手。但是Java语言本身很笨重,代

CoderOne 4772

让你了解操作系统基本概念

前言:本文是《操作系统教程(陈怀临注释)》的读书笔记,陈首席是在原书pdf 图片上注解,字体比较模糊,故我把注释中觉得比较重要的片段摘录下来。读完此文可以让非技术人员对操作系统有框架性的认识,也可以唤起技术人员记忆中某些概念片段,实际上很多概念我也理解得有点模糊,大家一起学习。:) 博客地址 1、OS其实是概念多于理论,技术多于算法。因此把握OS最重要的是把握概念,特别是概念的层次化。

perry_Fan 2万+

Qiime学习1

Log InQIIME2中文帮助文档 (Chinese Manual)Community ContributionsTranslationsin-progress installThis is the official forum for discussion of QIIME 2. If you’re looking for help with QIIME 1, please go to the...

u011562479的博客 6710

TowardsDataScience 博客中文翻译 2019(三百一十八)

你做错了旅游。不相信我?我可以证明。如果你是一个旅行者,你会知道在旅游景点的郊区看到小孩子卖纪念品是很常见的事情。有时小贩的孩子会变得好斗,即使他们不会说你的语言。它们都很可爱,以至于你很想让步买些东西……但你没有——可能是因为你并不真正需要那些纪念品,也可能是因为你的导游告诉你不要买。很多人对此感到内疚。我承认我也是。回到 12 月,我去了趟柬埔寨,在那里我们参观了很多很多寺庙,看到很多可爱的小孩在卖小饰品,大部分是在吴哥窟。

龙哥盟 3918

RTThread IO组件 GPIO

本文主要了解GPIO的实现drv_gpio.c文件的粗略分析 drv_gpio.c文件的粗略分析 在menuconfig图形配置中,我们可以看到components->Device Drivers->using generic GPIO device drivers中有开启。该文件只管一般的GPIO配置,不包括外设复用配置。 进来首先看到pin[]的声明,这里将IO口抽象为编号。我们使...

qq_24381977的博客 1568
上一篇: 物联网操作系统RT-Thread免费12城巡回培训报名啦
下一篇: 软件包大赏第12期 | SMTP软件包,让你的设备实现“书信往来”
RT-Thread物联网操作系统
博客等级 码龄6年 2万+粉丝 392原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值