How do you properly send an array from ROS in C++? - c++

I'm using Kinetic.
I have a custom message path.msg
string path_name
segment[] segments
I'm trying to send a ROS goal with that message type.
I initialize an array in my code
cuarl_rover_planner::segment segments[path->getSegments().size()];
//do stuff that populates the array
cuarl_rover_planner::path action_path;
action_path.segments = segments; // Error here
I get this error
error: no match for ‘operator=’ (operand types are ‘cuarl_rover_planner::path_<std::allocator<void> >::_segments_type {aka std::vector<cuarl_rover_planner::segment_<std::allocator<void> >, std::allocator<cuarl_rover_planner::segment_<std::allocator<void> > > >}’ and ‘cuarl_rover_planner::segment [(<anonymous> + 1)] {aka cuarl_rover_planner::segment_<std::allocator<void> > [(<anonymous> + 1)]}’)
action_path.segments = segments;
I'm assuming that the action_path.segments take a different data type, but I don't understand what that datatype is, from that error message.

action_path.segments is a std::vector<segment>, but your segments variable is just a single segment, not a vector of segments. If you want to add only one segment, you can use action_path.push_back(segment). Otherwise, you can declare segments as
std::vector<cuarl_rover_planner::segment> segments(path->getSegments().size());
If you wanted to use a raw pointer array for some reason (like you might be here), you have to explicitly set that up as std::vector first, i.e.
action_path.segments = std::vector<cuarl_rover_planner::segment>(segments, segments+path->getSegments().size());
See How to initialize std::vector from C-style array? for more about setting a vector from a raw C-array.

Related

Cannot initialize a variable of type 'double (*)[x]' with an rvalue of type 'double (*)[z]

I have a vector of doubles that I am passing to a lib https://github.com/llohse/libnpy in order to read a numpy file:
std::vector<unsigned long> shape {};
bool fortran_order;
std::vector<double> dataNpy;
const std::string path {"/home/ubuntu/template.npy"};
npy::LoadArrayFromNumpy(path, shape, fortran_order, dataNpy);
I will need to further process this data and have been instructed to use arrays since vector copy is not optimal.
So this data should be a matrix but the lib reads it as linear.
That is why I want to create a pointer to a 2D table with a given size for rows and columns like this with the data from the vector
double (*template_data)[12] = (double (*)[12]) dataNpy.data();
When I do it by explicitly putting the size, like above the compiler is ok with it, however, when I do it like the code below i get an error:
int sizeRows = 12, sizeColumns=12;
double (*template_data)[sizeRows] = (double (*)[sizeColumns]) dataNpy.data();
Cannot initialize a variable of type 'double ( * )[sizeRows]' with an rvalue of type 'double ( * )[sizeColumns]'
Could you explain to me why that is?

Passing three dimensional array by reference in c++

Function is defined as:
int strip(double *signalstnV){
.
.
return 0;
}
And main function it is called as:
main{
.
.
double signalstnV[iteration][2*range+1][3];
.
.
check = strip(signalstnV);
.
}
I wanted to use the array in next function in main after it is modified in strip function. But during compilation i am getting an error as following
sim.C: In function ‘int main(int, char**)’:
sim.C:54:26: error: cannot convert ‘double ()[151][3]’ to ‘double’ for argument ‘1’ to ‘int strip(double*)’
check = strip(signalstnV);
I am not able to understand it. Please help.
My main goal is to generate array from strip function and pass it to other functions later in code.
Also when i used this array in another function
threshold(double * signalstnV)
and using a for loop to extract some specific values, it gives error as:
invalid types ‘double[int]’ for array subscript
if (signalstnV[k][j][3] < -0.015){
..}
An ordinary single-dimensional array decays to a pointer to its first value. A multi-dimensional array decays only in its first dimension, decaying to a pointer to the initial 2nd dimension of the array.
If you wish to "super-decay" a multi-dimensional array to a pointer to its first value, then simply do that yourself:
check = strip(&signalstnV[0][0][0]);
For such cases, with more or less complicated types - use type aliases:
//double signalstnV[iteration][2*range+1][3];
using IterationValues = double[iteration];
using IterationRangesValues = IterationValues [2*range+1];
//...
then, it is obvious that calling this:
IterationRangesValues signalstnV[3];
check = strip(signalstnV);
You need this signature: strip(IterationRangesValues * matrix) or this strip(IterationRangesValues (& matrix)[3]). Of course for this last array you might use typedef too.
You might also use std::array:
using IterationValues = std::array<double, iteration>;
using IterationRangesValues = std::array<IterationValues, 2*range+1>;
//...
To pass the array by reference, one way is:
template<size_t X, size_t Y, size_t Z>
int strip( double(&strip)[X][Y][Z] )
{
}
Then you can call it with various sizes of array.
If you only need to support the one size, then remove the template line and replace X Y Z with the actual dimensions you need to support.

How do I use C++ vectors with a user defined structure?

I am trying to manage an array of structures using vectors but keep getting an error msg.
The vector is declared in the header file as:
vector< TLE_Values, allocator<TLE_Values> > SavedSatellites;
which VS2013 is quite happy with.
The structure is defined as:
struct TLE_Values
{
string CatalogNum;
string SatelliteName;
string DateStr;
string TimeStr;
string Classification;
double DecayValue;
int ElsetNum;
double InclinationValue;
double RaanValue;
double EccentricityValue;
double ArgPerigeeValue;
double PerigeeAngle;
double AvgSpeed;
double Period;
int OrbitNum;
};
and initialised with default values by a constructor.
In the main program code, having determined the number of elements I will require ( CountItemsInFile() ), I try to expand the vector list using:
SavedSatellites.push_back(CountItemsInFile());
This however returns the following compiler error message:
error C2664:
'void std::vector<TLE_Values,std::allocator<TLE_Values>>::push_back(const TLE_Values &)' : cannot convert argument 1 from 'int' to 'TLE_Values &&'
1> Reason: cannot convert from 'int' to 'TLE_Values'
1> No constructor could take the source type, or constructor overload resolution was ambiguous.
Another thread suggested that a vector needed to be initialised with 0, which won't happen with a user defined type like this.
What am I missing? where have I gone wrong? How do I create the initial vector with my structure?
There's lots of documentation for using vectors of type (int) but not much if you're not using integers.
To expand a vector use
SavedSatellites.resize(CountItemsInFile());
If you just want reserve memory for it but keep the size of the vector untouched and ready for subsequent push_back without memory reallocation:
SavedSatellites.reserve(CountItemsInFile());
The docs are key here:
void push_back (const value_type& val);
push_back doesn't take an int, it takes a parameter of the same type your vector holds. You need to give it a TLE_Values object.
You also don't need to preemptively size the vector; you can just keep calling push_back until you're done.

2D array of structures with new keyword in C++!

I have a structure defined in a file called 'xxx.h':
struct struct_name
{
declarations;
};
I included this header - 'xxx.h' - in another c++ file, yyy.cpp
And then I try to create a 2D array of the above structure using new keyword as follows (I learnt how to create a 2D array of structures from this link: Declaring a 2D array of type struct in c++).
struct struct_name * some_name;
some_name = new struct struct_name[x][y];
When I compile, I get the following error: error: ‘y’ cannot appear in a constant-expression. This error particularly points to the second dimension of the array.
Also When I tried to initialize this 2D array of structures with some value like:
some_name[i][j].var_name = value;
I get the following error:
error: no match for ‘operator[]’ in ‘*(some_name + ((sizetype)(((unsigned int)i) * 12u)))[j]’
Please advise me how to fix this.
Thanks.
In the interest of getting you up and running as quickly as possible, I'm going to belay the usual memory layout diatribe and simply tell you one way to get your situation resolved.
The reason you're error is happening is because C++ requires knowledge of types when declaring an array, allocating an array, etc. When you do this:
some_name = new struct_name[x][y];
what you're telling the compiler is "I want to allocate x objects of type struct_name[y]". But struct_name[y] isn't a type known at compile-time. The size is unknown, but must be known (thus the error about a constexpr expectations. This would work:
struct_name (*some_name)[WIDTH] = new struct_name[x][WIDTH];
would work if WIDTH is a compile-time known-constant. But for you, that isn't constant so another solution is required.
Altnerative Approach
An alternative quick-fix approach is presented below
#include <vector>
int main()
{
int rows, cols;
// get row and column count.
typedef std::vector<struct_name> MatrixRow;
typedef std::vector<MatrixRow> Matrix;
Matrix some_name(rows, MatrixRow(cols));
// use some_name[i][j] however you need
return 0;
}
There are other ways to do this, but this is likely the fastest way to get you running. Further, it promotes proper RAII concepts. If you need a more specialized purpose of a 2D matrix you may have to develop your own class, as the C++ standard library has no direct 2D dynamic array concept natively, thus why we invent it using a vector of vector-types.
Try the declaration within yyy.cpp as:
struct struct_name **some_name;
The reason for this is that some_name[i] needs to be of type struct_name * in order to access another level of variables.
Do you really need a c++ arrays?
Why not use std::vector<std::vector<struct_name>> ?
If you don't need dynamic allocation then you could use:
std::array<std::array<struct_name, 2>, 3> where 2 and 3 are the sizes of your 2D array.

Pushing a 2d array onto a C++ STL stack?

int test[5][5];
stack<int**> mystack;
mystack.push(test);
I get the error:
no matching function for call to ‘std::stack > >::push(int [5][5])’
/usr/include/c++/4.4/bits/stl_stack.h:182: note: candidates are: void std::stack<_Tp, _Sequence>::push(const typename _Sequence::value_type&) [with _Tp = int**, _Sequence = std::deque >]
I've never really used stacks before so I would appreciate any help. If I declare test as a one-dimensional array and stack as int*, it works fine.
Edit: I'm trying to implement backtracing for a sudokusolver. I have the sudoku grid as a 9x9 array of set objects (objects that hold the solution or possible solutions). I have to push the current state of the puzzle onto the stack, and then from there try guess and check. If a guess creates a contradiction (ie violates the rules of a sudoku), then I would pop from the stack to recover the puzzle before the invalid guess.
An int ** is not the same as a 2D array. A pointer to int test[5][5] would be int (*)[5], so you need a stack<int (*)[5]>. There's a good explanation of this here: Arrays and pointers in C.
In your example, test is not of type int**.
If you want a two-dimensional array, I would recommend using std::vector. This would certainly save your confusion with arrays and pointers...
typedef std::vector<std::vector<int> > two_d_vector;
two_d_vector test;
stack<two_d_vector> mystack;
mystack.push(test);