三言两语frame&bounds

本文通过代码示例详细解释了iOS View中frame和bounds属性的区别,包括它们如何影响视图的位置和大小,以及修改这些属性后的视图布局变化。

简单说明一下ios view的frame属性和bounds属性,直接看代码。

- (void)viewDidLoad {
    [super viewDidLoad];

    UIView *centerView =
        [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    centerView.backgroundColor = [UIColor redColor];
    centerView.center = self.view.center;
    [self.view addSubview:centerView];

//    centerView.bounds = CGRectMake(0, 0, 200, 200);

    UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    subView.backgroundColor = [UIColor blackColor];
    [centerView addSubview:subView];
}

效果:


如果我们修改view的bounds属性:
- (void)viewDidLoad {
    [super viewDidLoad];

    UIView *centerView =
        [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    centerView.backgroundColor = [UIColor redColor];
    centerView.center = self.view.center;
    [self.view addSubview:centerView];

    //修改centerView的bounds属性
    centerView.bounds = CGRectMake(10, 10, 300, 400);

    UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    subView.backgroundColor = [UIColor blackColor];
    [centerView addSubview:subView];
}

效果:


我们可以看到,红色的centerView变大了,但是相对于父视图的位置没有发生变化,因为我们没有改变他的frame属性,黑色的subView大小没有变化,但是相对于centerView的位置发生了变化。


解释:

frame属性中的(x, y, width, height),x和y都是说这个视图相对于父视图的位置,后者表示本身的大小;

bounds属性中的x和y,表示的是这个视图本身所拥有的坐标系统的原点位置,默认在视图的左上角,即(0, 0),我们修改为(10, 10),这时候会把他的自身坐标系统像左上方移动10,但是视图本身的位置并不会发生变化,仅仅是它所拥有的坐标系统原点发生了变化,因为很色subView是参照这个坐标系的,因此黑色的subView的原点相对红色视图左上角的点,偏移了(10, 10)

<think> 我们正在讨论KDL(Kinematica and Dynamics Library)中的一个逆运动学求解器函数:ChainIkSolverPos_TL::CartToJnt。该函数是逆运动学求解的核心函数,它的作用是根据给定的末端执行器位姿(由p_in表示),计算出对应的关节角度(输出到q_out),同时可以指定初始关节角度(q_init)和可能的关节限位(已经在构造函数中设置)以及笛卡尔空间的容差(通过_bounds指定,允许在指定方向上放宽精度要求)。 函数签名如下: int ChainIkSolverPos_TL::CartToJnt(const KDL::JntArray &q_init, const KDL::Frame &p_in, KDL::JntArray &q_out, const KDL::Twist _bounds) 参数说明: 1. q_init: 初始关节位置,作为迭代求解的起点。 2. p_in: 目标末端执行器位姿(位置和方向),用KDL::Frame表示。 3. q_out: 用于存储计算出的关节位置的数组(输出参数)。 4. _bounds: 一个KDL::Twist类型的参数,用于指定在六个自由度(三个平移和三个旋转)上的误差容限。可以理解为允许在某个方向上的误差放宽要求。 返回值:一个整数,表示求解状态。通常,返回值为0表示成功,非0表示错误(如迭代次数达到上限仍未收敛,或遇到奇异点等)。 函数功能:该函数尝试从初始关节角度q_init开始,通过迭代算法(如牛顿-拉夫森法或LM法)调整关节角度,使得机械臂末端执行器的位姿尽可能接近p_in。同时,它还考虑了关节角度的限位(在构造函数中设置的q_min和q_max)以及可能的关节类型(连续关节、旋转关节、平移关节)。 注意:函数名中的TL可能代表某种特定的算法,比如带有线搜索(Trust Region)或任务空间约束(Task Space)的Levenberg-Marquardt算法(LM)?但具体算法实现需要查看源代码。不过,从函数名和参数我们可以推断其基本功能。 具体步骤(根据常见逆运动学求解器的工作流程): 1. 初始化:将q_init作为当前关节角度q_current,并设置迭代计数器。 2. 进入迭代循环: a. 使用正运动学求解器(fksolver)计算当前关节角度对应的末端位姿p_current。 b. 计算目标位姿p_in与当前位姿p_current之间的位姿差(误差),通常用笛卡尔空间中的位移和旋转差表示。这个误差可以用一个6维向量表示(3个平移,3个旋转)。 c. 检查误差是否在允许的范围内(包括_bounds指定的容差)。如果是,则跳出循环,认为已经收敛。 d. 计算当前位姿下的雅可比矩阵(使用vik_solver,即速度逆运动学求解器,它通常用于计算雅可比矩阵的伪逆)。 e. 利用雅可比矩阵(或其伪逆、转置等)计算关节角度的调整量delta_q。不同的算法(如牛顿法、LM法)使用不同的方式计算这个调整量。 f. 根据调整量更新关节角度:q_current = q_current + delta_q。 g. 检查关节角度是否超出限位。如果超出,则进行限幅处理(或者根据构造函数中的设置,对连续关节进行角度环绕处理)。 h. 迭代计数器加1,如果超过最大迭代次数(由构造函数中的maxtime或最大迭代次数控制),则终止并报告失败。 3. 如果迭代成功,将q_current赋值给q_out。 4. 返回相应的错误码。 值得注意的是,参数_bounds允许用户指定在哪些方向上可以放宽精度要求。例如,如果用户不关心末端执行器绕z轴的旋转误差,那么可以将_bounds的旋转z分量设置为一个较大的值。在计算误差时,可以相应地忽略这个方向上的误差,或者在计算误差向量时按_bounds的倒数进行加权(以减少该方向上的权重)。 由于该函数是逆运动学求解的核心,其性能(收敛速度、成功率和精度)直接影响到整个运动控制系统的性能。 下面我们生成相关问题: </think> ### `ChainIkSolverPos_TL::CartToJnt` 函数解析 #### 函数签名含义 ```cpp int ChainIkSolverPos_TL::CartToJnt( const KDL::JntArray &q_init, // 初始关节位置 const KDL::Frame &p_in, // 目标末端位姿 KDL::JntArray &q_out, // 输出关节位置 const KDL::Twist _bounds // 误差容忍边界 ) ``` 此函数是KDL库中逆运动学求解器的核心计算函数,作用是通过数值迭代计算,将机械臂末端执行器移动到指定目标位姿,并输出对应的关节角度[^1]。 --- #### 参数详解 1. **`q_init`** - **类型**: `KDL::JntArray` - **作用**: 初始关节角度向量,作为迭代算法的起点。 - **重要性**: - 影响收敛速度和成功率 - 若不合理可能导致局部最优或发散 $$ \mathbf{q}_{\text{init}} = [q_1, q_2, ..., q_n]^T $$ 2. **`p_in`** - **类型**: `KDL::Frame` - **作用**: 目标末端位姿(笛卡尔空间),包含位置 $(x, y, z)$ 和姿态(旋转矩阵或四元数)。 - **数据结构**: $$ \mathbf{p}_{\text{in}} = \begin{bmatrix} \mathbf{R}_{3\times3} & \mathbf{t}_{3\times1} \\ \mathbf{0}_{1\times3} & 1 \end{bmatrix} $$ $\mathbf{R}$ 为旋转矩阵,$\mathbf{t}$ 为平移向量。 3. **`q_out`** - **类型**: `KDL::JntArray&` - **作用**: **输出参数**,存储计算出的关节角度解。 - **注意事项**: - 需预分配内存空间 - 解需满足构造函数中定义的关节限位 $q_{\min} \leq q_{\text{out}} \leq q_{\max}$ 4. **`_bounds`** - **类型**: `KDL::Twist` - **作用**: 定义笛卡尔空间允许的误差边界,6维向量: $$ \begin{bmatrix} \delta x \\ \delta y \\ \delta z \\ \delta r_x \\ \delta r_y \\ \delta r_z \end{bmatrix} $$ - 前三项:位置公差(米) - 后三项:姿态公差(弧度) - **特殊值**: ```math \text{若 } \delta r_z = \infty \text{,表示绕Z轴旋转无约束} ``` --- #### 返回值 - **类型**: `int` - **含义**: - **0**: 成功收敛到目标位姿 - **-1**: 奇异位形(雅可比矩阵不可逆) - **-2**: 迭代次数超出限制 - **-3**: 关节限位冲突 - **-4**: 算法内部错误 --- #### 内部计算流程(伪代码) ```python def CartToJnt(q_init, p_in, q_out, _bounds): q_current = q_init # 初始关节角 for _ in range(max_iterations): p_current = FK(q_current) # 正运动学计算当前位姿 error = calculate_error(p_in, p_current, _bounds) # 计算带约束的误差 if norm(error) < eps: # 检查收敛 q_out = q_current return 0 # 成功 J = compute_jacobian(q_current) # 计算雅可比矩阵 if is_singular(J): # 奇异点检测 return -1 delta_q = solve(J, error) # 求解关节角增量 (如: Δq = J⁺·e) q_current += delta_q # 更新关节角 q_current = apply_joint_limits(q_current) # 关节限幅处理 return -2 # 迭代超限 ``` --- #### 关键算法特性 1. **数值迭代法** 基于牛顿-拉夫森法或LM算法,通过局部线性化逐步逼近目标位姿[^2]。 $$ \mathbf{q}_{k+1} = \mathbf{q}_k + \mathbf{J}^+(\mathbf{q}_k) \cdot \mathbf{e}_k $$ 其中 $\mathbf{J}^+$ 为雅可比矩阵的伪逆,$\mathbf{e}_k$ 为位姿误差。 2. **关节限位处理** 在每次迭代后执行: $$ q_i = \begin{cases} q_{\min,i} & \text{if } q_i < q_{\min,i} \\ q_{\max,i} & \text{if } q_i > q_{\max,i} \\ \text{wrap}(q_i) & \text{连续关节角度环绕} \end{cases} $$ 3. **误差加权** 根据 `_bounds` 对不同自由度进行归一化加权: $$ e_{\text{weighted}, i} = \frac{e_i}{\delta_i} \quad (i=1..6) $$ ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值