Skip to content

Commit 79ca4e9

Browse files
committed
Make Q and Pose a class
1 parent 55c1ca4 commit 79ca4e9

8 files changed

Lines changed: 198 additions & 87 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ endif()
1717

1818

1919
add_library(urcl
20+
src/types.cpp
2021
src/comm/tcp_socket.cpp
2122
src/comm/tcp_server.cpp
2223
src/control/motion_primitives.cpp

examples/instruction_executor.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,12 @@ int main(int argc, char* argv[])
111111

112112
// To provide a q_near hint for the IK solver a joint configuration near the target can be added to a pose.
113113
urcl::Pose target_pose{ -0.206, -0.6437, 0.202, 0.0, 3.140, 0.0 };
114-
target_pose.q_near = urcl::Q{ -1.7, -4, 1.5, -1, 1.5, 0 };
115-
instruction_executor->moveJ(target_pose);
114+
target_pose.setQNear(urcl::Q{ -1.7, -4, 1.5, -1, 1.5, 0 });
115+
instruction_executor->moveJ(target_pose, 2.0, 2.0);
116+
117+
// q_near can also be set directly upon pose construction
118+
instruction_executor->moveJ(
119+
urcl::Pose{ -0.206, -0.6437, 0.202, 0.0, 3.140, 0.0, urcl::Q{ -1.7, -4, 1.5, -1, 1.5, 0 } }, 2.0, 2.0);
116120

117121
// goal time parametrization -- acceleration and velocity will be scaled to meed the goal time.
118122
instruction_executor->moveJ({ -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 }, 0.1, 0.1, goal_time_sec);
@@ -128,14 +132,14 @@ int main(int argc, char* argv[])
128132
instruction_executor->moveJ(urcl::Pose{ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 0.1, 0.1, goal_time_sec);
129133

130134
// moveP can also be called with brace-init (interpreted as pose) or explicitly using a Pose or Q
131-
instruction_executor->moveP({ -0.2, 0.363, 0.559, 0.68, -1.083, -2.076 });
132-
instruction_executor->moveP(urcl::Pose{ -0.0203, 0.303, 0.559, 0.68, -1.083, -2.076 });
133-
instruction_executor->moveP(urcl::Q{ -1.57, -1.83, 1.707, -0.833, 0.782, 0.479 });
135+
instruction_executor->moveP({ -0.2, 0.363, 0.559, 0.68, -1.083, -2.076 }, 0.2, 0.2);
136+
instruction_executor->moveP(urcl::Pose{ -0.0203, 0.303, 0.559, 0.68, -1.083, -2.076 }, 0.2, 0.2);
137+
instruction_executor->moveP(urcl::Q{ -1.57, -1.83, 1.707, -0.833, 0.782, 0.479 }, 0.2, 0.2);
134138

135139
// For moveC via and target can be a Pose or Q. When brace-init style lists are given, values are
136140
// interpreted as Pose.
137141
instruction_executor->moveC(urcl::Pose{ -0.1, 0.463, 0.559, 0.68, -1.083, -2.076 },
138-
urcl::Pose{ -0.0203, 0.303, 0.559, 0.68, -1.083, -2.076 });
142+
urcl::Pose{ -0.3203, 0.303, 0.559, 0.68, -1.083, -2.076 });
139143
instruction_executor->moveC(urcl::Pose{ -0.1, 0.463, 0.559, 0.68, -1.083, -2.076 },
140144
urcl::Q{ -1.57, -1.83, 1.707, -0.833, 0.782, 0.479 });
141145

include/ur_client_library/types.h

Lines changed: 37 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/*
2+
* Copyright 2026, Universal Robots A/S (Adding Q and Pose)
3+
*
24
* Copyright 2019, FZI Forschungszentrum Informatik (refactor)
35
*
46
* Copyright 2017, 2018 Simon Rasmussen (refactor)
@@ -21,12 +23,12 @@
2123
#pragma once
2224

2325
#include <inttypes.h>
24-
#include <algorithm>
2526
#include <array>
2627
#include <functional>
2728
#include <iostream>
2829
#include <optional>
2930
#include <variant>
31+
#include <vector>
3032

3133
namespace urcl
3234
{
@@ -46,76 +48,61 @@ using vector6uint32_t = std::array<uint32_t, 6>;
4648
* Unlike raw initializer lists (``{...}``) which may bind to either \ref vector6d_t or
4749
* \ref Pose, wrapping values in ``urcl::Q{...}`` always forces a joint-target interpretation.
4850
*/
49-
struct Q
51+
class Q
5052
{
53+
public:
5154
Q() = delete;
52-
Q(const double q1, const double q2, const double q3, const double q4, const double q5, const double q6)
53-
{
54-
values = { q1, q2, q3, q4, q5, q6 };
55-
}
56-
explicit Q(const vector6d_t& values)
57-
{
58-
this->values.resize(6);
59-
std::copy(values.begin(), values.end(), this->values.begin());
60-
}
55+
Q(const double q1, const double q2, const double q3, const double q4, const double q5, const double q6);
56+
explicit Q(const vector6d_t& values);
57+
58+
const std::vector<double>& getValues() const;
59+
void setValues(const vector6d_t& values);
60+
void setValues(const std::vector<double>& values);
6161

62-
std::vector<double> values;
62+
private:
63+
std::vector<double> values_;
6364
};
6465

65-
inline bool operator==(const Q& lhs, const Q& rhs)
66-
{
67-
return lhs.values.size() == rhs.values.size() && std::equal(lhs.values.begin(), lhs.values.end(), rhs.values.begin());
68-
}
66+
bool operator==(const Q& lhs, const Q& rhs);
6967

70-
struct Pose
68+
/*!
69+
* \brief A Cartesian pose (position and orientation) for a robot manipulator.
70+
*
71+
* The position is represented by ``x``, ``y``, and ``z`` in meters, and the orientation is
72+
* represented by AngleAxis ``rx``, ``ry``, and ``rz`` in radians.
73+
*
74+
* The optional \ref q_near member can be used to provide a hint to the solver for inverse
75+
* kinematics when this pose is used as a Cartesian motion target over the trajectory interface.
76+
*/
77+
class Pose
7178
{
72-
Pose() : x(0.0), y(0.0), z(0.0), rx(0.0), ry(0.0), rz(0.0), q_near(std::nullopt)
73-
{
74-
}
75-
Pose(const double x, const double y, const double z, const double rx, const double ry, const double rz)
76-
: x(x), y(y), z(z), rx(rx), ry(ry), rz(rz), q_near(std::nullopt)
77-
{
78-
}
79+
public:
80+
Pose();
81+
Pose(const double x, const double y, const double z, const double rx, const double ry, const double rz);
7982
Pose(const double x, const double y, const double z, const double rx, const double ry, const double rz,
80-
const Q& q_near)
81-
: x(x), y(y), z(z), rx(rx), ry(ry), rz(rz), q_near(q_near)
82-
{
83-
}
83+
const Q& q_near);
84+
85+
bool operator==(const Pose& other) const;
86+
87+
const std::optional<Q>& getQNear() const;
88+
void setQNear(const Q& q_near);
89+
8490
double x;
8591
double y;
8692
double z;
8793
double rx;
8894
double ry;
8995
double rz;
9096

97+
private:
9198
/*!
9299
* Optional joint-space hint (six joint positions in radians) passed to the controller for inverse
93100
* kinematics when this pose is used as a Cartesian motion target over the trajectory interface.
94101
*/
95-
std::optional<Q> q_near;
96-
97-
bool operator==(const Pose& other) const
98-
{
99-
if (x != other.x || y != other.y || z != other.z || rx != other.rx || ry != other.ry || rz != other.rz)
100-
{
101-
return false;
102-
}
103-
if (q_near.has_value() != other.q_near.has_value())
104-
{
105-
return false;
106-
}
107-
if (!q_near.has_value())
108-
{
109-
return true;
110-
}
111-
return *q_near == *other.q_near;
112-
}
102+
std::optional<Q> q_near_;
113103
};
114104

115-
inline bool operator==(const Q& lhs, const vector6d_t& rhs)
116-
{
117-
return lhs.values.size() == rhs.size() && std::equal(lhs.values.begin(), lhs.values.end(), rhs.begin());
118-
}
105+
bool operator==(const Q& lhs, const vector6d_t& rhs);
119106

120107
/*!
121108
* \brief A tagged union representing either a joint target (\ref Q) or a Cartesian target

src/control/motion_primitives.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ void MoveJPrimitive::setTarget(const MotionTarget& target)
169169
else if constexpr (std::is_same_v<T, Q>)
170170
{
171171
type = MotionType::MOVEJ;
172-
std::copy(target_variant.values.begin(), target_variant.values.end(), target_joint_configuration.begin());
172+
const auto& values = target_variant.getValues();
173+
std::copy(values.begin(), values.end(), target_joint_configuration.begin());
173174
}
174175
},
175176
target);
@@ -382,7 +383,8 @@ void OptimoveJPrimitive::setTarget(const MotionTarget& target)
382383
else if constexpr (std::is_same_v<T, Q>)
383384
{
384385
type = MotionType::OPTIMOVEJ;
385-
std::copy(target_variant.values.begin(), target_variant.values.end(), target_joint_configuration.begin());
386+
const auto& values = target_variant.getValues();
387+
std::copy(values.begin(), values.end(), target_joint_configuration.begin());
386388
}
387389
},
388390
target);

src/control/trajectory_point_interface.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ vector6d_t motionTargetToBlock(const urcl::MotionTarget& target)
5454
else
5555
{
5656
static_assert(std::is_same_v<T, urcl::Q>, "Unhandled MotionTarget alternative");
57-
return { alternative.values[0], alternative.values[1], alternative.values[2],
58-
alternative.values[3], alternative.values[4], alternative.values[5] };
57+
const auto& values = alternative.getValues();
58+
return { values[0], values[1], values[2], values[3], values[4], values[5] };
5959
}
6060
},
6161
target);
@@ -129,12 +129,11 @@ bool TrajectoryPointInterface::writeMotionPrimitive(const std::shared_ptr<contro
129129
using T = std::decay_t<decltype(alternative)>;
130130
if constexpr (std::is_same_v<T, urcl::Pose>)
131131
{
132-
if (alternative.q_near.has_value())
132+
if (alternative.getQNear().has_value())
133133
{
134134
has_qnear = true;
135-
return vector6d_t{ alternative.q_near->values[0], alternative.q_near->values[1],
136-
alternative.q_near->values[2], alternative.q_near->values[3],
137-
alternative.q_near->values[4], alternative.q_near->values[5] };
135+
const auto& values = alternative.getQNear()->getValues();
136+
return vector6d_t{ values[0], values[1], values[2], values[3], values[4], values[5] };
138137
}
139138
else
140139
{

src/types.cpp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// -- BEGIN LICENSE BLOCK ----------------------------------------------
2+
// Copyright 2026 Universal Robots A/S
3+
//
4+
// Redistribution and use in source and binary forms, with or without
5+
// modification, are permitted provided that the following conditions are met:
6+
//
7+
// * Redistributions of source code must retain the above copyright
8+
// notice, this list of conditions and the following disclaimer.
9+
//
10+
// * Redistributions in binary form must reproduce the above copyright
11+
// notice, this list of conditions and the following disclaimer in the
12+
// documentation and/or other materials provided with the distribution.
13+
//
14+
// * Neither the name of the {copyright_holder} nor the names of its
15+
// contributors may be used to endorse or promote products derived from
16+
// this software without specific prior written permission.
17+
//
18+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
// POSSIBILITY OF SUCH DAMAGE.
29+
// -- END LICENSE BLOCK ------------------------------------------------
30+
31+
#include <ur_client_library/types.h>
32+
33+
#include <algorithm>
34+
35+
namespace urcl
36+
{
37+
Q::Q(const double q1, const double q2, const double q3, const double q4, const double q5, const double q6)
38+
{
39+
values_ = { q1, q2, q3, q4, q5, q6 };
40+
}
41+
42+
Q::Q(const vector6d_t& values)
43+
{
44+
values_.resize(6);
45+
std::copy(values.begin(), values.end(), values_.begin());
46+
}
47+
48+
const std::vector<double>& Q::getValues() const
49+
{
50+
return values_;
51+
}
52+
53+
void Q::setValues(const vector6d_t& values)
54+
{
55+
values_.resize(6);
56+
std::copy(values.begin(), values.end(), values_.begin());
57+
}
58+
59+
void Q::setValues(const std::vector<double>& values)
60+
{
61+
values_ = values;
62+
}
63+
64+
bool operator==(const Q& lhs, const Q& rhs)
65+
{
66+
return lhs.getValues().size() == rhs.getValues().size() &&
67+
std::equal(lhs.getValues().begin(), lhs.getValues().end(), rhs.getValues().begin());
68+
}
69+
70+
Pose::Pose() : x(0.0), y(0.0), z(0.0), rx(0.0), ry(0.0), rz(0.0), q_near_(std::nullopt)
71+
{
72+
}
73+
74+
Pose::Pose(const double x, const double y, const double z, const double rx, const double ry, const double rz)
75+
: x(x), y(y), z(z), rx(rx), ry(ry), rz(rz), q_near_(std::nullopt)
76+
{
77+
}
78+
79+
Pose::Pose(const double x, const double y, const double z, const double rx, const double ry, const double rz,
80+
const Q& q_near)
81+
: x(x), y(y), z(z), rx(rx), ry(ry), rz(rz), q_near_(q_near)
82+
{
83+
}
84+
85+
bool Pose::operator==(const Pose& other) const
86+
{
87+
if (x != other.x || y != other.y || z != other.z || rx != other.rx || ry != other.ry || rz != other.rz)
88+
{
89+
return false;
90+
}
91+
if (q_near_.has_value() != other.q_near_.has_value())
92+
{
93+
return false;
94+
}
95+
if (!q_near_.has_value())
96+
{
97+
return true;
98+
}
99+
return *q_near_ == *other.q_near_;
100+
}
101+
102+
const std::optional<Q>& Pose::getQNear() const
103+
{
104+
return q_near_;
105+
}
106+
107+
void Pose::setQNear(const Q& q_near)
108+
{
109+
q_near_ = q_near;
110+
}
111+
112+
bool operator==(const Q& lhs, const vector6d_t& rhs)
113+
{
114+
return lhs.getValues().size() == rhs.size() &&
115+
std::equal(lhs.getValues().begin(), lhs.getValues().end(), rhs.begin());
116+
}
117+
118+
} // namespace urcl

0 commit comments

Comments
 (0)