微信小程序和ros2进行通信

news2024/9/26 1:28:08

微信小程序和ros2进行通信

  • 环境配置
    • ubuntu下安装ros2
    • ubuntu安装mqtt库
    • windows安装微信开发者工具
  • 主要功能模块介绍
    • ROS2基础程序讲解
    • 微信小程序基础程序讲解
  • 编译及运行ros2程序
  • 编译及运行微信小程序
  • 主要事项

  ROS2做为一款优秀的机器人操作系统软件,其搭载了丰富的机器人平台,是目前机器人领域应用最多的软件。微信做为一个大型社交软件,应用非常广泛,其中的小程序直接通过扫二维码进行加载,使用起来非常方便快捷。为了让手机端能够对机器人进行操作,于是通过微信小程序与ROS2通信的方式将两者联系在一起。
  ROS2在ubuntu的电脑上运行,而微信则运行在手机端,可以通过一个中间设备透传两者之间的消息的方式实现,笔者目前采用mqtt通信的方式进行,中间设备是 免费公共 MQTT 服务器 ,作为本次测试的 MQTT 服务器地址,服务器接入信息如下:

  • Broker: broker.emqx.io
  • TCP Port: 1883
  • SSL/TLS Port: 8883
    更多详情请访问 EMQX Cloud 官网,或查看EMQX Cloud 文档 。

环境配置

ubuntu下安装ros2

直接使用鱼香ros进行安装,安装脚本命令:

wget http://fishros.com/install -O fishros && . fishros

ubuntu安装mqtt库

git clone https://github.com/eclipse/paho.mqtt.c.git
cd paho.mqtt.c
mkdir build
cd build
cmake ..
make
sudo make install

windows安装微信开发者工具

进入官网下载windows版本的安装程序,保证C盘有1G的空闲空间,否则会出现安装失败的情况。

主要功能模块介绍

ROS2基础程序讲解

mqtt_c.hpp

#ifndef MQTT_C_HPP_
#define MQTT_C_HPP_

#include <iostream>
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include <functional>

#include "MQTTClient.h"

class Mqtt_C {
public:
    //加载类的静态函数或全局函数做为mqtt的回调函数
    Mqtt_C(char* address, char* client_id, char* user_name, char* password, char* topic, int qos, MQTTClient_messageArrived *callBack);
    
    //加载类的非静态函数做为mqtt的回调函数
    Mqtt_C(char* address, char* client_id, char* user_name, char* password, char* topic, int qos, std::function<void (void*, char*, int, MQTTClient_message*)> callBack);
    ~Mqtt_C();

    // 发送mqtt消息
    void publish(char *topic, char *payload);

private:
    bool connect_flag_;    //0表示连接失败,1表示成功
    long TIMEOUT = 10000;
    char* topic_;
    MQTTClient client_;
    int qos_;

    //待绑定的回调函数
    std::function<void (void*, char*, int, MQTTClient_message*)> callBackFun;

    //接受mqtt的回调函数
    static int on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message);
};

typedef Mqtt_C* Mqtt_C_Ptr;    //不能使用智能指针,否则会关闭mqtt连接

#endif

mqtt_c.cpp

#include "mqtt_c.hpp"

Mqtt_C::Mqtt_C(char* address, char* client_id, char* user_name, char* password, char* topic, int qos, MQTTClient_messageArrived *callBack)
: connect_flag_(0) {
    int rc;
    topic_ = topic;
    qos_ = qos;

    MQTTClient_create(&client_, address, client_id, 0, NULL);
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    conn_opts.username = user_name;
    conn_opts.password = password;

    //将全局函数或类的静态函数
    MQTTClient_setCallbacks(client_, NULL, NULL, callBack, NULL);

    if ((rc = MQTTClient_connect(client_, &conn_opts)) != MQTTCLIENT_SUCCESS) {
        std::cout << "Failed to connect, return code " << rc << std::endl;
        connect_flag_ = 0;
        return;
    } else {
        std::cout << "Connected to MQTT Broker!" << std::endl;
        connect_flag_ = 1;
    }
    // 开始订阅对应topic的消息
    MQTTClient_subscribe(client_, topic, qos);
}

Mqtt_C::Mqtt_C(char* address, char* client_id, char* user_name, char* password, char* topic, int qos, std::function<void (void*, char*, int, MQTTClient_message*)> callBack)
: connect_flag_(0)  {
    int rc;
    topic_ = topic;
    qos_ = qos;

    // 将需要回调的函数进行绑定
    callBackFun = callBack;

    MQTTClient_create(&client_, address, client_id, 0, NULL);
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    conn_opts.username = user_name;
    conn_opts.password = password;

    // 将类的this指针传入on_message函数中,以便静态函数调用类的非静态成员
    MQTTClient_setCallbacks(client_, this, NULL, on_message, NULL);

    if ((rc = MQTTClient_connect(client_, &conn_opts)) != MQTTCLIENT_SUCCESS) {
        std::cout << "Failed to connect, return code " << rc << std::endl;
        connect_flag_ = 0;
        return;
    } else {
        std::cout << "Connected to MQTT Broker!" << std::endl;
        connect_flag_ = 1;
    }
    // 开始订阅对应topic的消息
    MQTTClient_subscribe(client_, topic, qos);
}

Mqtt_C::~Mqtt_C() {
    if(connect_flag_ == 1) {
        MQTTClient_disconnect(client_, TIMEOUT);
        MQTTClient_destroy(&client_);
    }

    std::cout << "Close the mqtt connect" << std::endl;
}

void Mqtt_C::publish(char *topic, char *payload) {
    if(connect_flag_ == 1) {
        MQTTClient_message message = MQTTClient_message_initializer;
        message.payload = payload;
        message.payloadlen = strlen(payload);
        message.qos = qos_;
        message.retained = 0;
        MQTTClient_deliveryToken token;
        MQTTClient_publishMessage(client_, topic, &message, &token);
        MQTTClient_waitForCompletion(client_, token, TIMEOUT);
        std::cout << "Send " << payload << " to topic " << topic << std::endl;
    }
    else {
        std::cout << "Failed to connect" << std::endl;
    }
}

int Mqtt_C::on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
    // 调用绑定的回调函数
    Mqtt_C* ptr = (Mqtt_C*)context;
    ptr->callBackFun(context, topicName, topicLen, message);

    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);

    return 1;
}

main.cpp

#include <chrono>
#include <functional>
#include <memory>
#include <string>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

#include "MQTTClient.h"
#include "mqtt_c.hpp"

using namespace std::chrono_literals;

class MinimalPublisher : public rclcpp::Node {
public:
    MinimalPublisher() : Node("minimal_publisher") {
        // 初始化ros发布的消息
        publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);

        // 初始化mqtt的消息及加载回调函数
        mqtt_ = new Mqtt_C("tcp://broker.emqx.io:1883", "c-client", "test", "test", "/wechat_ros/mqtt", 0, std::bind(&MinimalPublisher::getMqttMessage, 
                                                                                                                     this,
                                                                                                                     std::placeholders::_1,
                                                                                                                     std::placeholders::_2,
                                                                                                                     std::placeholders::_3,
                                                                                                                     std::placeholders::_4));
    }
    
private:
    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
    
    Mqtt_C_Ptr mqtt_;

    // 定义mqtt的回调函数
    void getMqttMessage(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
        auto* payload = message->payload;
        std::cout << "Received " << (char*)(payload) << " from " << topicName << " topic" << std::endl;

        // 发布mqtt消息
        mqtt_->publish("/wechat_ros_return/mqtt", "ros2 to wechat");

        // 发布ros消息
        auto ros_message = std_msgs::msg::String();
        ros_message.data = (char*)(payload);
        RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", ros_message.data.c_str());
        publisher_->publish(ros_message);
    }
};

int main(int argc, char * argv[]) {
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<MinimalPublisher>());
    rclcpp::shutdown();
    return 0;
}

微信小程序基础程序讲解

微信小程序参考EMQ的demo,源程序

编译及运行ros2程序

mkdir ros2_ws
cd ros2_ws
mkdir src
cd src
git clone https://gitee.com/jdi-shen/wechat_to_ros2.git
cd ..
colcon build
export LD_LIBRARY_PATH=/usr/local/lib
source install/setup.bash
ros2 run ros2_end main

编译及运行微信小程序

在windows中下载源程序,运行微信开发者工具,加载源程序中的“wechat_robot”,勾选“不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书”,如同1所示。


图1

直接使用微信开发者工具中的模拟器或点击“真机调试”生成二维码,用手机微信扫描二维码运行。点击“连接”、“订阅”,然后点击“发布”,会在ros2终端中收到消息,同时手机小程序也会收到消息。至此实现了ros2和微信小程序之间的简单通信过程。

主要事项

  1. 在运行ros程序时,需要加载环境变量“export LD_LIBRARY_PATH=/usr/local/lib”;
  2. 所有源程序在gitee仓库,https://gitee.com/jdi-shen/wechat_to_ros2.git;
  3. 运行ros2程序的ubuntu系统和手机都需要连上互联网;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/129835.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深耕低代码领域20年,这个老牌低代码平台有多靠谱

编者按&#xff1a;市面上低代码平台多如牛毛&#xff0c;用户在选型低代码平台时该如何甄别&#xff1f;本文通过介绍20年的老品牌低代码平台的特性&#xff0c;展示了优秀第低代码平台的魅力。 关键词&#xff1a;老厂商&#xff0c;私有化部署&#xff0c;源码交付&#xf…

实现effect的stop和onStop功能

06_实现effect的stop和onStop功能 一、实现stop &#xff08;一&#xff09;单元测试 it(stop, () > {let dummy;const obj reactive({ prop: 1 });const runner effect(() > {dummy obj.prop;});obj.prop 2;expect(dummy).toBe(2);stop(runner);obj.prop 3;expe…

zookeeper学习笔记1(小D课堂)

win和linux双环境安装zookeeper 我们不点击这个download。 进行解压&#xff1a; 我们进入到conf目录。 我们给这个文件进行重命名。 接下来我们去打开它&#xff0c;去修改一下配置&#xff1a; 我们先去掉这部分注释。 去掉注释&#xff0c;一共就这些内容。 tickTime是我们的…

如何开通阿里云语音通知服务?

阿里云语音服务是阿里云为用户提供的一种通信服务的能力。支持快速发送语音通知服务。 安全级别更高&#xff0c;难窃取。支持大容量、高并发&#xff0c;稳定可靠。 一、如何开通阿里云语音服务&#xff1f; 注册阿里云平台账户&#xff1b;实名登记认证&#xff1b;阿里云语…

手把手教你 如何利用github搭建个人网站 无需服务器

目录 前言 准备工作 教程来啦&#xff01;&#xff01;&#xff01; 第一部分 第二部分 链接说明 前言 哈喽&#xff0c;大家好&#xff0c;我是木易巷。 今天给大家分享一下&#xff1a;如何使用GitHub创建自己的个人网站&#xff1f; 准备工作 需要使用GitHub&#xff0c;当…

【python】语法分析-化学分子式解析「编译原理」

题目 编写程序&#xff0c;计算化学分子式中元素的数目&#xff0c;并完成以下测试&#xff1a; atom_count(“He”) 1 atom_count(“H2”) 2 atom_count(“H2SO4”) 7 atom_count(“CH3COOH”) 8 atom_count(“NaCl”) 2 atom_count(“C60H60”) 120 参考语法 specie…

学习周报-20221230

文章目录一 如何设置字符集二 NFS配置文件父目录权限影响子目录三 对IP分组可以批量管理NFS客户端首先查看系统环境 [rootnfs-server ~]# cat /etc/redhat-release Red Hat Enterprise Linux release 8.7 (Ootpa) [rootnfs-server ~]# uname -r 4.18.0-425.3.1.el8.x86_64这是…

JAVA零基础小白学习免费教程day13-Collection数据结构

day13_JAVAOOP 课程目标 1. 【理解】集合的体系结构 2. 【掌握】Collection集合中常用的方法 3. 【理解】Iterator迭代器 4. 【掌握】增强for的使用 5. 【理解】List集合的特点 6. 【掌握】List集合中特有的方法 7. 【理解】LinkedList集合的特点 8. 【理解】LinkedList集合中…

解读YOLO v7的代码(二)训练数据的准备

在上一篇文章解读YOLO v7的代码(一)模型结构研究_gzroy的博客-CSDN博客&#xff0c;我对Yolo v7的模型结构进行了分析&#xff0c;那么这次我们将进一步研读代码的关键部分&#xff0c;学习是如何对模型进行训练的。 训练数据的准备是模型训练的关键&#xff0c;通常我们需要对…

保姆教程系列一、什么?Redis部署 so easy

系列文章目录 &#xff01;&#xff01;&#xff01;是的没错&#xff0c;胖友们&#xff0c;保姆教程系列又更新了&#xff01;&#xff01;&#xff01; 保姆教程系列一、Redis部署 so easy 保姆教程系列二、Redis高可用&#xff08;主从同步哨兵模式&#xff09; 保姆教程系…

(3)Qt中的变体数据类型(QVariant)

QVariant的使用 QVariant(变体数据类型)这个类很神奇&#xff0c;或者说方便。很多时候&#xff0c;需要几种不同的数据类型需要传递&#xff0c;如果用结构体&#xff0c;又不大方便&#xff0c;容器保存的也只是一种数据类型&#xff0c;而QVariant则可以统统搞定。QVariant …

ceph-mds文件系统操作指南

前言&#xff1a;ceph-mds文件系统操作&#xff0c;常规操作汇总&#xff0c;看这一篇就够了 一、文件系统简介 Ceph 文件系统 (CephFS) 是兼容 POSIX 标准的文件系统&#xff0c;在 Ceph 的分布式对象存储基础上构建&#xff0c;称为 RADOS&#xff08;可靠的自主分布式对象存…

用户级线程和内核级线程

线程的实现可以分为两类&#xff1a;用户级线程和内核级线程&#xff0c;后者又称为内核支持的线程或轻量级进程。在多线程操作系统中&#xff0c;各个系统的实现方式并不相同&#xff0c;在有的系统中实现了用户级线程&#xff0c;有的系统中实现了内核级线程。 用户级线程&am…

Python数据分析案例13——文本特征抽取(TfidfVectorizer)

在做机器学习的时候&#xff0c;构建特征变量有很多时候都是文本型的&#xff0c;比如电影分类的时候的电影标题&#xff0c;房价预测的时候房子地址&#xff0c;股吧评论等......都是文本类型的数据。 文本型数据怎么构建特征&#xff0c;它又不是分类变量不能直接独立热编码…

【再学Tensorflow2】TensorFlow2的模型训练组件(2)

TensorFlow2的模型训练组件&#xff08;2&#xff09;损失函数损失函数和正则化项Tensorflow2内置的损失函数自定义损失函数评估指标常用的内置评估指标自定义评估指标优化器优化器的使用使用optimizer.apply_gradients使用optimizer.minimize使用model.fitTensorflow2内置的优…

【nowcoder】笔试强训Day14

目录 一、选择题 二、编程题 2.1计算日期到天数转换 2.2幸运的袋子 一、选择题 1.定义学生、教师和课程的关系模式 S (S#,Sn,Sd,Dc,SA &#xff09;&#xff08;其属性分别为学号、姓名、所在系、所在系的系主任、年龄&#xff09;&#xff1b; C &#xff08; C#,Cn,P# &…

ansible的安装以及实例

目录 ansible的安装&#xff1a; 一、配置centos8基本源 二、配置epel 三、安装ansible 四、查看ansible是否安装以及版本 实例&#xff1a; 实例一&#xff1a;控制主机和受控主机通过root用户免密验证远程控制主机实施对应任务 实例二&#xff1a;控制主机连接受控主机…

SSH协议理论讲解

目录 基本概念 SSH协议的组成 SSH工作原理 SSH版本协商阶段&#xff08;确定V1版本或V2版本&#xff09; 算法协商阶段 密钥交换阶段 用户认证阶段 会话交互阶段 基本概念 SSH&#xff08;Secure Shell&#xff09;安全外壳协议&#xff0c;是一种用于在不安全网络上进…

Redisson实现延迟队列

k8s部署单点Redis (1)k8s部署redis的yaml文件 apiVersion: apps/v1 kind: Deployment metadata:creationTimestamp: nulllabels:app: redisname: redis spec:replicas: 1selector:matchLabels:app: redisstrategy: {}template:metadata:creationTimestamp: nulllabels:app: r…

Jmeter系统学习

Jmeter体系结构 Jmeter概念&#xff1a; 元件&#xff1a;每一个功能&#xff0c;例如Http请求&#xff0c;响应断言等。 组件&#xff1a;每一类元件的组合&#xff0c;例如采样器&#xff0c;配置元件。 Jmeter体系可以分为3个维度&#xff1a; X1--X5&#xff1a;负载模…