Home  
1  
I 
2 
3 

II 
4 
5  
6  
III 
7 
8  
9  
IV 
10 
11  
12  
13  
14  
V 
15 
16  
Toolboxes 
This page reports substantive errors not typos. I am however interested in collecting both classes of errors so please email me at rvc@petercorke.com and provide enough information to locate the error, and tell me what you think the error is. By default I will acknowledge you, let me know if you don't want this.
Big thanks to the following bug finders for their careful reading and attention to detail: Walter Lucia, Michael Mustillo, Mark Sheehan, Jana Kosecka, Do Nguyen Tien Thong, Jeff Trinkle, Muhammad Tufail, Frederic Maire, Nino Cauli, ENB339 class of 2011, Ugo Fabrizi, Liam O'Sullivan, Bassam Salameh, Rafael Perrone, Henry Carrillo Lindado, João Pinto, Richard Roberts, Diego Vera, David Breneisen, Stephen Fox, Julien Brisset, Chet Corcos, Diego Saqui, Chao Qu, Hugo Costelha, Geoffrey Vincent, Paul Pounds, Anis Koubaa, Bart Bastings, Hiroyuki Ichihara, Anuj Potnis, Richard Balogh, Murty S. Challa, Diego Cesar, Ulrik Skyt, George Haywood, Iain McCulloch, Troy Woo, Yang Daichuan, Steven Dirven, Dan Richards, Martin Stoelen, Feiteng Lee .
The convention here is that new text is shown in bold, and text to be
deleted is shown in strike through font.
There are currently two versions of the book. The first was released in 2011. The most recent, or second printing, was released in early 2013. You can identity the version from the copyright page (page iv), the second version has the words "© SpringerVerlag Berlin Heidelberg, first edition 2011, corrected second printing 2013". Importantly, pagination is the same between the versions so page numbers given below apply equally to both versions.
The second printing provided an opportunity to:
The pose vector from frame {O} to frame {B} should be labelled \xi_B not \xi_P. (thanks Richard Balogh)
The leading superscript T should all be V.
This is related to the errata below for p. 20. (thanks Anis Koubaa)
The equation just above the box has the wrong signs and should be
(thanks Murty S. Challa)
Coordinate frame {B} in Fig 2.9 is depicted as a lefthanded coordinate frame. In robotics we don't use these, only righthanded coordinate frames. The intent of the figure is to illustrate that point P can be described relative to both the frames, and is is correct (Thanks George Haywood).
The quaternionvector product in the sidebar has various sign errors in the matrix part, it should be
(thanks Diego Cesar)
Table 2.1, the rightmost column gives some examples of Toolbox functions that generate that particular representation. The list of functions given is not exhaustive. For instance the second last row, for SE(3), lists only one function transl(x,y,z) which does generate an SE(3) transform but with a null rotation component. trotx(th) creates a rotation but has a null translation. There is actually no Toolbox function that creates an SE(3) representation with both rotation and translation. (thanks Ulrik Skyt)
The result shown in sec 3.1.5 is incorrect and should be
>> trinterp(T0, T1, 0.5) ans = 0.6667 0.3333 0.6667 0 0.6667 0.6667 0.3333 0 0.3333 0.6667 0.6667 0.1500 0 0 0 1.0000(thanks Ulrik Skyt)
Equation (3.12) is incorrect and should read
Note the change to the dimensions of the added identity matrix which is 4 x 4. (thanks Paul Pounds)
Equation (6.1) is incorrect and should read
the arguments of sin and cos should not contain δ_{θ}. The other equations on this page are correct. (thanks Hugo Costelha)
Equation (6.4) is incorrect and should read
There's a spurious minus sign printed before the sine function. (thanks Dan Richards)
Equation (6.11) is incorrect and should read
The first two elements of the second row are swapped. (thanks Dan Richards)
Equation (6.14) is incorrect and should read
The first term should not be postmultiplied by a Jacobian matrix. The versions given in Appendix K are correct.
The top code fragment on this page should read
>> P0 = diag([.01, .01, 0.005].^2); >> map = Map(20); >> veh = Vehicle(WV); >> veh.add_driver( RandomPath(map.dim) ); >> sensor = RangeBearingSensor(veh, map, W); >> ekf = EKF(veh, V, P0, sensor, W, []);
that is, in the third line we should use the covariance V not W.
Buffon's needle problem. The probability should be h/n = 2l/tπ, where t is the strip width.
In (7.2) row 2, column 4, the subscript i should be a j. (thanks Yang Daichuan).
The model mdl_twolink now includes a base transform so that the robot arm moves in the xzplane and is thus influenced by gravity. Use the model mdl_planar2 instead.
>> mdl_planar2
which creates a workspace variable called p2 (thanks Steven Dirven)
In the MATLAB output showing the parameters of the p8 robot there is an error in the displayed base transform. The third column is shown as all zeros but it should be [1 0 0 0]. (thanks Julien Brisset)
The inverse kinematic results shown cannot be replicated with ikine() as of RTB 9.10. Use the method ikunc() instead.
>> p8.ikunc(T) ans = 0.2833 1.0642 0.1103 0.5412 0.6024 0.0831 1.2168 0.1070
but note you will need the Optimization Toolbox. (thanks Steven Dirven)
The plot command does not work, giving an error about missing 'workspace' option. This is due to a change in the Robotics Toolbox. The toolbox uses a simple heuristic to determine the size of the volume in which the robot moves, it needs this to size the plot correctly. For a robot with a prismatic link this is difficult, so you need to specify the size of the workspace. The toolbox used to make assumptions that worked for this example but were not general.
You have 2 options:
>> p8.plot([0 0 0 0 0 0 0 0], 'workspace', [2 2 2 2 2 2])
>> p8.plotopt={'workspace', [2 2 2 2 2 2]} >> p8.plot([0 0 0 0 0 0 0 0])
The manipulability results shown differ with recent versions of the Toolbox. The results now are:
>> p560.maniplty(qn) ans = 0.1112 >> p8.maniplty([0 0 qn]) ans = 0.8086
These measures are derived from the radii of the velocity ellipsoid, but some of the radii have dimensions of m/s and others have rad/s so the radii are not directly comparable. The toolbox by default now considers the translational degrees of freedom only. The options 'R' gives manipulability for all rotational degrees of freedom and 'all' considers all degrees of freedom and gives the old toolbox behaviour, for example:
>> p560.maniplty(qn, 'all') ans = 0.0786 >> p8.maniplty([0 0 qn], 'all') ans = 1.1151
(thanks Julien Brisset)
Fig 7.12(b) is wrong, it's the same as 7.12(c). To create this subfigure we would use numerical inverse kinematics. As of RTB 9.10, the ikine() method failes on this example, but the new ikunc() method works fine, but you would need the Optimisation Toolbox.
>> qik2=p560.ikunc(Ts); >> qplot(qik2);
(thanks Steven Dirven)
Fig 7.14(a) has incorrect axis labels, it should be (click to enlarge)
(thanks Bart Bastings)
In the equation at the top of the page the subscript should be 2, not 1. (thanks Feiteng Lee)
In the top highlight box, there's a missing equal sign before the left opening bracket. (thanks Martin Stoelen)
In (9.1) I use the symbol g to represent a wrench, whereas in the rest of the chapter I use an f. (thanks Steven Dirven)
Section 9.1.3 is quite wrong, sorry. The Coriolis matrix computed by the Toolbox was incorrect, now fixed in RTB. The numerical result printed on page 197 is wrong. However the result for C*q' is correct.
Equation (10.1), Planck's radiation formula, the units are missing an inverse steradian, and should be W sr^{1} m^{2} m^{1}. (thanks Iain McCulloch and Troy Woo)
The unnumbered equation just above Fig 11.3 should be
When expressed in homogenous coordinates the denominator is replaced by an implicit division by the third homogeneous coordinate. (Thanks Chao Qu).
The function plot_frame has been replaced by trplot.
>> trplot(eye(4,4), 'frame', 'T', 'color', 'b', 'length', 0.3)
(Thanks Anuj Potnis).
The top unnumbered equation on this page should read
the argument of the arccosine are inverted in the book (Thanks Geoffrey Vincent).
Section 12.4.1 has a number of errors where I misuse/confuse crosscorrelation and convolution. They are similar but different and there's a nice tutorial that explains clearly the difference.
The first equation in this section defines crosscorrelation not convolution. For convolution the two plussigns would be minussigns. The result is the same for the case of a symmetric kernel. The Toolbox function iconv() does in fact perform crosscorrelation, not convolution. The documentation is wrong but will be updated in MVTB 3.4. (Thanks Chet Corcos).
The code for the mosacing example in the topmost codebox on the page
>> surf = isurf(im1) >> surf = isurf(im2) >> m = surf.match(surf);
should be
>> surf1 = isurf(im1) >> surf2 = isurf(im2) >> m = surf1.match(surf2);
There's an error in the second equation on this page
The "hats" are transposed and it should be
(Thanks Diego Saqui).
The expression to compute the relative pose of the target with respect to the camera is incorrect. The line of code
Tdelta = TcStar_t * inv(Tc_t_est)
should be
Tdelta = Tc_t_est * inv(TcStar_t)
(thanks Hiroyuki Ichihara)
In (15.6) the elements [1,4] and [2,5] of the Jacobian have the pixel dimensions σ swapped. Element [1,4] should contain σ_{v} and element [2,5] should contain σ_{u}. (thanks Rafael Perrone)
Note also that the pixel dimensions are referred to here as σ_{u} x σ_{v}, but on page 255 they are introduced as σ_{w} x σ_{h} respectively. (thanks Murty Challa)
In the definition of SVD note that A is R^{mxn} and that Σ is R^{nxmmxn}.
The subscripts and superscripts T in (2.3) should all be V. (thanks Walter Lucia)
The code example
>> rotx(pi/2) * roty(pi/2) ans = 0.0000 0 1.0000 1.0000 0.0000 0.0000 0.0000 1.0000 0.0000 >> trplot(R)
won't work because the result of computing the product of rotation matrices is stored in ans not in R. Instead it should be
>> R = rotx(pi/2) * roty(pi/2) R = 0.0000 0 1.0000 1.0000 0.0000 0.0000 0.0000 1.0000 0.0000 >> trplot(R)
(thanks Rafael Perrone)
There is an error in the simple rpy2r() example on this page.
>> R = rpy2r(0.1,0.2,0.3) R = 0.9752 0.370 0.2184 0.0978 0.9564 0.2751 0.1987 0.2896 0.9363
Whereas the actual MATLAB result is
R = 0.9363 0.2896 0.1987 0.3130 0.9447 0.0978 0.1593 0.1538 0.9752
The cause of this is a change in the definition of the function. As per (2.14) rollpitchyaw angles are defined as a rotation sequence about the x then y then zaxes, and this is what the code implements.
In older versions of the Toolbox the sequence used was z then y then xaxes, which is consistent with early textbooks such as that by Paul. This convention makes a bit more sense for a robot manipulator where the zaxis is considered forward, but is inconsistent with the notation for vehicles. This behaviour can be invoked using the 'zyx' option to rpy2r() and will give the result shown in the book. (thanks Michael Mustillo)
The caption for Fig 2.13 is incorrect. The coordinate system is such that the xaxis points in vertical direction, the thrust axis. (thanks Rafael Perrone)
The quote in the blue box about Hamilton gives the fundamental quaternion equation which should read i^{2} = j^{2} = k^{2} = ijk = 1. (thanks Mark Sheehan)
In the rightmost vector term the third element should have a leading superscript of A not B, that is it should read
(thanks Richard Roberts)
Figure 2.15, two graph arcs are labeled with "quaternion" which should be "Quaternion". All classes begin with an uppercase letter. The arcs labelled "q.t" and "q.r" should be "q.T" and "q.R" respectively. The arcs "rotvec2tr" and "tr2rotvec" should be "angvec2tr" and "tr2angvec" respectively. (thanks Jeff Trinkle)
In Fig 3.4 the first red segment should be initially flat to reflect an initial zero velocity and acceleration. Similarly, the final red segment should be flat as it enters the point X4. (thanks Jeff Trinkle)
The motion comprises linear segments with polynomial blends, like
lpsblspb, but here we choose...
(thanks Walter Lucia)
The equation for acceleration during the blend is misleading. This is the average acceleration over the blend interval and can be used to determine whether or not the actuator acceleration limit is exceeded. Because the blend is a polynomial the peak acceleration will likely be higher than the average acceleration, and should properly be taken into consideration.
The equation near the bottom of the page is missing a factor 's' and should be
(thanks Jana Kosecka)
In further reading there is a reference to Corke et. al. (2007) which refers to the paper: P. Corke, J. Lobo, and J. Dias, ``An introduction to inertial and visual sensing'', Int. J. Robotics Research, vol. 26 pp. 519536, June 2007 which is omitted from the bibliography. (thanks Diego Vera)
The second line of text refers to Fig 15.1, it should be Fig 4.2. (thanks Rafael Perrone)
The Simulink Bicycle model shown in Figure 4.3 differs from equation (4.2). The Simulink block does not include the tan function or the division by the wheel length. (thanks Liam O'Sullivan)
This is a bug in the Toolbox, but fixing the bug will change the shape of responses all through Chapter 4. The best solution is to add another model to roblocks called Bicycle2 which does include the full model, or to make it switchable (no tan function by default). Added to the TODO list.
In Section 4.2.4 there is a mistake in the first equation where γ (the steer angle) should be replaced by ω the angular steering rate. The two quantities are related by equation (4.2). All instances of γ in this section should be replaced by ω.
In Fig 4.13 the input to Bicycle block is steer angle γ but we should in fact input the steering rate ω. If we assume that the steer angle is small (tan γ ≅ γ) then we convert from steer angle rate to steer angle by dividing by the velocity, and clearly this will be problematic as the velocity converges on zero. We could also multiply by the wheel base L but this overall gain is already incorporated in the control gains. (thanks João Pinto).
The code example
>> dx.plan(goal, show 0.1);is incorrect (and syntactically invalid), it should read
>> dx.plan(goal, 0.1);
The optional second argument causes the planner to display the evolution of the distance field every 0.1 seconds.
The covariance in the text "σ_{d} = 2cm" does not match the code.
>> V = diag([0.005, 0.5*pi/180].^2)
should be
>> V = diag([0.02, 0.5*pi/180].^2)
The rest of the example is in fact done with "σ_{d} = 2cm" as can be seen by the value of V in the next code block.
The top equation in (6.9) is incorrect and should be
(thanks Frederic Maire)
Equation (7.2), the element at row 2 column 4 should be a_{j} sin θ_{i} not α_{j} sin θ_{i}. (thanks Do Nguyen Tien Thong)
fifth element σ_{} indicates whether the joint is revolute
(σ_{i}=0)(σ_{j}=0)
or prismatic
(σ_{i}=0)(σ_{j}=1).
(thanks Do Nguyen Tien Thong)
indicates that the link is prismaticrevolute.
(thanks Walter Lucia)
The inverse kinematics for the 8link robot are not unique. Recent changes to the ikine() method will give slightly different numerical values for joint coordinates.
Fig 8.2b is incorrect and should look like
The ellipsoid is a zerothickness plate in the yzplane, with zerowidth in the xdirection. This indicates (as the book correctly states) that the endeffector can rotate about the y or zaxes but not the xaxis. (thanks Richard Roberts)
>> xd = J*qd; ans = 0.0829 0.0266 0 0 0 0.0266
should read
>> xd = J*qd; >> xd' ans = 0.0829 0.0266 0 0 0 0.0266
(thanks Rafael Perrone).
An important clarification here is that (8.4) applies for the case where {A} and {B} are attached to the same body, that is, they move together. If the frames are not rigidly attached then (8.4) is simpler and the topright block is zero.
Although not explicitly stated, the code example is for the case where the two frames are attached to the same body. (thanks Jeff Trinkle)
The equation for mapping velocity from frame {N} to frame {0} is incorrect, since those frames are not rigidly attached we must use the velocity transform with the topright block set to zero (see item above).
(thanks Jeff Trinkle)
An important clarification here is that this relationship applies for the case where {A} and {B} are attached to the same body, that is, they move together. Equation (8.10) is also written the wrong way around and should be
Although not explicitly stated, the code example is for the case where the two frames are attached to the same body. (thanks Jeff Trinkle)
For (8.15) the leading superscript on the Jacobian should be E not N. (thanks Jeff Trinkle)
The gravity load increase for the payload case is not as shown. I get
>> mdl_puma560 >> gravload = p560.gravload(qn); >> p560.payload(2.5, [0, 0, 0.1]); >> p560.gravload(qn) ./ gravload ans = 0.3737 1.5222 2.5416 18.7826 86.8056 NaN
Note that the result for elements 1, 4 and 6 are all to be ignored since they involve division of two almost zero quantities
>> gravload gravload = 0.0000 31.6399 6.0351 0.0000 0.0283 0
The example in 9.1.5 is correct for the case of the robot without payload. This requires that the robot model be reset before this example
>> mdl_puma560
Error in (9.9) which should read
(thanks Rafael Perrone)
The top equation on this page should read
The feedforward acceleration should be outside the term K_{v}(...) (thanks Jeff Trinkle)
Fig. 9.20 should properly include the feedforward acceleration. That is, the qdd output from the trajectory generator ${\ddot{q}}^{*}$ should be added to the signal going into the qdd input of the RNE block. Doing so would improve the error performance of the controller. (thanks Muhammad Tufail)
Equation (10.1), Planck's radiation formula should not have π in the numerator.
The matrix cxy should be transposed, that is, the columns are the 2vectors of cluster chromaticity. Note that the colorseg() function is deprecated and colorkmeans() should be used instead.
>> cam.T = transl(1, 0, 0.5) * troty(0.8); >> cam.mesh(X, Y, Z, 'Tcam', Tcam);
should be
>> Tcam = transl(1, 0, 0.5) * troty(0.8); >> cam.mesh(X, Y, Z, 'Tcam', Tcam);
which defines the variable Tcam which is passed to the method cam.mesh() and overrides its default pose.
An alternative approach is to change the pose of the camera and view the mesh
>> cam.T = transl(1, 0, 0.5) * troty(0.8); >> cam.mesh(X, Y, Z);
Both approaches are equivalent, but the latter leaves the camera pose unchanged. The code in the book mixes up the two use cases.
Line 5 of the top code example is wrong
cam.mesh(X, Y, Z, T_cube);
should be
cam.mesh(X, Y, Z, 'Tobj', T_cube);
(thanks Bassam Salameh)
The function peak returns the peak value not the position of the peak. To obtain the peak positions as shown in this example we need to assign two output arguments and use the value of the second one.
>> peak(n, v)'
should be
>> [py,px] = peak(n, v); >> px'
The same error appears later on the page
>> peak(n, v, 'scale', 25)'
should be
>> [py,px] = peak(n, v, 'scale', 25); >> px'
For both examples the values shown as returned by peak() are wrong, they should be one higher.
Fig 12.16 (a) and (b). Observant readers will note that the gradients have the wrong sign. For Fig 12.16(a) the white strip around the sign should lead, left to right, a strong positive gradient (blue) followed by a strong negative gradient (red).
The figures have this reversed, and this is due to a bug (effective sign flip) in the iconv() function, now fixed.
(12.4) is not strictly correct. The definition of ∇^{2}I is given by (12.3) whereas this equation describes a Gaussian smoothed Laplacian operator.
The equation
is incorrect and should read
The last two equations on this page are introduced with the comment that "morphological operations are associative". Only the first equation, for dilations, is associative. The second equation is correct, but it does not represent associativity. (thanks Frederic Maire)
The code block mid page
delta_v = v .* (k(1) * r.^2 + k(2) * r.^4 + k(3) * r.^6) + ... p(1) * (r.^2 + 2 * v.^2) + 2 * p(1) * u .* v;
should be
delta_v = v .* (k(1) * r.^2 + k(2) * r.^4 + k(3) * r.^6) + ... p(1) * (r.^2 + 2 * v.^2) + 2 * p(2) * u .* v;
That is, the last term should be have a coefficient of p(2) not p(1). This change will subtly alter Fig 12.36b as well. (thanks Nino Cauli)
Fig 12.27 uses an inverted color map, where the set pixels are black. This was an aesthetic choice to avoid large areas of black but is confusing since generally I have associated set pixels with the color white.
The arguments to the function pnmfilt are reversed.
>> rlena = pnmfilt(lena, 'pnmrotate 30');
should be
>> rlena = pnmfilt('pnmrotate 30', lena);
The captions for Fig 13.1 are incorrect. The rows should be labelled a, b, c, d; that is, the top two images are a, the next two images are b and so on. (thanks Frederic Maire).
The RegionFeature class contains a shape measure (aspect ratio) which is the ratio of the major (a) and minor (b) axis lengths of the equivalent ellipse. The shape measure property, .shape, is b/a which is always less than or equal to one. The display method of the RegionFeature class shows the shape measure correctly but incorrectly labels it as a/b and this is shown in the code examples on pages 352353, 357 and 358. (thanks ENB339 class)
It is not stated explicitly in the text, but iblobs() computes the 8neighbour chain code.
The blob perimeter length was computed incorrectly in the book, and this affects also the value of circularity. The correct answers as given by the fixed code is:
(1) area=1434, cent=(132.9,135.8), theta=3.10, b/a=0.852, class=1, label=2, touch=0, parent=1, perim=178.0, circ=0.569 (2) area=3380, cent=(95.9,210.9), theta=2.83, b/a=0.888, class=1, label=3, touch=1, parent=0, perim=222.4, circ=0.859 (3) area=456, cent=(11.7,228.4), theta=2.98, b/a=0.864, class=1, label=4, touch=1, parent=0, perim=81.0, circ=0.874
Note also that the property b/a is listed now, not a/b as shown in the book. See also the errata for p. 352.
The blob perimeter length was computed incorrectly in the book, and this affects also the value of circularity. The correct answers as given by the fixed code is:
(1) area=1375, cent=(94.9,108.2), theta=1.98, b/a=0.648, color=1, label=2, touch=0, parent=1, perim=214.8, circ=0.375 (2) area=795, cent=(204.6,122.4), theta=2.76, b/a=0.645, color=1, label=4, touch=0, parent=1, perim=162.5, circ=0.379
The property length_v does not exist, it should be length, ie.
>> k = find( lines.length > 100);
Equation at bottom of page, the last term + 2 δ_{u} δ_{v} … (thanks Ugo Fabrizi)
In equation 13.16 the trace value should be squared. (thanks Stephen Fox)
More formally, given two sets of points M_{i}M_{j}, D_{j}D_{i} ...
The caption for Fig. 14.36(b) is wrong. The figure is an anaglyph of the rock scene from Fig. 14.20, and clearly not an image of parking meters.
and consequently some datamodel points DjMj will be unpaired.
Missing closing parenthesis at the end of the third code example on this page, it should be
>> xc = homtrans(inv(T_est(:,:,k1), x))
Figure 14.53, the images caption are incorrect. From top left to bottom right they should be images: 11, 9, 13, and 10 respectively.
The first equation in (15.2) should read
(thanks Liam O'Sullivan)
(thanks Liam O'Sullivan)>> sl_xyzpartitioned
should be
>> sl_partitioned
>> r = sim('sl_ibvs')
should be
>> r = sim('sl_arm_ibvs')
At the bottom of the page the code should read
>> q = Quaternion( rotx(0.2) );
>> q2 = quaternion( roty(0.3) );
should be
>> q2 = Quaternion( roty(0.3) );
which correspond to ab and ba respectively.
Note that the second argument to gaussfunc is the variance not standard deviation
If the variables are uncorrelated the matrix V C would be diagonal.
There's an overall problem with this example in that the referenced equation 6.9 from p117 is itself in error (see errata above). Therefore everything that follows in this appendix does not represent the range and bearing Jacobian discussed on p.117. (thanks David Breneisen)
However the appendix is correct for the MATLAB function as written on p.527, except that the value given for h0 is incorrect, it should be
h0 = 0.8165 0.9828
(thanks Henry Carrillo Lindado)
Errors in the two examples. The first example, top of page, after the vertices have been added, should give.
>> g g = 2 dimensions 5 vertices 0 edges 5 components
note 5 not 4 components.
For the second example on the page, after the edges are added
>> g g = 2 dimensions 5 vertices 6 edges 1 components
note 6 not 5 edges. (thanks Bassam Salameh)