PX4二次开发快速入门(三):自定义串口驱动

2024-05-03 23:04

本文主要是介绍PX4二次开发快速入门(三):自定义串口驱动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言

前言

软件:PX4 1.14.0稳定版
硬件:纳雷NRA12,pixhawk4
仿照原生固件tfmini的驱动进行编写
源码地址:
https://gitee.com/Mbot_admin/px4-1.14.0-csdn

修改
src/drivers/distance_sensor/CMakeLists.txt
添加

add_subdirectory(nra12)

修改
src/drivers/distance_sensor/Kconfig
添加

select DRIVERS_DISTANCE_SENSOR_NRA12

在src/drivers/distance_sensor/目录下添加一个nra12文件夹
在nra12文件夹下添加Kconfig,NRA12.cpp,NRA12.hpp,nra12_main.cpp,module.yaml,nra12_parser.cpp,nra12_parser.h。

Kconfig如下:

menuconfig DRIVERS_DISTANCE_SENSOR_NRA12bool "nra12"default n---help---Enable support for nra12

NRA12.cpp如下:

#include "NRA12.hpp"#include <lib/drivers/device/Device.hpp>
#include <fcntl.h>NRA12::NRA12(const char *port, uint8_t rotation) :ScheduledWorkItem(MODULE_NAME, px4::serial_port_to_wq(port)),_px4_rangefinder(0, rotation)
{// store port namestrncpy(_port, port, sizeof(_port) - 1);// enforce null termination_port[sizeof(_port) - 1] = '\0';device::Device::DeviceId device_id;device_id.devid_s.devtype = DRV_DIST_DEVTYPE_NRA12;device_id.devid_s.bus_type = device::Device::DeviceBusType_SERIAL;uint8_t bus_num = atoi(&_port[strlen(_port) - 1]); // Assuming '/dev/ttySx'if (bus_num < 10) {device_id.devid_s.bus = bus_num;}_px4_rangefinder.set_device_id(device_id.devid);_px4_rangefinder.set_rangefinder_type(distance_sensor_s::MAV_DISTANCE_SENSOR_LASER);
}NRA12::~NRA12()
{// make sure we are truly inactivestop();perf_free(_sample_perf);perf_free(_comms_errors);
}int
NRA12::init()
{int32_t hw_model = 1; // only one model so far...switch (hw_model) {case 1: // NRA12 (12m, 100 Hz)// Note:// Sensor specification shows 0.3m as minimum, but in practice// 0.3 is too close to minimum so chattering of invalid sensor decision// is happening sometimes. this cause EKF to believe inconsistent range readings.// So we set 0.4 as valid minimum._px4_rangefinder.set_min_distance(0.1f);_px4_rangefinder.set_max_distance(30.0f);_px4_rangefinder.set_fov(math::radians(1.15f));break;default:PX4_ERR("invalid HW model %" PRId32 ".", hw_model);return -1;}// statusint ret = 0;do { // create a scope to handle exit conditions using break// open fd_fd = ::open(_port, O_RDWR | O_NOCTTY);if (_fd < 0) {PX4_ERR("Error opening fd");return -1;}// baudrate 115200, 8 bits, no parity, 1 stop bitunsigned speed = B115200;termios uart_config{};int termios_state{};tcgetattr(_fd, &uart_config);// clear ONLCR flag (which appends a CR for every LF)uart_config.c_oflag &= ~ONLCR;// set baud rateif ((termios_state = cfsetispeed(&uart_config, speed)) < 0) {PX4_ERR("CFG: %d ISPD", termios_state);ret = -1;break;}if ((termios_state = cfsetospeed(&uart_config, speed)) < 0) {PX4_ERR("CFG: %d OSPD\n", termios_state);ret = -1;break;}if ((termios_state = tcsetattr(_fd, TCSANOW, &uart_config)) < 0) {PX4_ERR("baud %d ATTR", termios_state);ret = -1;break;}uart_config.c_cflag |= (CLOCAL | CREAD);	// ignore modem controlsuart_config.c_cflag &= ~CSIZE;uart_config.c_cflag |= CS8;			// 8-bit charactersuart_config.c_cflag &= ~PARENB;			// no parity bituart_config.c_cflag &= ~CSTOPB;			// only need 1 stop bituart_config.c_cflag &= ~CRTSCTS;		// no hardware flowcontrol// setup for non-canonical modeuart_config.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);uart_config.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);uart_config.c_oflag &= ~OPOST;// fetch bytes as they become availableuart_config.c_cc[VMIN] = 1;uart_config.c_cc[VTIME] = 1;if (_fd < 0) {PX4_ERR("FAIL: laser fd");ret = -1;break;}} while (0);// close the fd::close(_fd);_fd = -1;if (ret == PX4_OK) {start();}return ret;
}int
NRA12::collect()
{perf_begin(_sample_perf);// clear buffer if last read was too long agoint64_t read_elapsed = hrt_elapsed_time(&_last_read);// the buffer for read chars is buflen minus null terminationchar readbuf[sizeof(_linebuf)] {};unsigned readlen = sizeof(readbuf) - 1;int ret = 0;float distance_m = -1.0f;// Check the number of bytes available in the bufferint bytes_available = 0;::ioctl(_fd, FIONREAD, (unsigned long)&bytes_available);if (!bytes_available) {perf_end(_sample_perf);return 0;}// parse entire bufferconst hrt_abstime timestamp_sample = hrt_absolute_time();do {// read from the sensor (uart buffer)ret = ::read(_fd, &readbuf[0], readlen);
// ret = ::write(_fd,&readbuf,10);
// if (ret < 0) {
//     PX4_ERR("write err: %d", ret);
// }if (ret < 0) {PX4_ERR("read err: %d", ret);perf_count(_comms_errors);perf_end(_sample_perf);// only throw an error if we time outif (read_elapsed > (kCONVERSIONINTERVAL * 2)) {/* flush anything in RX buffer */tcflush(_fd, TCIFLUSH);return ret;} else {return -EAGAIN;}}_last_read = hrt_absolute_time();// parse bufferfor (int i = 0; i < ret; i++) {// PX4_INFO("readbuf=%x\n",readbuf[i]);// PX4_INFO("ret=%d\n",ret);// PX4_INFO("bytes_available=%d\n",bytes_available);nra12_parse(readbuf[i], _linebuf, &_linebuf_index, &_parse_state, &distance_m);}// bytes left to parsebytes_available -= ret;} while (bytes_available > 0);// no valid measurement after parsing bufferif (distance_m < 0.0f){perf_end(_sample_perf);return -EAGAIN;}// publish most recent valid measurement from buffer_px4_rangefinder.update(timestamp_sample, distance_m);perf_end(_sample_perf);return PX4_OK;
}void
NRA12::start()
{// schedule a cycle to start things (the sensor sends at 100Hz, but we run a bit faster to avoid missing data)ScheduleOnInterval(7_ms);
}void
NRA12::stop()
{ScheduleClear();
}void
NRA12::Run()
{// fds initialized?if (_fd < 0) {// open fd_fd = ::open(_port, O_RDWR | O_NOCTTY);}// perform collectionif (collect() == -EAGAIN) {// reschedule to grab the missing bits, time to transmit 9 bytes @ 115200 bpsScheduleClear();ScheduleOnInterval(7_ms, 87 * 9);return;}
}void
NRA12::print_info()
{printf("Using port '%s'\n", _port);perf_print_counter(_sample_perf);perf_print_counter(_comms_errors);
}

NRA12.hpp如下:

#pragma once#include <termios.h>#include <drivers/drv_hrt.h>
#include <lib/perf/perf_counter.h>
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/module.h>
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp>
#include <lib/drivers/rangefinder/PX4Rangefinder.hpp>
#include <uORB/topics/distance_sensor.h>#include "nra12_parser.h"#define NRA12_DEFAULT_PORT	"/dev/ttyS3"using namespace time_literals;class NRA12 : public px4::ScheduledWorkItem
{
public:NRA12(const char *port, uint8_t rotation = distance_sensor_s::ROTATION_DOWNWARD_FACING);virtual ~NRA12();int init();void print_info();private:int collect();void Run() override;void start();void stop();PX4Rangefinder	_px4_rangefinder;NRA12_PARSE_STATE _parse_state {NRA12_PARSE_STATE::STATE0_UNSYNC};char _linebuf[24] {};char _port[20] {};static constexpr int kCONVERSIONINTERVAL{9_ms};int _fd{-1};unsigned int _linebuf_index{0};hrt_abstime _last_read{0};perf_counter_t _comms_errors{perf_alloc(PC_COUNT, MODULE_NAME": com_err")};perf_counter_t _sample_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": read")};};

module.yaml 如下:

module_name: nanoradar nra12 lidar
serial_config:- command: nra12 start -d ${SERIAL_DEV}port_config_param:name: SENS_NRA12_CFGgroup: Sensors

nra12_main.cpp如下:

#include "NRA12.hpp"#include <px4_platform_common/getopt.h>/*** Local functions in support of the shell command.*/
namespace nra12
{NRA12	*g_dev{nullptr};int start(const char *port, uint8_t rotation);
int status();
int stop();
int usage();int
start(const char *port, uint8_t rotation)
{if (g_dev != nullptr) {PX4_ERR("already started");return PX4_OK;}// Instantiate the driver.g_dev = new NRA12(port, rotation);if (g_dev == nullptr) {PX4_ERR("driver start failed");return PX4_ERROR;}if (OK != g_dev->init()) {PX4_ERR("driver start failed");delete g_dev;g_dev = nullptr;return PX4_ERROR;}return PX4_OK;
}int
status()
{if (g_dev == nullptr) {PX4_ERR("driver not running");return 1;}printf("state @ %p\n", g_dev);g_dev->print_info();return 0;
}int stop()
{if (g_dev != nullptr) {PX4_INFO("stopping driver");delete g_dev;g_dev = nullptr;PX4_INFO("driver stopped");} else {PX4_ERR("driver not running");return 1;}return PX4_OK;
}int
usage()
{PRINT_MODULE_DESCRIPTION(R"DESCR_STR(
### DescriptionSerial bus driver for the Benewake NRA12 LiDAR.Most boards are configured to enable/start the driver on a specified UART using the SENS_NRA12_CFG parameter.Setup/usage information: https://docs.px4.io/master/en/sensor/sonar.html### ExamplesAttempt to start driver on a specified serial device.
$ sonar start -d /dev/ttyS1
Stop driver
$ sonar stop
)DESCR_STR");PRINT_MODULE_USAGE_NAME("nra12", "driver");PRINT_MODULE_USAGE_SUBCATEGORY("distance_sensor");PRINT_MODULE_USAGE_COMMAND_DESCR("start","Start driver");PRINT_MODULE_USAGE_PARAM_STRING('d', nullptr, nullptr, "Serial device", false);PRINT_MODULE_USAGE_PARAM_INT('R', 25, 0, 25, "Sensor rotation - downward facing by default", true);PRINT_MODULE_USAGE_COMMAND_DESCR("status","Driver status");PRINT_MODULE_USAGE_COMMAND_DESCR("stop","Stop driver");PRINT_MODULE_USAGE_COMMAND_DESCR("test","Test driver (basic functional tests)");PRINT_MODULE_USAGE_COMMAND_DESCR("status","Print driver status");return PX4_OK;
}} // namespaceextern "C" __EXPORT int nra12_main(int argc, char *argv[])
{int ch = 0;uint8_t rotation = distance_sensor_s::ROTATION_DOWNWARD_FACING;const char *device_path = NRA12_DEFAULT_PORT;int myoptind = 1;const char *myoptarg = nullptr;while ((ch = px4_getopt(argc, argv, "R:d:", &myoptind, &myoptarg)) != EOF) {switch (ch) {case 'R':rotation = (uint8_t)atoi(myoptarg);break;case 'd':device_path = myoptarg;break;default:PX4_WARN("Unknown option!");return PX4_ERROR;}}if (myoptind >= argc) {PX4_ERR("unrecognized command");return nra12::usage();}if (!strcmp(argv[myoptind], "start")) {if (strcmp(device_path, "") != 0) {return nra12::start(device_path, rotation);} else {PX4_WARN("Please specify device path!");return nra12::usage();}} else if (!strcmp(argv[myoptind], "stop")) {return nra12::stop();} else if (!strcmp(argv[myoptind], "status")) {return nra12::status();}return nra12::usage();
}

nra12_parser.cpp如下:

#include "nra12_parser.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <termios.h>#include <drivers/drv_hrt.h>
#include <lib/perf/perf_counter.h>
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/module.h>//#define NRA12_DEBUG#ifdef NRA12_DEBUG
#include <stdio.h>const char *parser_state[] = {"0_UNSYNC","3_GOT_DIST_L","4_GOT_DIST_H","8_GOT_QUALITY""9_GOT_CHECKSUM"
};
#endifint nra12_parse(char c, char *parserbuf, unsigned *parserbuf_index, NRA12_PARSE_STATE *state, float *dist)
{int ret = -1;//char *end;
// PX4_INFO("parse");switch (*state) {case NRA12_PARSE_STATE::STATE12_GOT_END2:// PX4_INFO("STATE12_GOT_END2");// PX4_INFO("c=%x",c);if (c == 0xaa) {*state = NRA12_PARSE_STATE::STATE1_GOT_START1;} else {*state = NRA12_PARSE_STATE::STATE0_UNSYNC;}break;case NRA12_PARSE_STATE::STATE0_UNSYNC:// PX4_INFO("STATE0_UNSYNC");// PX4_INFO("c=%x",c);if (c == 0xaa) {*state = NRA12_PARSE_STATE::STATE1_GOT_START1;}break;case NRA12_PARSE_STATE::STATE1_GOT_START1:// PX4_INFO("STATE1_GOT_START1");// PX4_INFO("c=%x",c);if (c == 0xaa) {*state = NRA12_PARSE_STATE::STATE2_GOT_START2;}else{*state = NRA12_PARSE_STATE::STATE0_UNSYNC;}break;case NRA12_PARSE_STATE::STATE2_GOT_START2:// PX4_INFO("STATE2_GOT_START2");// PX4_INFO("c=%x",c);if(c == 0x0c){*state = NRA12_PARSE_STATE::STATE2_GOT_0C;}else{*state = NRA12_PARSE_STATE::STATE0_UNSYNC;}break;case NRA12_PARSE_STATE::STATE2_GOT_0C:// PX4_INFO("STATE2_GOT_0C");// PX4_INFO("c=%x",c);if(c == 0x07){*state = NRA12_PARSE_STATE::STATE2_GOT_07;}else{*state = NRA12_PARSE_STATE::STATE0_UNSYNC;}break;case NRA12_PARSE_STATE::STATE2_GOT_07:// PX4_INFO("STATE2_GOT_07");// PX4_INFO("c=%x",c);*state = NRA12_PARSE_STATE::STATE3_GOT_Index;break;case NRA12_PARSE_STATE::STATE3_GOT_Index:// PX4_INFO("STATE3_GOT_Index");// PX4_INFO("c=%x",c);*state = NRA12_PARSE_STATE::STATE4_GOT_Res;break;case NRA12_PARSE_STATE::STATE4_GOT_Res:// PX4_INFO("STATE4_GOT_Res");// PX4_INFO("c=%x",c);parserbuf[1]=c;*state = NRA12_PARSE_STATE::STATE5_GOT_DIST_H;break;case NRA12_PARSE_STATE::STATE5_GOT_DIST_H:// PX4_INFO("STATE5_GOT_DIST_H");// PX4_INFO("c=%x",c);*state = NRA12_PARSE_STATE::STATE6_GOT_DIST_L;parserbuf[2]=c;break;case NRA12_PARSE_STATE::STATE6_GOT_DIST_L:// PX4_INFO("STATE6_GOT_DIST_L");// PX4_INFO("c=%x",c);*state = NRA12_PARSE_STATE::STATE7_GOT_UNUSE1;break;case NRA12_PARSE_STATE::STATE7_GOT_UNUSE1:// PX4_INFO("STATE7_GOT_UNUSE1");// PX4_INFO("c=%x",c);*state = NRA12_PARSE_STATE::STATE8_GOT_UNUSE2;break;case NRA12_PARSE_STATE::STATE8_GOT_UNUSE2://  PX4_INFO("STATE8_GOT_UNUSE2");// PX4_INFO("c=%x",c);*state = NRA12_PARSE_STATE::STATE9_GOT_UNUSE3;break;case NRA12_PARSE_STATE::STATE9_GOT_UNUSE3:// PX4_INFO("STATE9_GOT_UNUSE3");// PX4_INFO("c=%x",c);*state = NRA12_PARSE_STATE::STATE10_GOT_UNUSE4;break;case NRA12_PARSE_STATE::STATE10_GOT_UNUSE4://  PX4_INFO("STATE10_GOT_UNUSE4");// PX4_INFO("c=%x",c);if(c==0x55){*state = NRA12_PARSE_STATE::STATE11_GOT_END1;}break;case NRA12_PARSE_STATE::STATE11_GOT_END1://  PX4_INFO("STATE11_GOT_END1");// PX4_INFO("c=%x",c);if(c==0x55){*state = NRA12_PARSE_STATE::STATE12_GOT_END2;unsigned int t1 = parserbuf[2];unsigned int t2 = parserbuf[1];t2 <<= 8;t2 += t1;if (t2 < 0xFFFFu) {*dist = ((float)t2) / 100;}//	 PX4_INFO("dist=%lf\n",(double)*dist);}else {*state = NRA12_PARSE_STATE::STATE0_UNSYNC;}break;}#ifdef NRA12_DEBUGprintf("state: NRA12_PARSE_STATE%s\n", parser_state[*state]);
#endifreturn ret;
}

nra12_parser.h如下:

enum class NRA12_PARSE_STATE {STATE0_UNSYNC = 0,STATE1_GOT_START1,STATE2_GOT_START2,STATE2_GOT_0C,STATE2_GOT_07,STATE3_GOT_Index,STATE4_GOT_Res,STATE5_GOT_DIST_H,STATE6_GOT_DIST_L,STATE7_GOT_UNUSE1,STATE8_GOT_UNUSE2,STATE9_GOT_UNUSE3,STATE10_GOT_UNUSE4,STATE11_GOT_END1,STATE12_GOT_END2
};int nra12_parse(char c, char *parserbuf, unsigned *parserbuf_index, NRA12_PARSE_STATE *state, float *dist);

修改src/drivers/drv_sensor.h
添加

#define DRV_DIST_DEVTYPE_NRA12      0xC2

修改boards/px4/fmu-v5/default.px4board
添加

CONFIG_COMMON_DISTANCE_SENSOR_NRA12=y

最后编译并将固件下载到飞控,将NRA12通过串口连接到UART&I2C B口,将参数SENS_NRA12_CFG设置成TELEM/SERIAL4,然后观察能观察到测距传感器的数据输出
在这里插入图片描述

这篇关于PX4二次开发快速入门(三):自定义串口驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/957852

相关文章

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

shell脚本快速检查192.168.1网段ip是否在用的方法

《shell脚本快速检查192.168.1网段ip是否在用的方法》该Shell脚本通过并发ping命令检查192.168.1网段中哪些IP地址正在使用,脚本定义了网络段、超时时间和并行扫描数量,并使用... 目录脚本:检查 192.168.1 网段 IP 是否在用脚本说明使用方法示例输出优化建议总结检查 1

Rust中的Option枚举快速入门教程

《Rust中的Option枚举快速入门教程》Rust中的Option枚举用于表示可能不存在的值,提供了多种方法来处理这些值,避免了空指针异常,文章介绍了Option的定义、常见方法、使用场景以及注意事... 目录引言Option介绍Option的常见方法Option使用场景场景一:函数返回可能不存在的值场景

SpringBoot 自定义消息转换器使用详解

《SpringBoot自定义消息转换器使用详解》本文详细介绍了SpringBoot消息转换器的知识,并通过案例操作演示了如何进行自定义消息转换器的定制开发和使用,感兴趣的朋友一起看看吧... 目录一、前言二、SpringBoot 内容协商介绍2.1 什么是内容协商2.2 内容协商机制深入理解2.2.1 内容

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题: