[carla] GNSS传感器与Carla坐标系 转换方法

news2024/11/17 1:31:37

文章目录

  • 方法1:通过python API直接获取转换后坐标
    • 1.1 GNSS传感器消息-内容介绍
    • 1.2 在线获取方法
    • 1.3 完整代码
  • 方法2-通过离线读取转换关系的方式转换
    • 2.1 转换类代码和使用方法
    • 2.2 转换矩阵保存和读取
    • 2.3 运行结果
    • 2.5 注意事项
  • 附件 所有地图的转换矩阵
  • 参考链接:

方法1:通过python API直接获取转换后坐标

这种方法是直接通过carla提供的pythonAPI建立客户端,直接从carla服务器中读取GNSS传感器消息.
要求你在本地启动carla服务器.并编写python脚本在线获取.
而如果通过carla-ros-bridge转发后的GNSS消息,是不能够存储转换关系的.所以这种方法是不适用与rosbag包的.

1.1 GNSS传感器消息-内容介绍

关于gnss传感器,CARLA官方文档-GNSS中展示了它输出的消息内容:
在这里插入图片描述
Output attributes可以看到,传感器输出的data中包含:

  • 当前帧frame,
  • 时间戳timestamp,
  • carla转换关系transform
  • 经度longitude,纬度latitude和海拔altitude.

1.2 在线获取方法

因此,想要获取gnss到carla坐标系的转换,我们可以直接从transform中拿.这个transform的格式是carla.Transform,包含location和rotation.
在这里插入图片描述
下面的函数是将location和rotation中的坐标存储到txt中

def save_pose(ego_vehicle):
    # world_2_camera = camera.get_transform().get_matrix()
    t = ego_vehicle.get_transform()
    global_location_x = t.location.x
    global_location_y = t.location.y
    global_location_z = t.location.z
    global_rotation_yaw = t.rotation.yaw
    global_rotation_pitch = t.rotation.pitch
    global_rotation_roll = t.rotation.roll

    pose_file = cfg.save_root + f"{cfg.map}/poses/{save_idx:0>2d}.txt"

    context = f"{global_location_x} {global_location_y} {global_location_z} " \
              f"{global_rotation_yaw} {global_rotation_pitch} {global_rotation_roll}\n"
    # mkdir_folder(pose_file)
    with open(pose_file, 'a', encoding='utf-8') as f:
        f.write(context)

1.3 完整代码

import numpy as np
import carla

if __name__ == '__main__':
    # >>>>>获取地图并计算转换矩阵
    client=carla.Client('127.0.0.1',2000)
    # world=client.load_world('Town07')
    world=client.get_world()
    map=world.get_map()

    
    # >>>>>获取车辆当前的gnss并打印信息:
    actors=world.get_actors()
    gnss_actor_list = actors.filter('*gnss*') #找到gnss
    gnss_actor = gnss_actor_list[0]
    print(gnss_actor)
    car_longitude=0.0
    car_latitude=0.0
    car_altitude=0.0
    car_transform=None
    def callback(data):
        global car_longitude,car_latitude,car_altitude
        print(f">>>>>>gnss传感器geo坐标值: longitude 经度:{data.longitude},latitude 维度:{data.latitude},altitude 海拔:{data.altitude}")
        car_longitude=data.longitude
        car_latitude=data.latitude
        car_altitude=data.altitude
        car_transform=data.transform
        print(f">>>>>>gnss传感器中的carla坐标值 x:{car_transform.location.x},y:{car_transform.location.y},z:{car_transform.location.z}")
    gnss_actor.listen(lambda data: callback(data))
    

    times = 0
    while times < 1:
        print('----------------------------------------------------')
        times +=1
        world.tick()

运行结果:
在这里插入图片描述
自动打印车辆当前的geoLocation和转换后的carlaLocation.

方法2-通过离线读取转换关系的方式转换

这里我们不像方法1那样直接获取转换后的坐标,而是事先计算出转换关系矩阵然后离线存储起来.下一次用的时候就可以直接调用,而无需在线获取.

2.1 转换类代码和使用方法

我们先给出这个转换类:

class Geo2Location(object):
    """
    Helper class for homogeneous transform from geolocation

    This class is used by GNSS class to transform from carla.GeoLocation to carla.Location.
    This transform is not provided by Carla, but it can be solved using 4 chosen points.
    Note that carla.Location is in the left-handed coordinate system.
    """

    def __init__(self, carla_map):
        """ Constructor method """
        self._map = carla_map
        # Pick 4 points of carla.Location
        loc1 = carla.Location(0, 0, 0)
        loc2 = carla.Location(1, 0, 0)
        loc3 = carla.Location(0, 1, 0)
        loc4 = carla.Location(0, 0, 1)
        # Get the corresponding carla.GeoLocation points using carla's transform_to_geolocation()
        geoloc1 = self._map.transform_to_geolocation(loc1)
        geoloc2 = self._map.transform_to_geolocation(loc2)
        geoloc3 = self._map.transform_to_geolocation(loc3)
        geoloc4 = self._map.transform_to_geolocation(loc4)
        # Solve the transform from geolocation to location (geolocation_to_location)
        l = np.array([[loc1.x, loc2.x, loc3.x, loc4.x],
                      [loc1.y, loc2.y, loc3.y, loc4.y],
                      [loc1.z, loc2.z, loc3.z, loc4.z],
                      [1, 1, 1, 1]], dtype=float)
        g = np.array([[geoloc1.latitude, geoloc2.latitude, geoloc3.latitude, geoloc4.latitude],
                      [geoloc1.longitude, geoloc2.longitude,
                          geoloc3.longitude, geoloc4.longitude],
                      [geoloc1.altitude, geoloc2.altitude,
                          geoloc3.altitude, geoloc4.altitude],
                      [1, 1, 1, 1]], dtype=float)
        # Tform = (G*L^-1)^-1
        self._tform = np.linalg.inv(g.dot(np.linalg.inv(l)))
        # self._tform = np.linalg.inv(g).dot(l)

    def transform(self, geolocation):
        """
        Transform from carla.GeoLocation to carla.Location (left_handed z-up).

        Numerical error may exist. Experiments show error is about under 1 cm in Town03.
        """
        geoloc = np.array(
            [geolocation.latitude, geolocation.longitude, geolocation.altitude, 1])
        loc = self._tform.dot(geoloc.T)
        return carla.Location(loc[0], loc[1], loc[2])

    def get_matrix(self):
        """ Get the 4-by-4 transform matrix """
        return self._tform
    def set_matrix(self,matrix):
        """ set the 4-by-4 transform matrix """
        self._tform = matrix

再给出类的使用方法的demo,在这个demo中.我们以一台车的坐标作为测试对象,验证我们的转换方法是否正确.


if __name__ == '__main__':
    # >>>>>获取地图并计算转换矩阵
    client=carla.Client('127.0.0.1',2000)
    # world=client.load_world('Town07')
    world=client.get_world()
    map=world.get_map()

    
    # >>>>>获取车辆当前的gnss并打印信息:
    actors=world.get_actors()
    gnss_actor_list = actors.filter('*gnss*') #找到gnss
    gnss_actor = gnss_actor_list[0]
    print(gnss_actor)
    car_longitude=0.0
    car_latitude=0.0
    car_altitude=0.0
    car_transform=None
    def callback(data):
        global car_longitude,car_latitude,car_altitude
        print(f">>>>>>gnss传感器值:data.longitude 经度:{data.longitude},latitude 维度:{data.latitude},altitude 海拔:{data.altitude}")
        car_longitude=data.longitude
        car_latitude=data.latitude
        car_altitude=data.altitude
        car_transform=data.transform
        print(f"x:{car_transform.location.x},y:{car_transform.location.y},z:{car_transform.location.z}")
    gnss_actor.listen(lambda data: callback(data))
    

    times = 0
    while times < 1:
        print('----------------------------------------------------')
        times +=1
        world.tick()
        # >>>>>>获取车辆的carla.Location并打印信息:
        vehicle_actor_list=actors.filter('*vehicle*')
        vehicle_actor=vehicle_actor_list[0]
        vehicle_location=vehicle_actor.get_location()
        print(f">>>>>>车辆坐标读取值:vehicle location x:{vehicle_location.x},y:{vehicle_location.y},z:{vehicle_location.z}")
        
        # >>>>>carla.GeoLocation -> carla.Location:  
        # 使用Geo2Location类转换
        g2l_obj=Geo2Location(map) #通过加入地图map计算转换矩阵
        trans_matrix=g2l_obj.get_matrix() #转换矩阵
        save_numpy(trans_matrix, 'town07')
        matrix_val=load_numpy_txt('town07')
        g2l_obj.set_matrix(matrix_val)
        
        car_gnss=carla.GeoLocation(longitude=car_longitude,latitude=car_latitude,altitude=car_altitude)
        car_location=carla.Location()
        car_location=g2l_obj.transform(car_gnss)
        print(f'>>>>>>转换后值车辆坐标值:car_location x:{car_location.x},y:{car_location.y},z:{car_location.z}')
        print('----------------------------------------------------')

2.2 转换矩阵保存和读取

2.1中还涉及到一个保存和载入转换矩阵的函数,将转换矩阵保存成txt和npy两种格式.

def save_numpy(array,name):
    path_txt=f'./transferMatric_G2L/{name}.txt'
    path_np=f'./transferMatric_G2L/{name}.npy'
    np.savetxt(path_txt, array)
    np.save(path_np, array)

def load_numpy_txt(name):
    path_txt=f'./transferMatric_G2L/{name}.txt'
    # path_np=f'./transferMatric_G2L/{name}.npy'
    return np.loadtxt(path_txt)
    # np.load(path_np)

def load_numpy_np(name):
    # path_txt=f'./transferMatric_G2L/{name}.txt'
    path_np=f'./transferMatric_G2L/{name}.npy'
    # np.load(path_txt)
    return np.load(path_np)

通过调用上述函数,就可以获取转换矩阵文件,对应每一个地图.
在这里插入图片描述

2.3 运行结果

我们通过carla-ros-bridge开启了一个节点,召唤了一台车,界面左侧展示了一些粗略的信息.

需要注意的是:这里的Location,GNSS和height都比较粗略,所以仅供参考.

在这里插入图片描述
然后我们运行2.1的main程序,会打印出4个结果,分别是:

  1. gnss传感器中的geoLocation值
  2. gnss传感器中的carla坐标值
  3. 通过API读取的carla坐标值(也就是车辆当前的值)
  4. 离线转换的carla坐标值(我们计算出来的值)

在这里插入图片描述
可以清楚的看到, 2,3,4得到的值完全一致,也就证明了我们转换矩阵的有效性.

2.5 注意事项

这里生成的GNSS传感器的坐标设置在(0,0,0)位置,也就是和当前车辆完全一致的位置,其他位置的GNSS传感器带进去计算的话,计算的就不是车辆本身的Location了.

附件 所有地图的转换矩阵

点击:我的gitte代码库
找到transferMatric_Geo2Loc文件夹

参考链接:

github 讨论贴: https://github.com/carla-simulator/carla/issues/2737

坐标转换代码来源:https://github.com/lian999111/carla-semantic-localization/blob/c4844f2f6b8bbc21c8e3e4962954cf01eb673e85/carlasim/data_collect.py

carla-geolocation:https://carla.readthedocs.io/en/latest/python_api/#carlageolocation

carla-location:https://carla.readthedocs.io/en/latest/python_api/#carla.Location

carla.GnssMeasurement:https://carla.readthedocs.io/en/latest/python_api/#carla.GnssMeasurement

GNSS sensorhttps://carla.readthedocs.io/en/latest/ref_sensors/#gnss-sensor

carla.tranform https://carla.readthedocs.io/en/latest/python_api/#carlatransform

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

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

相关文章

工作中学到的一些小点

1.结构体对齐 记得之前面试的时候被问过这个问题【汗】 这个结构体占多大 struct sExample {char c;int n; };占8字节&#xff0c;问有没有办法让它占5个字节&#xff1f; 有 #pragma pack(push) //保存对齐状态 #pragma pack(1) //设定为1字节对齐struct sExample {char c;…

qt串口配置(端口号列表选择/自动保存/初始化模板)复制粘贴直接用

一、前言 废话不多说&#xff0c;写这个作为串口模板&#xff0c;后续会继续补充其他模板&#xff0c;有相识功能直接复制模板里东西到程序中&#xff0c;直接使用&#xff0c;无需大的调整&#xff0c;为自己模板记录&#xff0c;也提供给需要的朋友们。 二、环境 qt5.7 win…

R15.3-15.3-15.3-15.3A_哈威泵_样本及应用

R15.3-15.3-15.3-15.3A_哈威泵_样本及应用R11.8-11.8-11.8-11.8-BABSL_水泥行业用主用于钢厂&#xff0c;油田&#xff0c;水利&#xff0c;飞机&#xff0c;压铸机等重型液压设备。 对油泵R11.8-11.8-11.8-11.8-BABSL_水泥行业用的维护保养应注意以下方面&#xff1a; 1.会腐…

项目需求及架构设计

第2章 项目需求及架构设计 2.1 项目需求分析 用户行为数据采集平台搭建 用户行为数据会以文件的形式存储在服务器&#xff0c;这个阶段需要考虑&#xff1a;采集用户行为数据使用的工具,需要提供详细的设计需求 如&#xff1a;flume&#xff0c;flume采用的 source、channel、…

HDFS的Shell操作

该文章主要为完成实训任务及总结&#xff0c;详细实现过程及结果见【参考文章】 参考文章&#xff1a;https://howard2005.blog.csdn.net/article/details/127170478 文章目录一、 三种Shell命令方式二、FileSystem Shell文档三、常用Shell命令四、实例练习1、创建目录2、查看目…

这位00后经历人生重大变故后,选择了智能家居,选择了Aqara绿米

作者 | 布斯 编辑 | 小沐 出品 | 智哪儿 zhinaer.cn编者按&#xff1a;虽然概念由来已久&#xff0c;但智能家居如今依然属于新兴产业。而这样一个当今在全国范围遍地开花的新型商业存在&#xff0c;已经创造了许多的就业岗位与创业机会&#xff0c;也隐藏着许多让人回味的故事…

Profinet总线模拟输出模块

上电后&#xff0c;耦合器自动识别所有与之相连的 I/O 模块&#xff0c;并根据模块的类型、数据宽度和模块在节点中的位置创建内部本地过程映像。 如果添加、更改或移除 I/O 模块&#xff0c;会建立新的过程映像&#xff0c;过程数据地址会改变。在添加 I/O 模块时&#xff0c…

【MySQL】MySQL执行计划与SQL调优提高查询效率(优化篇)(实战篇)(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

Pixel Difference Networks for Efficient Edge Detection论文笔记

文章目录一、背景知识二、Pixel Difference Convolution&#xff08;PDC&#xff09;1.CPDC2.APDC3.RPDC三、轻量化边缘检测网络A. Block_x_yB. CSAMC. CDCMD. 1*1卷积层E. 深度监督&#xff08;deep supervision&#xff09;F. 损失函数四、实验结果1. 消融实验2.网络可扩展性…

SpringAMQP简介及简单使用

一、SpringAMQP简介 SpringAMQP是基于RabbitMQ封装的一套模板&#xff0c;并且还利用SpringBoot对其实现了自动装配&#xff0c;使用起来非常方便。 SpringAmqp的官方地址&#xff1a;https://spring.io/projects/spring-amqp SpringAMQP提供了三个功能&#xff1a; 自动声明…

Maven基础概念

仓库 仓库用于存储资源&#xff0c;包含各种jar包。 仓库分类&#xff1a; 本地仓库&#xff1a;自己电脑作为仓库&#xff0c;连接远程仓库获取资源。远程仓库&#xff1a;非本地的仓库&#xff0c;为本地仓库提供资源。中央仓库&#xff1a;由Maven团队维护&#xff0c;存…

【Servlet】4:详解请求对象 HttpServletRequest

目录 | 请求对象 HttpServletRequest接口 HttpServletRequest的基本概述 请求对象获取 URL & Method 请求对象获取 参数名 请求对象获取 参数值 参数值乱码问题 本文章属于后端全套笔记的第三部分 &#xff08;更新中&#xff09;【后端入门到入土&#xff01;】Java…

CAN电压测试

CAN总线&#xff1a; 一般用在汽车&#xff0c;伺服驱动器&#xff0c;步进驱动器&#xff0c;舵机&#xff0c;分布式io等设备上。 有以太网转CAN和4G网转CAN。 当然得到数据后&#xff0c;可以往RS485等上面转。 只需要2根线&#xff1a; H和L线&#xff0c;终端再并联120…

Linux history 命令相关使用以及配置

Linux history 命令相关使用以及配置 Linux history 新手学习 shell 的时候都知道 history 命令能帮助我们查看之前运行的命令集合&#xff0c;通过这个能够帮我们回忆之前的命令&#xff0c;以及进行各种排错等等。 比如我们直接输入 history 进行查看&#xff1a; histor…

Flutter高仿微信-第20篇-支付-充值

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 实现代码&#xff1a; /*** Author : wangning* Email : maoning20080809163.…

Android AIDL跨进程通信基础(多端情况)

简介 AIDL建议在来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL&#xff0c;其他情况下你都可以选择其他方法&#xff0c;如使用 Messenger&#xff0c;也能跨进程通信。可见 AIDL 是处理多线程、多客户端并发访问的&#xff0c;而 Messenger 是单线程…

年末盘点时间——用Python绘制饼状图对商品库存进行分析

人生苦短&#xff0c;我用python 存货盘点最重要的是什么&#xff0c;盘点比例要达到&#xff0c; 比如说要达到80%&#xff0c;于是就拿着企业给导的进销存明细表&#xff0c; 于是就开始筛选大金额的存货作为选择的样本&#xff0c; 这样就够比例了。 可是实际盘点的时候…

手把手教你在ARM板上写一个驱动程序!

摘要&#xff1a;搞嵌入式有两个方向&#xff0c;一个是嵌入式软件开发(MCU方向)&#xff0c;另一个是嵌入式软件开发(Linux方向)。其中MCU方向基本是裸机开发和RTOS开发。而Linux开发方向又分为驱动开发和应用开发。其中应用开发相比于驱动开发来说简单一些&#xff0c;因为搞…

初阶指针---从入门到入坟

今天我们来见识一下c语言里让万千少年少女从入门到入坟的一道大门槛——指针 目录 1.指针是什么&#xff1f; 2.指针和指针类型 3.野指针 4. 指针运算 5. 指针和数组 6. 二级指针 7. 指针数组 1.指针是什么&#xff1f; 指针理解的2个要点&#xff1a; 1. 指针是内存中一…

C语言:计算阶乘与计算从1加到100的代码对比:都要用到3个变量,不同之处在于表达式

计算1 到 100 之间所有整数之和 #include <stdio.h> int main() {int i1,total0;while(i<100)//不能在 while 后面加分号{totali;i;//循环内要有使循环趋近于假的操作}printf("%d\n",total);return 0; } 和下面对比&#xff0c;只不过是100用输入j来代替了 …