<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_%E5%90%8C%E6%97%B6%E4%BD%BF%E7%94%A8%E6%BF%80%E5%85%89%E3%80%81%E5%9C%B0%E7%BA%B9%E3%80%81%E4%BA%8C%E7%BB%B4%E7%A0%81%E3%80%81%E8%BD%AE%E7%BC%96%E9%87%8C%E7%A8%8B%E8%AE%A1%E5%92%8CIMU%E8%BF%9B%E8%A1%8C%E9%B2%81%E6%A3%92%E5%AE%9A%E4%BD%8D</id>
	<title>使用手册 - 同时使用激光、地纹、二维码、轮编里程计和IMU进行鲁棒定位 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_%E5%90%8C%E6%97%B6%E4%BD%BF%E7%94%A8%E6%BF%80%E5%85%89%E3%80%81%E5%9C%B0%E7%BA%B9%E3%80%81%E4%BA%8C%E7%BB%B4%E7%A0%81%E3%80%81%E8%BD%AE%E7%BC%96%E9%87%8C%E7%A8%8B%E8%AE%A1%E5%92%8CIMU%E8%BF%9B%E8%A1%8C%E9%B2%81%E6%A3%92%E5%AE%9A%E4%BD%8D"/>
	<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_%E5%90%8C%E6%97%B6%E4%BD%BF%E7%94%A8%E6%BF%80%E5%85%89%E3%80%81%E5%9C%B0%E7%BA%B9%E3%80%81%E4%BA%8C%E7%BB%B4%E7%A0%81%E3%80%81%E8%BD%AE%E7%BC%96%E9%87%8C%E7%A8%8B%E8%AE%A1%E5%92%8CIMU%E8%BF%9B%E8%A1%8C%E9%B2%81%E6%A3%92%E5%AE%9A%E4%BD%8D&amp;action=history"/>
	<updated>2026-04-15T18:00:27Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_%E5%90%8C%E6%97%B6%E4%BD%BF%E7%94%A8%E6%BF%80%E5%85%89%E3%80%81%E5%9C%B0%E7%BA%B9%E3%80%81%E4%BA%8C%E7%BB%B4%E7%A0%81%E3%80%81%E8%BD%AE%E7%BC%96%E9%87%8C%E7%A8%8B%E8%AE%A1%E5%92%8CIMU%E8%BF%9B%E8%A1%8C%E9%B2%81%E6%A3%92%E5%AE%9A%E4%BD%8D&amp;diff=701&amp;oldid=prev</id>
		<title>Yuhang：​创建页面，内容为“=== 1.为什么要使用如此多的里程计 === 由于detour中tc(紧耦合)，参与的里程计越多，小车的定位就会越稳定、越平滑，所以希望能够有足够多的里程计参与其中。  激光的优点在于，视野大，并且可以从可视化中轻易看出小车目前所在位置，但是缺点是在高动态环境或无明显几何特征的环境中，定位会变得不稳定。  地纹的有点在于精度非常高，但是范…”</title>
		<link rel="alternate" type="text/html" href="https://wiki.lessokaji.com/index.php?title=%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C_-_%E5%90%8C%E6%97%B6%E4%BD%BF%E7%94%A8%E6%BF%80%E5%85%89%E3%80%81%E5%9C%B0%E7%BA%B9%E3%80%81%E4%BA%8C%E7%BB%B4%E7%A0%81%E3%80%81%E8%BD%AE%E7%BC%96%E9%87%8C%E7%A8%8B%E8%AE%A1%E5%92%8CIMU%E8%BF%9B%E8%A1%8C%E9%B2%81%E6%A3%92%E5%AE%9A%E4%BD%8D&amp;diff=701&amp;oldid=prev"/>
		<updated>2024-06-17T07:18:35Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“=== 1.为什么要使用如此多的里程计 === 由于detour中tc(紧耦合)，参与的里程计越多，小车的定位就会越稳定、越平滑，所以希望能够有足够多的里程计参与其中。  激光的优点在于，视野大，并且可以从可视化中轻易看出小车目前所在位置，但是缺点是在高动态环境或无明显几何特征的环境中，定位会变得不稳定。  地纹的有点在于精度非常高，但是范…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;=== 1.为什么要使用如此多的里程计 ===&lt;br /&gt;
由于detour中tc(紧耦合)，参与的里程计越多，小车的定位就会越稳定、越平滑，所以希望能够有足够多的里程计参与其中。&lt;br /&gt;
&lt;br /&gt;
激光的优点在于，视野大，并且可以从可视化中轻易看出小车目前所在位置，但是缺点是在高动态环境或无明显几何特征的环境中，定位会变得不稳定。&lt;br /&gt;
&lt;br /&gt;
地纹的有点在于精度非常高，但是范围小，且脱离图层范围之后，难以快速重新重定位。&lt;br /&gt;
&lt;br /&gt;
二维码的优点在于，可以快速恢复定位，但是若大规模使用，施工量大，且柔性不足。&lt;br /&gt;
&lt;br /&gt;
轮里程计的有点在于，稳定，不受环境影响，缺点是打滑会产生影响，且无法回环消除误差。&lt;br /&gt;
&lt;br /&gt;
所以将以上所有里程计同时使用，进行鲁棒定位&lt;br /&gt;
&lt;br /&gt;
=== 2.部署多个定位源 ===&lt;br /&gt;
激光和地纹部署，在wiki的[[使用手册 - 激光＋纹理导航|其它文章]]中已有说明，此处不做赘述，二维码部署也有[[使用手册 - 在地纹导航中使用二维码快速找回定位|详细说明]]，此处重点讲如何部署轮里程计&lt;br /&gt;
&lt;br /&gt;
轮里程计需要通过车轮编码器、imu数据进行积分，得出一个完整的位置，然后post给detour使用。&lt;br /&gt;
&lt;br /&gt;
首先在medulla中创建用于上传数据的类&amp;lt;syntaxhighlight lang=&amp;quot;c#&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
 public partial class TightCoupler&lt;br /&gt;
 {&lt;br /&gt;
     // Should put into medulla.&lt;br /&gt;
     public static SharedObject externalFeed;&lt;br /&gt;
     public static void PostExternalFeed(ExternalFeed obj, string name)&lt;br /&gt;
     {&lt;br /&gt;
         externalFeed ??= new SharedObject(name);&lt;br /&gt;
         byte[] buf = new byte[1024];&lt;br /&gt;
         using Stream stream = new MemoryStream(buf);&lt;br /&gt;
         using BinaryWriter bw = new BinaryWriter(stream);&lt;br /&gt;
         bw.Write(obj.name);&lt;br /&gt;
         bw.Write(obj.counter);&lt;br /&gt;
         bw.Write(obj.hasTranslation);&lt;br /&gt;
         bw.Write(obj.hasRotation);&lt;br /&gt;
         bw.Write(obj.is3D);&lt;br /&gt;
         bw.Write(obj.is2D);&lt;br /&gt;
         bw.Write(obj.integrated);&lt;br /&gt;
         bw.Write(obj.toRemap);&lt;br /&gt;
         bw.Write(obj.startingTick);&lt;br /&gt;
         bw.Write(obj.x);&lt;br /&gt;
         bw.Write(obj.y);&lt;br /&gt;
         bw.Write(obj.z);&lt;br /&gt;
         bw.Write(obj.th);&lt;br /&gt;
         bw.Write(obj.pitch);&lt;br /&gt;
         bw.Write(obj.roll);&lt;br /&gt;
         externalFeed.Post(buf.Take((int)stream.Position).ToArray());&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     public class ExternalFeed&lt;br /&gt;
     {&lt;br /&gt;
         // always aggregates.&lt;br /&gt;
         public string name;&lt;br /&gt;
         public long counter; // increment one per frame.&lt;br /&gt;
         public bool hasTranslation, hasRotation, is3D, is2D, integrated, toRemap;&lt;br /&gt;
         public long startingTick;&lt;br /&gt;
         public float x, y, z, th, pitch, roll;&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;由于上传的数据要求无重复，且轨迹平滑，所以直接在motorRoutine中进行处理，保证每次读到驱动器数据后进行一次上传。&lt;br /&gt;
&lt;br /&gt;
以差速轮底盘为例，进行轨迹计算。首先计算车轮在此次循环中走过的路程，单位使用毫米。由于是差速轮模型，所以车体此时的里程变换应该是左右轮变化量和的一半。&lt;br /&gt;
&lt;br /&gt;
然后使用此次循环imu数据和上次循环做差，得到此时间段车辆角度变换。&lt;br /&gt;
&lt;br /&gt;
然后在之前位置的基础上，加上此次位置变换，即不断对位置变化量做积分得到目前的位置，得到最新的位置，然后post给detour使用。&lt;br /&gt;
&lt;br /&gt;
ExternalFeed中数据含义如下表&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!名称&lt;br /&gt;
!h含义&lt;br /&gt;
|-&lt;br /&gt;
|name&lt;br /&gt;
|名称&lt;br /&gt;
|-&lt;br /&gt;
|x&lt;br /&gt;
|定位的x坐标&lt;br /&gt;
|-&lt;br /&gt;
|y&lt;br /&gt;
|定位的y坐标&lt;br /&gt;
|-&lt;br /&gt;
|th&lt;br /&gt;
|定位的th&lt;br /&gt;
|-&lt;br /&gt;
|hasTranslation&lt;br /&gt;
|定位信息中是否包含x、y（如纯imu就只有角度）&lt;br /&gt;
|-&lt;br /&gt;
|hasRotation&lt;br /&gt;
|定位信息中是否包含th（如纯gps只有坐标）&lt;br /&gt;
|-&lt;br /&gt;
|is2D&lt;br /&gt;
|是否是2D位姿&lt;br /&gt;
|-&lt;br /&gt;
|startingTick&lt;br /&gt;
|startingTick不变时，认为是一个连续的轨迹&lt;br /&gt;
|-&lt;br /&gt;
|counter&lt;br /&gt;
|计数，每个循环+1&lt;br /&gt;
|-&lt;br /&gt;
|integrated&lt;br /&gt;
|是否通过积分得到的位姿（轮里程计通过积分获得，gps是绝对位置）&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c#&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
var leftDelta = cart.ActualLeftWheelPos - lastLeftWheelEncoder;&lt;br /&gt;
var rightDelta = cart.ActualRightWheelPos - lastRightWheelEncoder;&lt;br /&gt;
var distanceDelta = (leftDelta + rightDelta) / 2f;&lt;br /&gt;
var thDelta = MathTools.thDiff((float)cart.GyrosTh, (float)lastGyro);&lt;br /&gt;
var moveTup = Tuple.Create(distanceDelta, 0f, thDelta);&lt;br /&gt;
var curMode = cart.NavigationMode;&lt;br /&gt;
var moved = MathTools.Transform2D(&lt;br /&gt;
    Tuple.Create(cart.InertialNavigationX, cart.InertialNavigationY,&lt;br /&gt;
        cart.InertialNavigationTh), moveTup);&lt;br /&gt;
cart.InertialNavigationX = moved.Item1;&lt;br /&gt;
cart.InertialNavigationY = moved.Item2;&lt;br /&gt;
cart.InertialNavigationTh = moved.Item3;&lt;br /&gt;
lastLeftWheelEncoder = cart.ActualLeftWheelPos;&lt;br /&gt;
lastRightWheelEncoder = cart.ActualRightWheelPos;&lt;br /&gt;
lastGyro = cart.GyrosTh;&lt;br /&gt;
&lt;br /&gt;
TightCoupler.PostExternalFeed(new TightCoupler.ExternalFeed()&lt;br /&gt;
    {&lt;br /&gt;
        name = &amp;quot;wheel&amp;quot;,&lt;br /&gt;
        x = cart.InertialNavigationX,&lt;br /&gt;
        y = cart.InertialNavigationY,&lt;br /&gt;
        th = cart.InertialNavigationTh,&lt;br /&gt;
        hasTranslation = true,&lt;br /&gt;
        hasRotation = true,&lt;br /&gt;
        is2D = true,&lt;br /&gt;
        startingTick = startTime,&lt;br /&gt;
        counter = counter++,&lt;br /&gt;
        integrated = true,&lt;br /&gt;
    }, &amp;quot;cart_odometry&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;此时就完成了轮里程计数据的上传，然后需要在detour中添加数据源来使用此数据。&lt;br /&gt;
&lt;br /&gt;
首先在detour车体布局中，添加外部定位源，并将name字段改为&amp;quot;cart_odometry&amp;quot;，将该定位源的x、y、th都改为0，然后点击动作中的捕捉，此时可以在状态中看到数据已经在跳动了。此时代表轮里程计已经参与到detour的tc计算中。&lt;br /&gt;
[[文件:C4e06e908e2e3f4c9223045ee89fd5d.png|居中|缩略图|500x500像素]]&lt;br /&gt;
&lt;br /&gt;
=== 3.耦合效果判定 ===&lt;br /&gt;
可以在detour-里程计-里程计状态中进行查看。&lt;br /&gt;
[[文件:954a68c5edbe408b7ef7293a7206706.png|居中|缩略图|500x500像素]]&lt;br /&gt;
需要在稳定的环境中进行测试，即激光、地纹、轮里程计都无外部影响。此时的现象应该是，多个里程计交替成为最好传感器，且没有传感器被频繁丢弃。&lt;br /&gt;
&lt;br /&gt;
=== 4.Q&amp;amp;A ===&lt;br /&gt;
Q：若轮里程计始终是最好传感器或轮里程计频繁被丢弃，会是什么原因&lt;br /&gt;
&lt;br /&gt;
A：detour判断最好传感器时，是根据此里程计提供的轨迹进行判断，轨迹越平滑、越合理，则会成为最好传感器。所以若轮里程计始终是最好传感器，需要查看轮里程计上传周期是否过于频繁，导致上传的轨迹”异常“的平滑和合理。一般将motorRoutine的扫描周期设为50ms，此时轮里程计也是50ms上传一次。若轮里程计被频繁丢弃，则需从两个方面检查，首先查看上传频率是否过低，导致位置虽然正确，但是不平滑，从而被detour丢弃。然后查看数据源是否正确，可以暂停其它里程计，仅使用轮里程计，通过Simple下发任务，看小车位置是否和激光提供的定位误差有多大。具体操作如下，在定位稳定的环境下建好激光地图，然后在一个点找到此时的激光定位（锁定到正确的关键帧），然后暂停激光里程计，通过simple下发任务，让小车进行行走、自旋、转弯等操作，然后记录此时位置，然后恢复激光里程计，再次找到此时的激光定位，记录此时位置，比较两次记录的位置是否有较大差异。&lt;br /&gt;
&lt;br /&gt;
Q：陀螺仪选型标准是什么&lt;br /&gt;
&lt;br /&gt;
A：笔者使用瑞芬tl740d进行测试，可以满足紧耦合要求，测试结果如下图，可作为参考，打码的为另一品牌陀螺仪&lt;br /&gt;
[[文件:618e4f05b59db604d4e312d6f0ef72b.png|居中|缩略图|600x600像素]]&lt;/div&gt;</summary>
		<author><name>Yuhang</name></author>
	</entry>
</feed>