配置IsaacLab环境

IsaacLab本地安装的方式有两种 通过PIP安装 二进制安装 本次课程将使用二进制安装 安装要求 系统要求 Element Minimum Spec Good Ideal OS Ubuntu 20.04/22.04、Windows 10/11 Ubuntu 20.04/22.04、Windows 10/11 Ubuntu 20.04/22.04、Windows 10/11 CPU Intel Core i7 (7th Generation)、AMD Ryzen 5 Intel Core i7 (9th Generation)、AMD Ryzen 7 Intel Core i9, X-series or higher、AMD Ryzen 9, Threadripper or higher Cores 4 8 16 RAM 32GB* 64GB* 64GB* Storage 50GB SSD 500GB SSD 1TB NVMe SSD GPU GeForce RTX 3070 GeForce RTX 4080 RTX Ada 6000 VRAM 8GB* 16GB* 48GB* 本机配置 描述 地址 显卡 RTX 3080 Ti 操作系统 PopOS(一款基于Ubuntu的操作系统) https://pop.system76.com IsaacSim 4.2.0 https://developer.nvidia.com/omniverse#section-getting-started IsaacLab 最新的main分支 https://github.com/isaac-sim/IsaacLab Anaconda Anaconda3-2024.10-1-Linux-x86_64 https://docs.anaconda.com/anaconda/install 🎉 开始安装! 1. Anaconda安装(Linux) # 安装依赖 sudo apt-get install libgl1-mesa-glx libegl1-mesa libxrandr2 libxrandr2 libxss1 libxcursor1 libxcomposite1 libasound2 libxi6 libxtst6 # 下载 & 安装anaconda curl -O https://repo.anaconda.com/archive/Anaconda3-2024.10-1-Linux-x86_64.sh bash ~/Anaconda3-2024.10-1-Linux-x86_64.sh # 刷新环境变量 source ~/.zshrc # 或source ~/.bashrc 2. 安装Omniverse Launcher # 下载Omniverse Launcher wget https://install.launcher.omniverse.nvidia.com/installers/omniverse-launcher-linux.AppImage # 添加可执行权限 chmod +x omniverse-launcher-linux.AppImage # 运行 ./omniverse-launcher-linux.AppImage 运行后出现如下界面,然后输入邮箱账号登陆(没注册过的需要先注册) ...

November 20, 2024 · 2 min · 300 words · FakeRick

Rust嵌入式开发embassy环境搭建

先配置Rust开发STM32所需的环境,文章地址: https://fake-rick.github.io/posts/rust%E9%85%8D%E7%BD%AEstm32%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/ 安装项目创建CLI工具 cargo install cargo-embassy 生成项目 cargo embassy init my_project --chip stm32f407vgtx 在Cargo.toml中[dependencies]添加: embassy-stm32 = { version = "0.1.0", features = ["defmt", "stm32f407vg", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } Embed.toml文件 # This file was automatically generated. [default.general] chip = "STM32F407VGTx" [default.reset] halt_afterwards = false [default.rtt] enabled = true [default.gdb] enabled = false 运行 cargo run 如果在终端出现以下内容则表示运行成功:

August 5, 2024 · 1 min · 57 words · FakeRick

Rust配置STM32嵌入式开发环境

安装 安装cargo工具 cargo install cargo-generate 安装stlink v2驱动 sudo apt-get install git make cmake libusb-1.0-0-dev sudo apt-get install gcc build-essential git clone https://github.com/stlink-org/stlink.git cd stlink/ mkdir build cd build cmake .. make cd bin/ sudo cp st-* /usr/local/bin cd ../lib/ sudo cp *.so* /lib32 cd ../../ sudo cp config/udev/rules.d/49-stlinkv* /etc/udev/rules.d/ 安装烧录和调试的工具 Linux, macOS curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.sh | sh WIndows irm https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-tools-installer.ps1 | iex 安装适用于ARM Cortex-M目标的rust-std组件 rustup target add thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf ...

August 4, 2024 · 1 min · 132 words · FakeRick

IsaacLab创建直接工作流RL环境

原文地址:https://isaac-sim.github.io/IsaacLab/source/tutorials/03_envs/create_direct_rl_env.html 从环境中获取信息(观察) 获取joint(铰链)信息:位置和速度 joint会被包含在Articulation(关节)中,一个Articulation可能会包含1个或多个的joint对象,可以通过Articulation.find_joints()方法获得joint在当前Articulation中的索引(index)数据。 find_joints的返回值是这样的:tuple[list[joint索引], list[joint名字]] find_joints的函数声明如下: def find_joints( self, name_keys: str | Sequence[str], joint_subset: list[str] | None = None, preserve_order: bool = False ) -> tuple[list[int], list[str]] 在Articulation内部有一个属性私有变量_data: ArticulationData,该变量通过方法def data(self) -> ArticulationData获取,在ArticulationData中存放着几个关节重要的数据:位置ArticulationData._joint_pos,速度ArticulationData._joint_vel,加速度ArticulationData._joint_acc 在ArticulationData有几个@property装饰器函数,用于获取上述的三个属性,这样可以用过属性名的方式直接访问到这些数据。 下面介绍下这三个方法的返回值: joint_pos返回torch.Size([num_instances, num_joints]) joint_vel返回torch.Size([num_instances, num_joints]) joint_acc返回torch.Size([num_instances, num_joints]) 是时候讲解下DirectRLEnv(gym.Env)._get_observations(self) -> VecEnvObs方法了,该方法带有@abstractmethod被定义成抽象方法,所以我们在继承DirectRLEnv类后必须在自己的类中实现_get_observations方法。 我们在_get_observations方法中计算并返回观测值,这会用到上面提到的ArticulationData以及如何通过joint索引从中获取实际数据。 在cartpole_env.py的代码中有如下实现: def _get_observations(self) -> torch.Dict[str, torch.Tensor | torch.Dict[str, torch.Tensor]]: obs = torch.cat( ( self.joint_pos[:, self._pole_dof_idx[0]].unsqueeze(dim=1), self.joint_vel[:, self._pole_dof_idx[0]].unsqueeze(dim=1), self.joint_pos[:, self._cart_dof_idx[0]].unsqueeze(dim=1), self.joint_vel[:, self._cart_dof_idx[0]].unsqueeze(dim=1), ), dim=-1, ) observations = {"policy": obs} return observations 上述代码中的_pole_dof_idx里边存放的是杆子的joint对应的索引数据,_cart_dof_idx存放的是小车的joint对应的索引数据,这里介绍下获取杆子位置的代码,获取杆子速度和小车位置和速度的代码都一样。 ...

July 21, 2024 · 2 min · 330 words · FakeRick

Park变换

Park变换 Park变换的目的是将Clark变换后的αβ坐标系转换成d,q旋转坐标系。d轴方向与转子磁链方向重合,所以d轴也叫直轴。q轴方向与转子磁链方向垂直,所以q轴又叫交轴。 旋转矩阵是什么? ⊿abo: $ob = oa\times \cos(\theta)$ 已知:bc = ad $$ \because \angle pad + \angle pab = 90°\\ \angle oab + \angle pab = 90°\\ \therefore \angle oab = \angle pad\\ \angle aob = \angle apd = \angle \theta $$⊿adp: $ad = ap \times \sin(\theta)$ $$ \because oc = ob + bc \\ \therefore oc = oa \times \cos(\theta) + ap \times \sin(\theta) $$所以向量p到d轴的投影为:$oa \times \cos(\theta) + ap \times \sin(\theta)$ ...

July 18, 2024 · 2 min · 281 words · FakeRick

Clark变换矩阵

什么是Clark变换? Clark变换将三相系统(在 abc 坐标系中)的时域分量转换为正交静止坐标系 (αβ) 中的两个分量。 利用基变换来实现三相坐标系(abc)到两相正交坐标系(αβ) 已知三相坐标系的相位依次相差120°且αβ为正交坐标系。 将α轴与a轴重叠,将向量a沿着原点O的方向延长做一条辅助线,∠boe和∠coe等于60°。 计算向量b和向量c到α轴的投影长度: $$ be = \sin(∠boe) = \sin(60°) = \frac{\sqrt{3}}{2} \\ ce = -\sin(∠coe) = -\sin(60°) = -\frac{\sqrt{3}}{2} $$因为向量c在α轴的下方所以投影为负 计算向量b和向量c到β轴的投影长度: $$ bg = -\cos(∠boe) = -\cos(60°) = -\frac{1}{2} \\ ch = -\cos(∠coe) = -\cos(60°) = -\frac{1}{2} $$因为向量b和向量c在β轴的左侧所以投影为负 组合出基变换矩阵 根据上面的投影可以得到a,b,c三个向量的坐标:向量 $a=[1, 0]$,向量$b=[-\frac{1}{2},\frac{\sqrt{3}}{2}] $,向量 $c=[-\frac{1}{2},-\frac{\sqrt{3}}{2}] $ 所以基变换矩阵为: $$ A = \left[ \begin{matrix} 1 & -\frac{1}{2} & -\frac{1}{2} \\ 0 & \frac{\sqrt{3}}{2}& -\frac{\sqrt{3}}{2} \end{matrix} \right] $$坐标转换公式为: ...

July 18, 2024 · 2 min · 354 words · FakeRick

Qt使用Keepalive机制实现断线重连

QTcpSocket能够检测到Socket的连接与断开状态,并触发相关信号,我们只需要关联信号与槽就能够知道连接状态。 connect(&m_socket, &QTcpSocket::connected, this, &TcpClient::onConnected, Qt::QueuedConnection); connect(&m_socket, &QTcpSocket::disconnected, this, &TcpClient::onDisconnected, Qt::QueuedConnection); 还有一些特殊情况是无法触发QTcpSocket::disconnected信号,比如说:网线突然拔了、对端设备突然爆掉了等。这类情况由于对端socket未正常调用close()方法而导致的。 我们可以定义一个心跳包去定期检查对端的存活状态,这种做法在协议还未指定的初期是比较适合的,客户端与服务端制定一套心跳请求与应答机制来判断对端的存活状态。但是往往下位机的程序已经存在(开发者不愿意修改或增加现有协议),这时候如何能够在特殊情况下检测到网络断开呢? 主角登场:Keepalive机制 keepalive简介(摘自维基百科) 传输控制协议(TCP)存活包为可选特性,且默认关闭。存活包内没有数据。在以太网网络中,存活包的大小为最小长度的几帧(64字节)。协议中,还有三个与存活包相关的参数: 存活时长(英语:Keepalive time)即空闲时,两次传输存活包的持续时间。TCP存活包时长可手动配置,默认不少于2个小时。 存活间隔(英语:Keepalive interval)即未收到上个存活包时,两次连续传输存活包的时间间隔。 存活重试次数(英语:Keepalive retry)即在判断远程主机不可用前的发送存活包次数。当两个主机透过TCP/IP协议相连时,TCP存活包可用于判断连接是否可用,并按需中断。 多数支持TCP协议的主机也同时支持TCP存活包。每个主机按一定周期向其他主机发送TCP包来请求回应。若发送主机未收到特定主机的回应(ACK),则将从发送主机一侧中断连接。 若其他主机在连接关闭后发送TCP存活包,关闭连接的一方将发送RST包来表明旧连接已不可用。其他主机将关闭它一侧的连接以新建连接。 空闲的TCP连接通常会隔每45秒或60秒发送一次存活包。在未连续收到三次ACK包时,连接将中断。此行为因主机而异,如默认情况下的Windows主机将在7200000ms(2小时)后发送首个存活包,随后再以1000ms的间隔发送5个存活包。若任意存活包未收到回应,连接将被中断。 Qt开启Keepalive(Linux与Windows) #include "keepalive.h" #include <QObject> const int keepalive = 1; // 开启keepalive属性 const int keepidle = 5; // 如果连接在5秒内没有任何数据来往则进行探测 const int keepinterval = 3; // 探测时发包的时间间隔为3秒 const int keepcount = 3; // 尝试探测的次数, 如果第一次探测包就收到响应,则不在继续探测 #if defined (Q_OS_LINUX) || defined (Q_OS_MACOS) #include <sys/socket.h> #include <sys/types.h> #include <netinet/tcp.h> #include <netinet/in.h> // 开启TCP心跳检测机制 int enableKeepalive(int fd) { if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) < 0) return -1; if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle)) < 0) return -1; if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &keepinterval, sizeof(keepinterval)) < 0) return -1; if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &keepcount, sizeof(keepcount)) < 0) return -1; return 0; } #elif defined (Q_OS_WIN) #include <winsock2.h> #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) struct tcp_keepalive { unsigned long onoff; unsigned long keepalivetime; unsigned long keepaliveinterval; }; int enableKeepalive(int fd) { if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&keepalive, sizeof(keepalive)) < 0) return -1; struct tcp_keepalive in_keep_alive; memset(&in_keep_alive, 0, sizeof(in_keep_alive)); unsigned long ul_in_len = sizeof(struct tcp_keepalive); struct tcp_keepalive out_keep_alive; memset(&out_keep_alive, 0, sizeof(out_keep_alive)); unsigned long ul_out_len = sizeof(struct tcp_keepalive); unsigned long ul_bytes_return = 0; in_keep_alive.onoff = 1; // 打开keepalive in_keep_alive.keepaliveinterval = keepinterval * 1000; // 发送keepalive心跳时间间隔-单位为毫秒 in_keep_alive.keepalivetime = keepidle * 1000; // 多长时间没有报文开始发送keepalive心跳包-单位为毫秒 if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, (LPVOID)&in_keep_alive, ul_in_len, (LPVOID)&out_keep_alive, ul_out_len, &ul_bytes_return, NULL, NULL) < 0) return -1; return 0; } #else int enableKeepalive(int fd) { Q_UNUSED(fd); return -1; } #endif Socket文件描述符的获取 QAbstractSocket::socketDescriptor() ,在socket连接成功后可使通过m_socket->socketDescriptor();获取到QTcpSocket的文件描述符(FD),失败时返回-1,这边获取到的fd可以提供给int enableKeepalive(int fd);作为参数用于启用keepalive。 ...

July 16, 2024 · 2 min · 319 words · FakeRick