一、项目名称:
二、项目概述:
随着技术的不断进步和发展,农业机器人逐渐经历了从机械自动化到人工智能、机器视觉等新技术加持的转变。人工智能(Artificial Intelligence,AI)作为一种应用于农业领域的新兴技术,正逐渐改变着传统农业的面貌。智能农机作为人工智能在农业中的代表之一,在高效种植施肥和精确农药喷洒方面发挥着重要作用。
基于树莓派和stm32f746的智能多功能农业机器人系统,可以实现手动遥控和自主导航。完全无人作业。
本系统主要包括以树莓派4B为AI中枢,以stm32f746 discovery开发板为核心、48V转5V 5A电源模块、4G /WIFI模块、3D激光雷达、电机驱动模块,RTK高精度查分定位系统单元,2.4G无线遥控器等设备组成。
遥控器主要由按键、指示灯、显示屏等组成。 按键包括前进、后退、左转、右转、启动喷药、停止喷药等,通过无线通讯将指令传输给智能喷药车,实现车辆的主动遥控。 指示灯用于显示遥控器和智能喷药车的状态,如电量、工作状态、通讯状态等。stm32f746 discovery开发板显示屏用于显示智能喷药车的实时位置、运动状态、喷药状态等信息,方便农业管理人员对机器人的管理和监控。
智能喷药车通过树莓派实现喷药控制、定位等功能,遥控器通过按键、指示灯等方式实现对喷药车的遥控和监测。 智能喷药车由底盘、行驶控制系统、喷药控制系统、运动传感器、GNSS差分定位等组成。
系统的软件设计主要包括ROS系统Slam算法为核心,以FreeRTOS实时操作系统在单片机为执行器。树莓派与单片机数据传输的通讯调试、千寻阿里云物联网实现高精度差分定位和4G /WIFI模块在单片机上的接入以及树莓派上位机控制软件的实现。
通过利用深度学习算法实现障碍我的识别与定位,将RTK 信息以及农业机器人的状态使用物联网技术传输到云端,实现喷药车位置点的采集、路径的编辑/下发、模式切换、导航控制功能。
三、作品实物图
系统架构图:
实物图:
部件:
基于树莓派和stm32f746的智能多功能农业机器人开发系统主要由3个部分组成:
①环境感知。涉及多种传感器,包括土壤、烟感器、测距和温度检测传感器等,在巡检过程中实现对无人环境感知实时监测。
②执行机构。为了方便后期的机器人维护,上层控制器部分与底层执行机构部分采用模块化设计,执行机构部分采用 STM32F7作为底层处理器,通过4路PWM实现机器人底层电机的驱动。针对环境感知系统中存在的导航、传感器数据复杂和信息量较大等问题,上层控制器的处理器采用树莓派作为主控。
③控制系统:需要给树莓派的SD卡里烧录系统镜像。相关配置如下:
操作系统:Ubuntu18.04系统,基于Debian GNU/Linux,支持x86、amd64(即x64)、ARM和ppc架构。
仿真系统:基于开源机器人操作系统ROS melodic,上位机采用ROS melodic,基于Rviz完成全向移动底盘小车slam导航运动规划,采用gazebo完成全向移动底盘小车物理运动仿真;下位机采用基于FreertOS STM32F76实现对全向移动底盘运动的控制。
STM32H7采集传感器将检测到的数据通过IIC协议的方式传递给树莓派,执行机构部分与树莓派之间、导航RTK与树莓派之间采用 USB 通信方式,为了方便管理者在后端管理**查看机器人的位置和无人化仓库的情况,机器人**与终端采用无线的方式实现通信。
为了能够让机器人按照一定的路径进行农业作业,需规划出机器人从此刻位置到某一位置的移动路径,使得机器人从当前位姿到达目标位姿。移动机器人的速度与位置、位姿存在紧密联系,要对机器人进行控制,需要对其位姿进行准确表达。
首先建立搭建ROS开发环境,进行Slam导航算法,找到合适的坐标系,对主要信息量进行表达,然后分析各坐标系之间存在的位置关系,最后确定速度与位姿之间的数学关系表达式。
VSLAM则主要用摄像头来实现,主要分为单目、双目、单目结构光、双目结构光、ToF几大类。核心都是获取RGB和depth map(深度信息)。
STM32与树莓派交互关键代码
#include <serial/serial.h>
#include "MbotRosSerial.h"
#include <iostream>
/********************************************************
串口发送接收相关常量、变量、共用体对象
********************************************************/
const unsigned char ender[2] = { 0x0d, 0x0a };
const unsigned char header[2] = { 0x55, 0xaa };
serial::Serial sp;//创建一个serial对象
//发送左右轮速控制速度共用体
union sendData
{
short d;
unsigned char data[2];
}leftVelSet, rightVelSet;
//接收数据(左轮速、右轮速、角度)共用体(-32767 - +32768)
union receiveData
{
short d;
unsigned char data[2];
}leftVelNow, rightVelNow, angleNow;
/********************************************************
函数功能:串口参数初始化
入口参数:无
出口参数:无
作者:K.Fire
日期:2022.02.10
********************************************************/
void Serial_Init()
{
serial::Timeout to = serial::Timeout::simpleTimeout(100);//创建timeout
serial::parity_t pt = serial::parity_t::parity_none;//创建校验位为0位
serial::bytesize_t bt = serial::bytesize_t::eightbits;//创建发送字节数为8位
serial::flowcontrol_t ft = serial::flowcontrol_t::flowcontrol_none;//创建数据流控制,不使用
serial::stopbits_t st = serial::stopbits_t::stopbits_one;//创建终止位为1位
sp.setPort("/dev/ttyUSB0");//设置要打开的串口名称
sp.setBaudrate(9600);//设置串口通信的波特率
sp.setParity(pt);//设置校验位
sp.setBytesize(bt);//设置发送字节数
sp.setFlowcontrol(ft);//设置数据流控制
sp.setStopbits(st);//设置终止位
sp.setTimeout(to);//串口设置timeout
try
{
//打开串口
sp.open();
}
catch (serial::IOException& e)
{
ROS_ERROR_STREAM("Unable to open port.");
return;
}
}
/********************************************************
函数功能:将对机器人的左右轮子控制速度,打包发送给下位机
入口参数:机器人线速度、角速度
出口参数:无
作者:K.Fire
日期:2022.02.10
********************************************************/
void SendSTM32(double Left_v, double Right_v, unsigned char CtrlCmd)
{
unsigned char buf[11] = { 0 };//发送数组
int i, length = 4;
leftVelSet.d = Left_v;//mm/s
rightVelSet.d = Right_v;
// 设置消息头
for (i = 0; i < 2; i++)
buf[i] = header[i]; //buf[0] buf[1]
//设置控制位
buf[2] = CtrlCmd; //buf[2]
//设置数据长度
buf[3] = length; //buf[3]
// 设置机器人左右轮速度
for (i = 0; i < 2; i++)
{
buf[i + 4] = leftVelSet.data[i]; //buf[4] buf[5]
buf[i + 6] = rightVelSet.data[i]; //buf[6] buf[7]
}
// 设置校验值、消息尾
buf[4 + length] = getCrc8(buf, 3 + length);//buf[8]
buf[5 + length] = ender[0]; //buf[9]
buf[6 + length] = ender[1]; //buf[10]
// 通过串口下发数据
sp.write(buf, 11);
}
/********************************************************
函数功能:读取下位机数据,左右轮速度值、航向角、控制信息
入口参数:左右轮速度值、航向角、控制信息
出口参数:bool
作者:K.Fire
日期:2022.02.10
********************************************************/
bool ReceiveSTM32(double& Left_v, double& Right_v, double& Angle, unsigned char& CtrlCmd)
{
char i, length = 0;
unsigned char checkSum;
unsigned char buf[150] = { 0 };
int n;//信息长度
size_t Receive_N = sp.available();//获取缓冲区内的字节数
if (n != 0)
{
n = sp.read(buf, n);//读出数据
// 检查信息头
if (buf[0] != header[0] || buf[1] != header[1]) //buf[0] buf[1]
{
ROS_ERROR("Received message header error!");
return false;
}
//读取控制位
CtrlCmd = buf[2]; //buf[2]
//读取数据长度
length = buf[3]; //buf[3]
// 检查信息校验值
checkSum = getCrc8(buf, 4 + length); //buf[10] 计算得出
if (checkSum != buf[4 + length]) //buf[10] 串口接收
{
ROS_ERROR("Received data check sum error!");
return false;
}
// 读取速度值和航向角
for (i = 0; i < 2; i++)
{
leftVelNow.data[i] = buf[i + 4]; //buf[4] buf[5]
rightVelNow.data[i] = buf[i + 6]; //buf[6] buf[7]
angleNow.data[i] = buf[i + 8]; //buf[8] buf[9]
}
Left_v = leftVelNow.d;
Right_v = rightVelNow.d;
Angle = angleNow.d;
return true;
}
}
/********************************************************
函数功能:获得8位循环冗余校验值
入口参数:数组地址、长度
出口参数:校验值
********************************************************/
unsigned char getCrc8(unsigned char* ptr, unsigned short len)
{
unsigned char crc;
unsigned char i;
crc = 0;
while (len--)
{
crc ^= *ptr++;
for (i = 0; i < 8; i++)
{
if (crc & 0x01)
crc = (crc >> 1) ^ 0x8C;
else
crc >>= 1;
}
}
return crc;
}
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "MbotRosSerial.h"
//test send value
double testSend1=5555.0;
double testSend2=2222.0;
unsigned char testSend3=0x07;
//test receive value
double testRece1=0.0;
double testRece2=0.0;
double testRece3=0.0;
unsigned char testRece4=0x00;
int main(int argc,char **argv)
{
ros::init(argc,argv,"serial_test");//节点初始化
ros::NodeHandle n;//创建节点句柄
ros::Rate loop_rate(10);
//串口初始化
Serial_Init();
while(ros::ok())
{
//发送数据
SendSTM32(testSend1,testSend2,testSend3);
//接收数据
ReceiveSTM32(testRece1,testRece2,testRece3,testRece4);
//打印数据
ROS_INFO("Receive Data is: %f,%f,%f,%dn",testRece1,testRece2,testRece3,testRece4);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
RTK 载波相位差分技术,是实时处理两个测量站载波相位观测量的差分方法,将基准站采集的载波相位发给用户接收机,进行求差解算坐标。一般包含流动站 (移动站) 和基准站 (基站) 。本系统中RTK定位采用千寻定位, 参考的也是千寻CORS基站的坐标,所以需要先登入千寻cors账号。
RTK接入ROS系统,nmea_navsat_driver是一套用于获取并解析GPS数据的ROS驱动包,使用Python语言实现。GPS设备使用此包的条件是:遵守或者兼容NMEA0183协议。
本次设计结合摄像头激光雷达和RTK实现融合定位,真正做到厘米级别,属于国际领先。
喷嘴可以用来喷洒农药也可以进行环境消毒,也可以进行施肥作业,真正做到一机多用。
四、演示视频
https://www.bilibili.com/video/BV1uA4m1j7pM/?buvid=XY75B537C416E17A953A00A33EDB883CA28EB&is_story_h5=false&mid=Pw2Hq3t6IhfKj%2FPD%2Bao96g%3D%3D&plat_id=147&share_from=ugc&share_medium=android&share_plat=android&share_session_id=06897bb8-6ae8-4efd-99e7-41f15d1b701d&share_source=WEIXIN&share_tag=s_i×tamp=1706692332&unique_k=Km1lrk3&up_id=526937168
五、项目文档
ROS串口程序.zip (7.13 KB)
基于树莓派和stm32f746的智能多功能农业机器人开发.zip (4.67 MB)