( C# + vs2017 )串口助手 零基础详细教程(二)

2023-05-16

感谢:

串口助手(简洁版)上位机软件零基础教程( C# + visual studio2017 )(二)_SWPU_机器人实验室-CSDN博客

在上篇博客中,我们完成了串口助手(简洁版)可视化窗体的设计,并且单击启动后可以运行。但是光有外壳,没有灵魂。所以接下来我们将继续一步一步来编写上位机软件的程序部分。

首先,我谈一下自己所理解的C#上位机软件程序编写的中心思想。以串口助手(简洁版)为例,所有程序都是以 “事件” 为核心来进行的,对应的 “事件”发生了,那软件就去执行 我们自己编写的 对应事件中的 程序。

  • 按键按下,算一个事件吧 ----> 执行这个按键按下对应的程序;
  • 串口突然收到数据 ,算一个事件吧 -----> 执行串口收到数据时对应的程序
  • 定时器中断来了,也是个事件 ----> 执行定时器中断发生时对应的程序

不知道这样讲符不符合C#上位机真正的编程方式,但是对于初学者应该会有种豁然开朗的感觉。如果错了,先就错着看吧,哈哈。。。咱们下面就一个事件,一个事件的写代码,代码后都有详细的注释,大家不要心虚。。。。。
 

1、窗口加载时事件(程序)

窗体刚刚加载出来,就是弹出软件窗口的一瞬间,算个事件吧。那怎么去编写这一段的程序呢?我们到上一章编好的可视化窗体中,去双击窗体的空白处,就跳转到对应的事件发生程序中去了。比如双击这里:

 然后就跳转到这个代码段中来了:

、、、 C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace 串口助手_简洁版_
{
    public partial class Form1 : Form
    {
        /*默认存在*/
        public Form1()
        {
            InitializeComponent();
        }
 
        /*窗体加载时被调用*/
        private void Form1_Load(object sender, EventArgs e)
        {
 
        }
 
    }
}

函数  Form1_Load()  就会在窗体加载的时候被调用一次。上方的 Form1()   函数会默认存在,暂时不用理会。在其中加入代码:

''' C#
 
        /*窗体加载时被调用*/
        private void Form1_Load(object sender, EventArgs e)
        {
            Updata_Serialport_Name(comboBox1);  //调用更新可用串口函数,comboBox1为 端口 组合框名字
 
            radioButton1.Checked = true;   //函数中选择发送模式 为“数值”发送模式。 radioButton1为单选按钮属性(name)名字
            radioButton3.Checked = true;   //函数中选择接收模式 为“数值”接收模式。 radioButton3为单选按钮属性(name)名字
 
            button2.Text = "打开串口";     // 确保 “打开串口”按键文本属性为 “打开串口”
        }
 
        /*用户自定义更新可用串口函数*/
        private void Updata_Serialport_Name(ComboBox MycomboBox)
        {
            string[] ArryPort = SerialPort.GetPortNames();  //定义字符串数组,数组名为 ArryPort
                                                            //SerialP ort.GetPortNames()函数功能为获取计算机所有可用串口,以字符串数组形式输出
            MycomboBox.Items.Clear();       //清除当前组合框下拉菜单内容                  
 
            for (int i = 0; i < ArryPort.Length; i++)
            {
                MycomboBox.Items.Add(ArryPort[i]);   //将所有的可用串口号添加到  端口 对应的组合框中
            }
        }

  总结:

  • 在窗体加载事件中,我们设置  发送和接收模式都默认选择 “”数值“”模式,  同时 调用自定义的串口号更新函数 Updata_Serialport_Name (), 来更新一下 “端口”   组合框下拉菜单中的串口信息。
  •  SerialPort.GetPortNames()  函数,用来查询所有的可用串口号。

2.定时器中断事件(程序)

上一章在可视化窗体编辑过程中,我们添加并使能了定时器控件,并设定时周期为500ms。所以在程序中,我们需要为其添加定时器中断处理程序。同上一样,我们需要正在GUI窗口中双击Timer图标。便可创建 和 进入 定时器中断事件代码段。

双击此处:

 

 编辑函数如下:

''' C#   
 
        /*定时器500ms中断调用*/
        private void timer1_Tick(object sender, EventArgs e)
        {
            Updata_Serialport_Name(comboBox1);   //依然是调用更新可用串口函数
                                                 //目的是在软件使用过程中,时刻刷新串口信息
        }

总结:  间隔500ms产生一次定时器中断事件,在中断事件中调用用户自定义的更新串口号函数,来实现串口号的动态更新。

3.串口开关按键按下事件(程序)

在GUI界面中,我们做了一个“”打开串口“”按键,用于打开上位机串口。同样双击按键图标进入事件对应的程序段。事件对应的代码如下:

''' C#        
 
       /*打开串口按键按下调用*/
        private void button2_Click(object sender, EventArgs e)
        {
 
            if (button2.Text == "打开串口")     //如当前是串口设备是关闭状态
            {
                try                             //try 是尝试部分  ,如果尝试过程中出现问题,进入 catch部分,执行错误处理代码  
                {
                    serialPort1.PortName = comboBox1.Text;                   //将串口设备的串口号属性设置为  comboBox1复选框中选择的串口号
                    serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);  //将串口设备的波特率属性设置为  comboBox2复选框中选择的波特率
                    serialPort1.Open();     //打开串口,如果打开了继续向下执行,如果失败了,跳转至catch部分
 
                    comboBox1.Enabled = false;   //串口已经打开了,将comboBox1设置为不可操作
                    comboBox2.Enabled = false;   //串口已经打开了,将comboBox2设置为不可操作
 
                    button2.BackColor = Color.Red;   //将串口开关按键的颜色,改为红色
                    button2.Text = "关闭串口";      //将串口开关按键的文字改为  “关闭串口”
                }
                catch
                {
                    MessageBox.Show("打开串口失败,请检查串口", "错误");   //弹出错误对话框
                }
            }
            else              //如果当前串口设备是打开状态
            {
                try
                {
                    serialPort1.Close();    //关闭串口
 
                    comboBox1.Enabled = true;   //串口已经关闭了,将comboBox1设置为可操作
                    comboBox2.Enabled = true;   //串口已经关闭了,将comboBox2设置为可操作
 
                    button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
 
                    button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
                }
                catch
                {
                    MessageBox.Show("关闭串口失败,请检查串口", "错误");   //弹出错误对话框
                }
 
            }
        }

总结:

  • Convert.ToInt32(comboBox2.Text);  意思是将comboBox2中选中的波特率字符串,转化为int 32位的数值数据。
  • try 和  catch  是C#中特有的,用来进行错误处理的语句。出错了就跳至catch部分补救处理。如果没有catch,一旦出错程序就崩掉了。
  • 打开串口后,串口开关按键的颜色和文字就已经在程序中被修改了,而且还让两个组合框发灰,变成不可操作状态
     

4.发送按钮按下事件(程序)

 当按下串口发送按键后,就需要将发送文本框中的数据通过串口发出。并且要通过判断单选按钮的按下状态来判断该以什么样的数据形式发送。同样双击发送按键  ,进入发送按钮按下代码段,并写入代码如下:

'''C#
  
        /*发送按键按下调用*/
        private void button1_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)    //如果串口设备已经打开了
            {
                if (radioButton2.Checked)  //如果是以字符的形式发送数据
                {
                    char[] str = new char[1];  //定义一个字符数组,只有一位
 
                    try
                    {
                        for (int i = 0; i < textBox1.Text.Length; i++)
                        {
                            str[0] = Convert.ToChar(textBox1.Text.Substring(i, 1));  //取待发送文本框中的第i个字符
                            serialPort1.Write(str, 0, 1);     //写入串口设备进行发送
                        }
                    }
                    catch
                    {
                        MessageBox.Show("串口字符写入错误!", "错误");   //弹出发送错误对话框
 
                        serialPort1.Close();             //关闭串口
 
                        button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
 
                        button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
                    }
                }
                else  //如果以数值的形式发送
                {
                    byte[] Data = new byte[1];   //定义一个byte类型数据,相当于单片机中的  unsigned char 类型
 
                    int flag = 0;   //定义一个标志,标志这是第几位
 
                    try
                    {
                        for (int i = 0; i < textBox1.Text.Length; i++)
                        {
                            if (textBox1.Text.Substring(i, 1) == " " && flag == 0)   //如果是第一位,并且为空字符
                            {
                                continue;
                            }
 
                            if (textBox1.Text.Substring(i, 1) != " " && flag == 0)  //如果是第一位,但不为空字符
                            {
                                flag = 1;   //标志转到第二位数据去
 
                                if (i == textBox1.Text.Length - 1)   //如果这是文本框字符串的最后一个字符
                                {
                                    Data[0] = Convert.ToByte(textBox1.Text.Substring(i, 1), 16);  //转化为byte类型数据,以16进制显示
                                    serialPort1.Write(Data, 0, 1);   //通过串口发送
                                    flag = 0;    //标志回到第一位数据去
                                }
                                continue;
                            }
 
                            else if (textBox1.Text.Substring(i, 1) == " " && flag == 1)  //如果是第二位 ,且第二位字符为空
                            {
                                Data[0] = Convert.ToByte(textBox1.Text.Substring(i - 1, 1), 16);  //只将第一位字符转化为byte类型数据,以十六进制显示
                                serialPort1.Write(Data, 0, 1);    //通过串口发送
                                flag = 0;    //标志回到第一位数据去
                                continue;
                            }
                            else if (textBox1.Text.Substring(i, 1) != " " && flag == 1)  //如果是第二位字符,且第一位字符不为空
                            {
                                Data[0] = Convert.ToByte(textBox1.Text.Substring(i - 1, 2), 16);  //将第一,二位字符转化为byte类型数据,以十六进制显示
                                serialPort1.Write(Data, 0, 1);  //通过串口发送
                                flag = 0;  //标志回到第一位数据去
                                continue;
                            }
                        }
                    }
                    catch
                    {
                        MessageBox.Show("串口数值写入错误!", "错误");
 
                        serialPort1.Close();
 
                        button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
 
                        button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
 
                    }
                }
 
 
            }
 
        }

总结:

  • serialPort1.Write(str, 0, 1); 是向串口发送缓冲区中写数据,第一位是待写入数组名,第二位是数组起始位置,第三位是数据长度。
  • textBox1.Text.Substring(i, 1);是字符串截取函数,截取完后形成一个子字符串,第一位是首字符地址,第二位是字符串长度。
  • 串口发送函数分为按数值方式,和按字符方式。需要根据单选按钮控件的按下状态来决定。
  • .数值发送方式写的有点复杂,目的是要从字符串中,两两抠出16进制数据,如0x46,但同时又要考虑空格作为分隔符的存在。虽然代码复杂了,但是相对用户来说,就没有了输入格式要求,随心所欲的输都可以。

5. 串口接收到数据事件(程序)

  当串口接收到数据时,会调用串口接收到数据的事件函数,串口接收代码段的打开方式和其他的有所不同,双击图标并不会进行代码段的创建,需要注意一下。这里需要这样来进行创建和打开。

在串口属性窗口中,单击这个像闪电一样的图标。

 然后双击   DataREceived 属性栏,才会创建 并打开串口接收代码段:

 填入代码如下:

''' C#
 
        /*串口接收到*/
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
 
            if (radioButton4.Checked)  //如果以字符串形式读取
            {
                string str = serialPort1.ReadExisting();   //读取串口接收缓冲区字符串
 
                textBox2.AppendText(str + "");             //在接收文本框中进行显示
            }
            else   //以数值形式读取
            {
                int length = serialPort1.BytesToRead;    // 读取串口接收缓冲区字节数
 
                byte[] data = new byte[length];          //定义相同字节的数组
 
                serialPort1.Read(data, 0, length);       //串口读取缓冲区数据到数组中
 
                for (int i = 0; i < length; i++)   
                {
                    string str = Convert.ToString(data[i], 16).ToUpper();          //将数据转换为字符串格式
                    textBox2.AppendText("0X" + (str.Length == 1 ? "0" + str + " " : str + " "));   //添加到串口接收文本框中
                }
            }
 
        }

总结:

1.serialPort1.ReadExisting();以字符串的形式读取串口接收缓冲区内的数据。

2. (str.Length == 1 ? "0" + str + " " : str + " ")三目运算符,跟C语言一样。

6.清空数据按键按下事件(代码)

现在来说这个就比较简单了,直接上代码:

  ''' C#
 
 
     /*清除按键按下*/
        private void button3_Click(object sender, EventArgs e)
        {
            textBox2.Text = "";
        }

到此为止,串口助手就已经开发完毕。按启动按钮后,可以对软件进行测试。如果想要将软件拷贝出来,直接定位到工程文件夹下的obj目录,将其中的.exe文件拷贝出来即可。

再附上程序整图:

''' C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
 
 
namespace 串口助手_简洁版_
{
    public partial class Form1 : Form
    {
        /*默认存在*/
        public Form1()
        {
            InitializeComponent();
        }
 
        /*窗体加载时被调用*/
        private void Form1_Load(object sender, EventArgs e)
        {
            Updata_Serialport_Name(comboBox1);  //调用更新可用串口函数,comboBox1为 端口 组合框名字
 
            radioButton1.Checked = true;   //函数中选择发送模式 为“数值”发送模式。 radioButton1为单选按钮属性(name)名字
            radioButton3.Checked = true;   //函数中选择接收模式 为“数值”接收模式。 radioButton3为单选按钮属性(name)名字
 
            button2.Text = "打开串口";     // 确保 “打开串口”按键文本属性为 “打开串口”
        }
 
        /*用户自定义更新可用串口函数*/
        private void Updata_Serialport_Name(ComboBox MycomboBox)
        {
            string[] ArryPort = SerialPort.GetPortNames();  //定义字符串数组,数组名为 ArryPort
                                                            //SerialP ort.GetPortNames()函数功能为获取计算机所有可用串口,以字符串数组形式输出
            MycomboBox.Items.Clear();       //清除复选框                  
 
            for (int i = 0; i < ArryPort.Length; i++)
            {
                MycomboBox.Items.Add(ArryPort[i]);   //将所有的可用串口号添加到  端口 对应的组合框中
            }
        }
 
 
        /*定时器500ms中断调用*/
        private void timer1_Tick(object sender, EventArgs e)
        {
            Updata_Serialport_Name(comboBox1);   //依然是调用更新可用串口函数
                                                 //目的是在软件使用过程中,时刻刷新串口信息
        }
 
 
 
        /*开关串口按键按下调用*/
        private void button2_Click(object sender, EventArgs e)
        {
 
            if (button2.Text == "打开串口")     //如当前是串口设备是关闭状态
            {
                try                             //try 是尝试部分  ,如果尝试过程中出现问题,进入 catch部分,执行错误处理代码  
                {
                    serialPort1.PortName = comboBox1.Text;                   //将串口设备的串口号属性设置为  comboBox1复选框中选择的串口号
                    serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);  //将串口设备的波特率属性设置为  comboBox2复选框中选择的波特率
                    serialPort1.Open();     //打开串口,如果打开了继续向下执行,如果失败了,跳转至catch部分
 
                    comboBox1.Enabled = false;   //串口已经打开了,将comboBox1设置为不可操作
                    comboBox2.Enabled = false;   //串口已经打开了,将comboBox2设置为不可操作
 
                    button2.BackColor = Color.Red;   //将串口开关按键的颜色,改为红色
                    button2.Text = "关闭串口";      //将串口开关按键的文字改为  “关闭串口”
                }
                catch
                {
                    MessageBox.Show("打开串口失败,请检查串口", "错误");   //弹出错误对话框
                }
            }
            else              //如果当前串口设备是打开状态
            {
                try
                {
                    serialPort1.Close();    //关闭串口
 
                    comboBox1.Enabled = true;   //串口已经关闭了,将comboBox1设置为可操作
                    comboBox2.Enabled = true;   //串口已经关闭了,将comboBox2设置为可操作
 
                    button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
 
                    button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
                }
                catch
                {
                    MessageBox.Show("关闭串口失败,请检查串口", "错误");   //弹出错误对话框
                }
 
            }
        }
 
 
   
        /*发送按键按下调用*/
        private void button1_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)    //如果串口设备已经打开了
            {
                if (radioButton2.Checked)  //如果是以字符的形式发送数据
                {
                    char[] str = new char[1];  //定义一个字符数组,只有一位
 
                    try
                    {
                        for (int i = 0; i < textBox1.Text.Length; i++)
                        {
                            str[0] = Convert.ToChar(textBox1.Text.Substring(i, 1));  //取待发送文本框中的第i个字符
                            serialPort1.Write(str, 0, 1);     //写入串口设备进行发送
                        }
                    }
                    catch
                    {
                        MessageBox.Show("串口字符写入错误!", "错误");   //弹出发送错误对话框
 
                        serialPort1.Close();             //关闭串口
 
                        button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
 
                        button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
                    }
                }
                else  //如果以数值的形式发送
                {
                    byte[] Data = new byte[1];   //定义一个byte类型数据,相当于单片机中的  unsigned char 类型
 
                    int flag = 0;   //定义一个标志,标志这是第几位
 
                    try
                    {
                        for (int i = 0; i < textBox1.Text.Length; i++)
                        {
                            if (textBox1.Text.Substring(i, 1) == " " && flag == 0)   //如果是第一位,并且为空字符
                            {
                                continue;
                            }
 
                            if (textBox1.Text.Substring(i, 1) != " " && flag == 0)  //如果是第一位,但不为空字符
                            {
                                flag = 1;   //标志转到第二位数据去
 
                                if (i == textBox1.Text.Length - 1)   //如果这是文本框字符串的最后一个字符
                                {
                                    Data[0] = Convert.ToByte(textBox1.Text.Substring(i, 1), 16);  //转化为byte类型数据,以16进制显示
                                    serialPort1.Write(Data, 0, 1);   //通过串口发送
                                    flag = 0;    //标志回到第一位数据去
                                }
                                continue;
                            }
 
                            else if (textBox1.Text.Substring(i, 1) == " " && flag == 1)  //如果是第二位 ,且第二位字符为空
                            {
                                Data[0] = Convert.ToByte(textBox1.Text.Substring(i - 1, 1), 16);  //只将第一位字符转化为byte类型数据,以十六进制显示
                                serialPort1.Write(Data, 0, 1);    //通过串口发送
                                flag = 0;    //标志回到第一位数据去
                                continue;
                            }
                            else if (textBox1.Text.Substring(i, 1) != " " && flag == 1)  //如果是第二位字符,且第一位字符不为空
                            {
                                Data[0] = Convert.ToByte(textBox1.Text.Substring(i - 1, 2), 16);  //将第一,二位字符转化为byte类型数据,以十六进制显示
                                serialPort1.Write(Data, 0, 1);  //通过串口发送
                                flag = 0;  //标志回到第一位数据去
                                continue;
                            }
                        }
                    }
                    catch
                    {
                        MessageBox.Show("串口数值写入错误!", "错误");
 
                        serialPort1.Close();
 
                        button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
 
                        button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
 
                    }
                }
 
 
            }
 
        }
 
 
        /*串口接收到*/
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
 
            if (radioButton4.Checked)  //如果以字符串形式读取
            {
                string str = serialPort1.ReadExisting();   //读取串口接收缓冲区字符串
 
                textBox2.AppendText(str + "");             //在接收文本框中进行显示
            }
            else   //以数值形式读取
            {
                int length = serialPort1.BytesToRead;    // 读取串口接收缓冲区字节数
 
                byte[] data = new byte[length];          //定义相同字节的数组
 
                serialPort1.Read(data, 0, length);       //串口读取缓冲区数据到数组中
 
                for (int i = 0; i < length; i++)   
                {
                    string str = Convert.ToString(data[i], 16).ToUpper();          //将数据转换为字符串格式
                    textBox2.AppendText("0X" + (str.Length == 1 ? "0" + str + " " : str + " "));   //添加到串口接收文本框中
                }
            }
 
        }
 
        /*清除按键按下*/
        private void button3_Click(object sender, EventArgs e)
        {
            textBox2.Text = "";
        }
 
    }
}

看看最后效果:

 重要:如果程序运行时出现线程间访问出错,记得在Form1()函数中加一段代码,即可完美解决:

'''C#   
 
        /*默认*/
        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//设置该属性 为false
        }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

( C# + vs2017 )串口助手 零基础详细教程(二) 的相关文章

随机推荐

  • VINS - Fusion GPS/INS/视觉 融合 0、 Kitti数据测试

    放两张图片 至于为什么 xff1f 后面会解释 xff01 程序下载 xff1a https github com HKUST Aerial Robotics VINS Fusion 数据集制作 xff1a https zhuanlan z
  • GPS/INS/视觉 融合 、 自己采集数据测试

    cd VIO GPS MapVIG cmake build cmake make run MapVIG 别忘了更新一下 一 运行程序 打开第一个终端 roscore 打开第二个终端 进入工作区间内 xff0c 分别输入 xff1a cd G
  • 九、 惯性导航解算

    一 概述 惯性导航解算就是从上一时刻的导航信息推导本时刻的导航信息 xff0c 包括姿态 速度 位置 具体来讲 xff0c 就是构建当前时刻导航信息与上一时刻导航信息 运动输入 角速度 加速度 之间的关系 xff0c 确切地说 xff0c
  • 十二、构建一个基本的组合导航系统

    一 概述 在之前的文章里 xff0c 我们从一个基本的IMU模块开始讲起 xff08 二 xff09 xff0c 利用Allan方差分析方法 xff08 三 四 xff09 xff0c 得出了其误差参数 xff0c 又通过标定 xff08
  • 电脑键盘工作原理

    xfeff xfeff 随着IBM PC机的发展 xff0c 键盘也分为XT AT PS 2键盘以至于后来的USB键盘 PC系列机使用的键盘有83键 84键 101键 102键和104键等多种 XT和AT机的标准键盘分别为83键和84键 x
  • 十三、扩展一个组合导航系统

    感谢大神分享 xff1a https zhuanlan zhihu com p 156958777 一 概述 上一篇文章我们讲述了怎样搭建一个基本的组合导航系统 xff0c 它仅仅包括IMU做预测 GPS做观测 xff0c 而实际中 xff
  • 三、FSAS + Novatel接收机和相机时间同步、数据保存、解码等 细节说明

    一 器件说明 1 GNSS 接收机是 P ropak6 如下图所示 xff1a 具体得介绍 xff1a 1 https blog csdn net hltt3838 article details 110622732 2 二 NovAtel
  • Word 中出现公式不能编辑问题(兼容模式)

    当word中的公式不能编辑 xff0c 多数原因是由于word是处于兼容模式下 xff0c 这个时候就需要取消world的兼容模式 xff0c 具体步骤如下 xff1a 一 打开word文档 二 点击 word中的文件 出现如下结果 xff
  • 理论三、 MSCKF 数学基础

    感谢 xff1a 紫薯萝卜 https zhuanlan zhihu com p 76793847 1 数学定义 后续将进行MSCKF数学基础介绍 xff0c 先总结一下数据符号定义 坐标系定义 物理量定义 估计量定义 四元数定义 xff1
  • 算法改进5:开源算法Open VINS试用

    1 Open VINS简介 Open VINS是Huang Guoquan老师团队在2019年8月份开源的一套基于MSCKF的VINS算法 xff0c 黄老师曾是Tango项目的核心成员 xff0c 在MSCKF这块非常的权威 Github
  • MSCKF 公式推导

    看完这篇博客建议再看 xff1a http www xinliang zhong vip msckf notes 目录 一 简介 二 符号说明 三 状态向量 3 1 真实状态向量 true state 3 2 误差状态向量 error st
  • MSCKF 源码解析 一

    论文 xff1a https arxiv org abs 1712 00036 源码路径 https github com daniilidis group msckf mono 源码框架 上图展示了整个msckf源码框架 xff0c 每当
  • C++中 仿函数简单介绍

    仿函数 xff0c 顾名思义 xff0c 就是 仿造函数 的意思 xff0c 它并不是函数 xff0c 但是却有着类似于函数的行为 那么 xff0c 它到底是什么 xff1f 首先要说的是 xff1a 仿函数是泛型编程强大威力和纯粹抽象概念
  • GNSS/INS组合导航(八):INS/GPS组合导航

    INS GPS组合导航 对比INS与GPS导航方法 xff0c 二者都有其各自的优缺点 惯性导航系统INS是一种全自主的导航系统 xff0c 可以输出超过200Hz的高频信号 xff0c 并且具有较高的短期测量精度 除了提供位置与速度之外还
  • Word 中利用“多级列表“功能实现章节标题自动编号

    一 打开 多级列表 打开Word文档 xff0c 在 开始 选择多级列表 点击定义新的多级列表 xff1b 点击之后 xff0c 便可以得到下面的界面 xff1a 二 设置固定格式的 多级标题 假设我们需要下面的标题格式 xff0c 我们需
  • 端口映射怎么设置

    路由器端口映射的作用就是让互联网上的用户可以访问内网中的服务器 xff0c 内网的一台电脑要上因特网对外开放服务或接收数据 xff0c 都需要端口映射 端口映射分为动态和静态 动态端口映射 xff1a 内网中的一台电脑要访问某网站 xff0
  • 解决Word中出现的多级列表编号不显示的问题

    解决办法一 常见的办法是 xff1a 光标置于标题前方 xff0c 按 ctrl 43 xff0c 编号消失位置出现一小条灰色 xff0c 再按ctrl 43 shift 43 S 重新应用样式 确定 即可找回编号 注意 xff1a 但下次
  • GPS从入门到放弃(二十五)、卡尔曼滤波

    一 概述 单点定位的结果因为是单独一个点一个点进行的 xff0c 所以连续起来看数据可能出现上串下跳的情况 xff0c 事实上并不符合实际情况 为了解决这个问题 xff0c 考虑到物体运动的连续性和运动变化的缓慢性 xff0c 可以通过滤波
  • RealSenseD435i (一):Ubuntu18.04 下的安装、使用和bag录制 ,且解决 undefined symbol 问题(最简单的方法)

    注意 realsense ros 要和 librealsense 版本匹配 realsense ros 2 2 11 对应的 Realsense SDK 为 librealsense 2 31 0 否则后面会出现让人崩溃的问题 其中 nbs
  • ( C# + vs2017 )串口助手 零基础详细教程(二)

    感谢 xff1a 串口助手 简洁版 上位机软件零基础教程 xff08 C 43 visual studio2017 xff09 xff08 二 xff09 SWPU 机器人实验室 CSDN博客 在上篇博客中 xff0c 我们完成了串口助手