I use following code to generate discrete dynamic gradient matrix. It looks like to generate different value in some matrix element when runs the same get_dynamics_gradient2() for several times. I can't find any obvious mistake from many testing. Could you tell me how to get it correct?
#include "drake/common/find_resource.h"
#include "drake/multibody/parsing/parser.h"
#include "drake/multibody/plant/multibody_plant.h"
#include "drake/systems/framework/diagram_builder.h"
#include <Eigen/Dense>
#include "drake/math/autodiff.h"
#include "drake/math/autodiff_gradient.h"
#include "iostream"
using namespace std;
using drake::FindResourceOrThrow;
using drake::multibody::MultibodyPlant;
using drake::multibody::Parser;
using drake::systems::Context;
using drake::systems::InputPort;
using drake::systems::DiagramBuilder;
using Eigen::VectorXd;
using drake::AutoDiffVecXd;
using Eigen::MatrixXd;
using drake::AutoDiffXd;
using drake::math::initializeAutoDiff;
using drake::math::autoDiffToGradientMatrix;
using drake::math::autoDiffToValueMatrix;
MatrixXd get_dynamics_gradient2(std::unique_ptr<MultibodyPlant<AutoDiffXd>>& plant_ad,std::unique_ptr<Context<AutoDiffXd>>& context_ad,const VectorXd& x_val,const VectorXd& u_val) {
AutoDiffVecXd x_ad = initializeAutoDiff(x_val);
context_ad -> SetContinuousState(x_ad);
AutoDiffVecXd u_ad = initializeAutoDiff(u_val);
const InputPort<Eigen::AutoDiffScalar<Eigen::VectorXd>>& actuation_port = plant_ad -> get_actuation_input_port();
actuation_port.FixValue(context_ad.get(), u_ad);
auto derivatives = plant_ad -> AllocateTimeDerivatives();
plant_ad -> CalcTimeDerivatives(*context_ad, derivatives.get());
AutoDiffVecXd xdot_ad = derivatives -> get_vector().CopyToVector();
AutoDiffVecXd x_next_ad = xdot_ad * 0.1 + x_ad;
MatrixXd x_next = autoDiffToValueMatrix(x_next_ad);
AutoDiffVecXd x_next_ad_t = x_next_ad.transpose();
AutoDiffVecXd u_ad_t = u_ad.transpose();
AutoDiffVecXd xu_next_ad_t(x_next_ad_t.rows()+u_ad_t.rows(),x_next_ad_t.cols());
xu_next_ad_t << x_next_ad_t,u_ad_t;
MatrixXd AB = autoDiffToGradientMatrix(xu_next_ad_t.transpose());
return AB;
}
int main(int argc, char* argv[]) {
const double time_step = 0;
DiagramBuilder<double> builder;
const std::string relative_name = "drake/wc/ll0/acrobot.sdf";
const std::string full_name = FindResourceOrThrow(relative_name);
MultibodyPlant<double>& acrobot = *builder.AddSystem<MultibodyPlant>(time_step);
Parser parser(&acrobot);
parser.AddModelFromFile(full_name);
acrobot.Finalize();
std::unique_ptr<MultibodyPlant<AutoDiffXd>> plant_ad = MultibodyPlant<double>::ToAutoDiffXd(acrobot);
std::unique_ptr<Context<AutoDiffXd>> context_ad = plant_ad -> CreateDefaultContext();
VectorXd x_valp = VectorXd(4);
x_valp << 1.3, 5.8, 1.5, 0.02;
VectorXd u_valp= VectorXd(1);
u_valp << 0.01;
MatrixXd AB1 = get_dynamics_gradient2(plant_ad, context_ad, x_valp, u_valp);
MatrixXd AB2 = get_dynamics_gradient2(plant_ad, context_ad, x_valp, u_valp);
MatrixXd AB3 = get_dynamics_gradient2(plant_ad, context_ad, x_valp, u_valp);
MatrixXd AB4 = get_dynamics_gradient2(plant_ad, context_ad, x_valp, u_valp);
cout <<"AB2-AB1" << endl << AB2-AB1 <<endl;
cout <<"AB3-AB1" << endl << AB3-AB1 <<endl;
cout <<"AB4-AB1" << endl << AB4-AB1 <<endl;
return 0;
}
Here is the result:
AB2-AB1
0 0 0 0
0 0 0 0
0 0 0.735961 0.377986
0 0 -1.47292 -0.756483
0 1.73059e-77 1.96356 0
AB3-AB1
0 0 0 0
0 0 0 0
0 0 -0.35439 -0.35439
0 0 0.70926 0.70926
0 1.73059e-77 0.963558 0
AB4-AB1
0 0 0 0
0 0 0 0
0 0 1.28067 1.50475
0 0 -2.56308 -3.01153
0 2.90227e-157 0.963558 0
Related
I have an application that is written in C, and I would like to use a few OpenCV functions to do some image processing. I see where the C API has been deprecated, so I am currently trying to interface with the C++ API from C. I am running into some compilation issues.
Just to reproduce the example, let's say that I have this C main function in a file grouping_test_main.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <malloc.h>
extern "C"
{
#include "opencv_grouping.h"
}
uint8_t **allocate_2D_array(uint32_t SizeY, uint32_t SizeX);
int free_2D_array(uint8_t **image_array, uint32_t SizeY);
int main()
{
uint32_t SizeY=19;
uint32_t SizeX=20;
uint8_t **image_array;
FILE* fimage_array = fopen("./test_array.txt", "r");
double threshold_value=128;
ConnectedComponentsResults results;
int i;
int j;
image_array = allocate_2D_array(SizeY, SizeX);
for (i=0; i<SizeY; i++)
{
for (j=0; j<SizeX; j++)
{
fscanf(fimage_array, "%hhd", &image_array[i][j]);
}
}
fclose(fimage_array);
treshold_then_group(image_array, SizeY, SizeX, results);
printf("Number of connected components: %d\n", results.num_components);
free_2D_array(image_array, SizeY);
}
uint8_t **allocate_2D_array(uint32_t SizeY, uint32_t SizeX)
/*
* Allocates memory for a 2D image array.
*/
{
int i;
uint8_t **image_array;
image_array = malloc(SizeY * sizeof(uint8_t *));
for (i = 0; i < SizeY; i++)
{
image_array[i] = malloc(SizeX * sizeof(uint8_t ));
if(image_array[i] == NULL)
{
fprintf(stderr, "Memory allocation for image_array[%d] failed.\n", i);
exit(EXIT_FAILURE);
}
}
return image_array;
}
int free_2D_array(image_array, SizeY)
/*
* Frees memory allocated for 2D image array.
*/
uint8_t **image_array;
uint32_t SizeY;
{
int i;
for (i = 0; i < SizeY; i++)
{
free(image_array[i]);
}
return(1);
}
threshold_then_group() is the C++ function. test_array.txt is a text file with a 19X20 array:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 255 255 255 0 0 0 0 0 0 255 255 255 255 255 0 0 0
0 0 0 255 255 255 0 0 0 0 0 0 0 255 255 255 0 0 0 0
0 0 255 255 255 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 255 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0
0 0 0 255 255 255 255 255 0 0 0 0 255 255 255 255 0 0 0 0
0 0 0 0 255 255 255 255 255 0 0 255 255 255 0 0 0 0 0 0
0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 0 0 0 0 0
0 0 0 0 0 0 0 255 255 255 255 255 255 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
opencv_grouping.h is the header file where I declare the C++ functions.
/* Header file for opencv_grouping.cpp.
*/
#ifndef CONNECTED_COMPONENTS_H
#define CONNECTED_COMPONENTS_H
#include <stdint.h>
#include <opencv2/opencv.hpp>
struct ConnectedComponentsResults
{
int num_components;
cv::Mat labels;
cv::Mat stats;
cv::Mat centroids;
};
void threshold_then_group(uint8_t **image_array, uint32_t SizeY, uint32_t SizeX, double threshold_value, ConnectedComponentsResults &results);
#endif
Then, the C++ functions in opencv_grouping.cpp are:
/* Grouping and centroiding implementation using OpenCV's
* connectedComponentsWithStats().
*/
#include <stdint.h>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <opencv2/opencv.hpp>
#include "opencv_grouping.h"
void threshold_then_group(uint8_t **image_array, uint32_t SizeY, uint32_t SizeX, double threshold_value, ConnectedComponentsResults &results)
{
uint8_t *image_data = new uint8_t[SizeY * SizeX];
double max_value=255.0;
int i;
int j;
for (i=0; i<SizeY; i++)
{
for (j=0; j<SizeX; j++)
{
image_data[i * SizeX + j] = image_array[i][j];
}
}
cv::Mat image(SizeY, SizeX, CV_8U, image_data);
cv::Mat binary;
threshold(image, binary, threshold_value, max_value, cv::THRESH_BINARY);
cv::Mat labels, stats, centroids;
int num_components = cv::connectedComponentsWithStats(binary, results.labels, results.stats, results.centroids, 8, CV_32S);
results.num_components = results.stats.rows - 1;
delete[] image_data;
}
I am attempting to compile the code like this:
g++ `pkg-config --cflags opencv4` -c opencv_grouping.cpp
gcc `pkg-config --cflags opencv4` -c grouping_test_main.c
gcc opencv_test.o opencv_grouping.o -lstdc++ `pkg-config --libs opencv4` -o opencv_test2
opencv_grouping.cpp compiles just fine, but grouping_test_main.c fails. This is because opencv_grouping.h includes opencv2/opencv.hpp, and the error messages indicate that the files included in opencv.hpp must be compiled using a C++ compiler. I haven't tried to compile the main function using g++, but even if this somehow works, this isn't really a solution. My actual main function is a lot more complicated than what I've shown here, and it uses a lot of C libraries that I don't think would compile with g++.
I came across a problem in a game described below. You are given an n by n matrix with 0 and 1. The only operation that you can do is to "press" one value in the matrix and the rows and columns associated with the value will flip. (including itself)
So for example, if we are given a 5 by 5 matrix.
1 0 1 0 1
0 1 1 1 0
1 0 0 1 1
0 0 0 1 1
1 1 1 0 0
"Pressing" the (1,1) position will yield a matrix
1 1 1 0 1
1 0 0 0 1
1 1 0 1 1
0 1 0 1 1
1 0 1 0 0
The goal is to reach all 0 with the least steps.
I used bfs in this case and I was able to get the least steps. However, what I want to print out is the position in the matrix that I am changing along the way. Any help will be appreciated. My current code is as follows.
void flip(int i, int j, std::vector<std::vector<int>>& adj)
{
int m = adj.size(), n = adj[0].size();
adj[i][j] ^= 1;
for (int row = 0; row < n; row++)
{
adj[i][row] ^= 1;
}
for (int col = 0; col < m; col++)
{
adj[col][j] ^= 1;
}
}
int minFlips(std::vector<std::vector<int>>& mat)
{
if (all_zero(mat))
{
return 0;
}
std::map<std::vector<std::vector<int>>, int> mp;
std::queue<std::vector<std::vector<int>>> q;
std::set<std::vector<std::vector<int>>> visited;
q.push(mat);
mp[mat] = 0;
visited.insert(mat);
while (!q.empty())
{
auto cur = q.front();
q.pop();
auto adj = cur;
for (int i = 0; i < adj.size(); i++)
{
for (int j = 0; j < adj[0].size(); j++)
{
flip(i, j, adj);
if (all_zero(adj))
{
return 1 + mp[cur];
}
if (visited.find(adj) == visited.end())
{
visited.insert(adj);
mp[adj] = 1 + mp[cur];
q.push(adj);
}
flip(i, j, adj);
}
}
}
return -1;
}
This is a follow-up of another similar issue. Only in my case, I am seeing >2 geometry ids not only for a link, but also its collision element.
In the code below, I am printing out geometry id's that are valid collision pairs:
#include "drake/multibody/inverse_kinematics/inverse_kinematics.h"
#include "drake/math/rotation_matrix.h"
#include "drake/solvers/create_constraint.h"
#include "drake/solvers/solve.h"
#include "drake/multibody/parsing/parser.h"
// #include "drake/solvers/clp_solver.h"
// #include "drake/solvers/csdp_solver.h"
#include "drake/solvers/gurobi_solver.h"
#include "drake/solvers/ipopt_solver.h"
#include "drake/solvers/mosek_solver.h"
#include "drake/solvers/snopt_solver.h"
#include "drake/solvers/solver_options.h"
#include "drake/solvers/nlopt_solver.h"
#include "drake/geometry/proximity_properties.h"
#include "drake/geometry/scene_graph_inspector.h"
#include "drake/geometry/shape_specification.h"
// #include "drake/multibody/tree/multibody_tree_indexes.h"
#include "drake/systems/analysis/simulator.h"
#include "drake/visualization/visualization_config_functions.h"
#include <iostream>
#include <boost/filesystem.hpp>
#include <fstream>
#include <chrono>
#include <numeric>
#include <bits/stdc++.h>
// using namespace boost::filesystem;
using namespace std;
int main() {
string sdf_filepath = "path_to_sdf.sdf";
drake::systems::DiagramBuilder<double> builder;
drake::multibody::MultibodyPlant<double>* plant{};
drake::geometry::SceneGraph<double>* scene_graph{};
std::tie(plant, scene_graph) = drake::multibody::AddMultibodyPlantSceneGraph(&builder, timestep);
plant->set_name("plant");
scene_graph->set_name("scene_graph");
drake::multibody::Parser parser(plant, scene_graph);
const auto robot_model_index = parser.AddModelFromFile(sdf_filepath, "robot");
plant->Finalize();
auto diagram = builder.Build();
auto diagram_context= diagram->CreateDefaultContext();
auto plant_context = &(diagram->GetMutableSubsystemContext(*plant,
diagram_context.get()));
const auto& inspector = scene_graph->model_inspector();
auto collision_pairs = inspector.GetCollisionCandidates();
for (auto& pair : collision_pairs) {
cout << pair.first << ", " << pair.second << endl;
const auto first_geom_id = pair.first;
const auto second_geom_id = pair.first;
const auto first_name = inspector.GetName(first_geom_id);
const auto second_name = inspector.GetName(second_geom_id);
cout << first_name << ", " << second_name << endl;
cout << "Left: " << endl;
const auto first_frame_id = inspector.GetFrameId(first_geom_id);
const auto first_geom_model_index = inspector.GetFrameGroup(first_frame_id);
const auto first_source_name = inspector.GetOwningSourceName(first_frame_id);
// NOTE: CUSTOM MODIFIED FUNCTION, essentially making GeometryState::get_solver_id() public
const auto first_source_id = inspector.GetOwningSourceId(first_geom_id);
cout << "frame_id: " << first_frame_id << endl;
cout << "geom_model_index: " << first_geom_model_index << endl;
cout << "robot_model_index: " << robot_model_index << endl;
cout << "source_name: " << first_source_name << endl;
cout << "source_id: " << first_source_id << endl;
cout << endl;
cout << "Right: " << endl;
const auto second_frame_id = inspector.GetFrameId(second_geom_id);
const auto second_geom_model_index = inspector.GetFrameGroup(second_frame_id);
const auto second_source_name = inspector.GetOwningSourceName(second_frame_id);
const auto second_source_id = inspector.GetOwningSourceId(second_geom_id);
cout << "frame_id: " << second_frame_id << endl;
cout << "geom_model_index: " << second_geom_model_index << endl;
cout << "robot_model_index: " << robot_model_index << endl;
cout << "source_name: " << second_source_name << endl;
cout << "source_id: " << second_source_id << endl;
cout << endl;
}
}
and here is a clip of the output:
129, 150
robot::right_link5_collision, robot::right_link5_collision
129, 152
robot::right_link5_collision, robot::right_link5_collision
129, 154
robot::right_link5_collision, robot::right_link5_collision
129, 156
robot::right_link5_collision, robot::right_link5_collision
129, 162
robot::right_link5_collision, robot::right_link5_collision
129, 168
robot::right_link5_collision, robot::right_link5_collision
Here is the corresponding part of the SDF file that contains right_link5 (defined only once):
<link name='right_link5'>
<pose relative_to='right_joint5'>0 0 0 0 -0 0</pose>
<inertial>
<pose>-0.000234 0.036705 -0.080064 0 -0 0</pose>
<mass>0.18554</mass>
<inertia>
<ixx>0.010000</ixx>
<ixy>8.9957e-07</ixy>
<ixz>8.5285e-07</ixz>
<iyy>0.010000</iyy>
<iyz>-0.00025682</iyz>
<izz>0.010000</izz>
</inertia>
</inertial>
<collision name='right_link5_collision'>
<pose>0 0 0 0 -0 0</pose>
<geometry>
<mesh>
<scale>1 1 1</scale>
<uri>file:///home/user/.../collision/link5.STL</uri>
</mesh>
</geometry>
</collision>
<visual name='right_link5_visual'>
<pose>0 0 0 0 -0 0</pose>
<geometry>
<mesh>
<scale>1 1 1</scale>
<uri>file:///home/user/.../visual/link5.STL</uri>
</mesh>
</geometry>
</visual>
</link>
Any thoughts on why this could be happening? I also printed out more information, and these geometry bodies seem to be identical:
129, 162
robot::right_link5_collision, robot::right_link5_collision
Left:
frame_id: 125
geom_model_index: 2
robot_model_index: 2
source_name: plant
source_id: 15
Right:
frame_id: 125
geom_model_index: 2
robot_model_index: 2
source_name: plant
source_id: 15
I'm trying to extract the 3x3 rotation matrix from the 3x4 pose matrix I have. However, two values are differing even though I have very simple code setting one to the other. I'm banging my head against the wall because I have no idea why this is happening. Here is the code:
std::cout << "Camera pose matrix from optical flow homography" << std::endl;
for (int e = 0; e < pose.rows; e++) {
for (int f = 0; f < pose.cols; f++) {
std::cout << pose.at<double>(e,f) << " " << e << " " << f;
std::cout << " ";
}
std::cout << "\n" << std::endl;
}
std::cout << "Creating rotation matrix" << std::endl;
Mat rotvec = Mat::eye(3, 3, CV_32FC1);
for (int s = 0; s < pose.rows; s++) {
for (int g = 0; g < pose.cols-1; g++) {
rotvec.at<double>(s, g) = pose.at<double>(s,g);
std::cout << rotvec.at<double>(s,g) << " " << s << " " << g;
std::cout << " ";
}
std::cout << "\n" << std::endl;
}
std::cout << "Rotation matrix" << std::endl;
for (int e = 0; e < pose.rows; e++) {
for (int f = 0; f < pose.cols-1; f++) {
std::cout << rotvec.at<double>(e,f) << " " << e << " " << f;
std::cout << " ";
std::cout << pose.at<double>(e,f) << " " << e << " " << f;
std::cout << " ";
}
std::cout << "\n" << std::endl;
}
Here is the output:
Camera pose matrix from optical flow homography
5.26354e-315 0 0 0 0 1 0.0078125 0 2 0 0 3
0.0078125 1 0 0 1 1 0 1 2 5.26354e-315 1 3
0 2 0 5.26354e-315 2 1 1.97626e-323 2 2 7.64868e-309 2 3
Creating rotation matrix
5.26354e-315 0 0 0 0 1 0.0078125 0 2
0.0078125 1 0 0 1 1 0 1 2
0 2 0 5.26354e-315 2 1 1.97626e-323 2 2
Rotation matrix
5.26354e-315 0 0 5.26354e-315 0 0 0 0 1 0 0 1 5.26354e-315 0 2 0.0078125 0 2
0.0078125 1 0 0.0078125 1 0 0 1 1 0 1 1 0.0078125 1 2 0 1 2
0 2 0 0 2 0 5.26354e-315 2 1 5.26354e-315 2 1 1.97626e-323 2 2 1.97626e-323 2 2
Here you can see I'm trying to save the first three columns of pose into the rotvec matrix. When I actually set the rotation matrix equal to the pose for those three columns, I get the correct matrix, as the second matrix is equal to the first three columns of the first matrix. However, when I check the rotation matrix once again, (third matrix) it is not the same as the output I require on coordinates (0, 2) and (1, 2). (I outputted the rotvec matrix number next to the pose matrix number, and you can see at these coordinates the numbers do not match). I am not sure why this is happening, could someone please help me out?
Solved my problem for anyone else who stumbles upon this later: I just changed the Mat type to CV_64F (to make it double) for both rotvec and pose, and used all to display. Creds to berak for pointing me in the right direction.
My code (below) is working if I use QoS 0. But for QoS 1 or QoS 2. MQTTClient_publishMessage(...) failed.
Am I missing any configuration? Or, is it because I am using free XIvely account?
I use Paho API.
------------------------------- start of cut -------------------------------------
/**
* #file
*
* Paho MQ Client API to Xively mqtt broker
*
*/
enter code here
#include "MQTTClient.h"
#include <stdlib.h>
void usage()
{
printf("Usage: speicify QoS\n");
printf(" turn on bulb -> ka_pub Qos 1 1\n");
printf(" turn off bulb -> ka_pub Qos 1 0\n");
printf(" send 7 to led -> ka_pub Qos 2 7\n");
printf(" send 2 to led -> ka_pub Qos 2 2\n");
}
int main(int argc, char** argv)
{
int rc = 0;
if (argc < 3) {
usage();
exit (0);
}
char TOPIC[250] ; // given enough space first to avoid malloc
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
int QoS = atoi(argv[1]);
if (argv[2][0] == '1') {
strcpy(TOPIC, BULB_TOPIC);
conn_opts.username = BULB_API_KEY ;
conn_opts.password = "" ; // will be ignored
} else
if (argv[2][0] == '2') {
strcpy(TOPIC, LED_TOPIC) ;
conn_opts.username = LED_API_KEY ;
conn_opts.password = "" ; // will be ignored
} else {
printf("Bad arg\n");
usage();
exit (0);
}
setenv("MQTT_C_CLIENT_TRACE", "ON", 1); // same as 'stdout'
setenv("MQTT_C_CLIENT_TRACE_LEVEL", "ERROR", 1); //ERROR, PROTOCOL, MINIMUM, MEDIUM and MAXIMUM
MQTTClient_create(&client, XIVELY_END_URL, "test", MQTTCLIENT_PERSISTENCE_DEFAULT, NULL);
//conn_opts.keepAliveInterval = 20; // init to 60
//conn_opts.cleansession = 1; // default 1, will clean previous msg in server
conn_opts.reliable = 0 ; //default 1, only 1 can in-flight, 0 - allow 10 msg
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to connect, return code %d\n", rc);
exit(-1);
}
// prepare publish msg
char tmsg[250] ; // check max 250 boundary later
if (argv[2][0] == '1')
sprintf(tmsg, "{\"id\":\"switch\",\"current_value\":\"%c\"}", argv[3][0]);
else
sprintf(tmsg, "{\"id\":\"num\",\"current_value\":\"%c\"}", argv[3][0]) ;
int tmsg_len = strlen(tmsg);
pubmsg.payload = &tmsg[0] ;
pubmsg.payloadlen = tmsg_len; //mlen
pubmsg.qos = QoS;
pubmsg.retained = 0;
MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
//MQTTClient_publish(client, TOPIC, pubmsg.payloadlen, pubmsg.payload,
// pubmsg.qos, pubmsg.retained, &token);
rc = MQTTClient_waitForCompletion(client, token, 100000);
printf("Finish publish for TOPIC: %s, QoS: %d, msg of '%s'\n", TOPIC, pubmsg.qos, (char *) pubmsg.payload);
if (rc == 0)
MyLog(LOGA_INFO, "verdict pass");
else
MyLog(LOGA_INFO, "verdict fail");
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}
------------------------------- end of cut -------------------------------------
I don't believe Xively supports QoS>0.