I have a callback function (for ROS subscriber of type PointCloud2 msg).
I want to be able to pass a different pointer member inside the callback function because I saw that when I call the function twice there is a problem in the values of the variable that use this pointer.
This is part of my code:
class Planner {
public:
char frame_id[10] = "os1_lidar";
int num_area = 1;
int i = 0; // for create the circular path
float right_point_y = 0;
float left_point_y = 0;
float y_distance = 0; //the distance between the trees in the Y axis
float center_point_y = 0; //the center point between the trees in the y axis after average calculation
float right_center_point_x = 0; //the center point of the right tree in the x axis
float left_center_point_x = 0; //the center point of the left tree in the x axis
float max_center_point_y = 1.4; //the max distance in the 7 axis for sending to arduino the steering angle
//setting the two side area of the trees to filter the point cloud
float minX_r = -5, minY_r = 2, minZ_r = -0.4;
float maxX_r = -2, maxY_r = 4, maxZ_r = -0.1;
float minX_l = -5, minY_l = -4, minZ_l = -0.4;
float maxX_l = -2, maxY_l = -2, maxZ_l = 0.1;
int red, green, blue = 0; //for change the boxes' color outside the lines
bool publish_points = true;
bool publish_markers = true;
ros::Publisher point_cloud_pub;
ros::Publisher center_point_marker_pub;
ros::Publisher right_point_marker_pub;
ros::Publisher left_point_marker_pub;
ros::Publisher marker_area_right_pub;
ros::Publisher marker_area_left_pub;
void Point_Filtering(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &cloud_msg);
}
void Planner::Point_Filtering(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &cloud_msg) {
ROS_INFO_STREAM_ONCE("Getting Data from Lidar");
ROS_INFO_STREAM_ONCE("size " << cloud_msg->size());
ROS_INFO_STREAM_ONCE("width " << cloud_msg->width);
ROS_INFO_STREAM_ONCE("height " << cloud_msg->height);
// Right Line
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered_r(new pcl::PointCloud<pcl::PointXYZ>);
//Left Line
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered_l(new pcl::PointCloud<pcl::PointXYZ>);
//Right Trees Box Filter
pcl::CropBox<pcl::PointXYZ> boxFilter_r;
boxFilter_r.setInputCloud(cloud_msg);
boxFilter_r.setMin(Eigen::Vector4f(minX_r, minY_r, minZ_r, 1.0));
boxFilter_r.setMax(Eigen::Vector4f(maxX_r, maxY_r, maxZ_r, 1.0));
boxFilter_r.setNegative(false);
boxFilter_r.setTranslation(Eigen::Vector3f(0.0, 0.0, 0.0));
boxFilter_r.filter(*cloud_filtered_r);
//Left Trees Box Filter
pcl::CropBox<pcl::PointXYZ> boxFilter_l;
boxFilter_l.setInputCloud(cloud_msg);
boxFilter_l.setMin(Eigen::Vector4f(minX_l, minY_l, minZ_l, 1.0));
boxFilter_l.setMax(Eigen::Vector4f(maxX_l, maxY_l, maxZ_l, 1.0));
boxFilter_l.setNegative(false);
boxFilter_l.setTranslation(Eigen::Vector3f(0.0, 0.0, 0.0));
boxFilter_l.filter(*cloud_filtered_l);
//Right Trees (Y axis)
Eigen::Vector4f centroid_r_y;
pcl::compute3DCentroid(*cloud_filtered_r, centroid_r_y);
right_point_y = centroid_r_y[1];
//Left Trees (Y axis)
Eigen::Vector4f centroid_l_y;
pcl::compute3DCentroid(*cloud_filtered_l, centroid_l_y);
left_point_y = centroid_l_y[1];
y_distance = abs(centroid_l_y[1]) + abs(centroid_r_y[1]);
center_point_y = (abs(centroid_l_y[1]) - abs(centroid_r_y[1])) / 2;
//Right Trees (X axis)
Eigen::Vector4f centroid_r_x;
pcl::compute3DCentroid(*cloud_filtered_r, centroid_r_x);
right_center_point_x = centroid_r_x[0];
// ROS_INFO_STREAM("right_point_x : "<< num_area << " :" << right_center_point_x);
//Left Trees (X axis)
Eigen::Vector4f centroid_l_x;
pcl::compute3DCentroid(*cloud_filtered_l, centroid_l_x);
left_center_point_x = centroid_l_x[0];
}
int main(int argc, char **argv) {
ROS_INFO_STREAM_ONCE("Running");
// Initialize ROS
ros::init(argc, argv, "pcl_filter_node");
ros::NodeHandle nh;
//region 1st
Planner planner;
ros::Subscriber sub = nh.subscribe<pcl::PointCloud<pcl::PointXYZ> >("/fused_points", 1,
&Planner::Point_Filtering, &planner);
planner.num_area = 1;
planner.minX_r = -3;
planner.minX_l = -3;
planner.maxX_r = 0;
planner.maxX_l = 0;
planner.point_cloud_pub = nh.advertise<pcl::PointCloud<pcl::PointXYZ> >("pcl_filtered", 1);
planner.center_point_marker_pub = nh.advertise<visualization_msgs::Marker>("center_marker",
1);
planner.right_point_marker_pub = nh.advertise<visualization_msgs::Marker>("right_marker",
1);
planner.left_point_marker_pub = nh.advertise<visualization_msgs::Marker>("left_x_marker",
1);
planner.marker_area_right_pub = nh.advertise<visualization_msgs::Marker>("right_box_marker",
1);
planner.marker_area_left_pub = nh.advertise<visualization_msgs::Marker>("left_box_marker",
1);
//endregion
//region 2nd
Planner planner_2;
planner_2.num_area = 2;
planner_2.minX_r = -8 ;
planner_2.minX_l = -8;
planner_2.maxX_r = -5;
planner_2.maxX_l = -5;
planner_2.publish_points = false;
planner_2.point_cloud_pub = nh.advertise<pcl::PointCloud<pcl::PointXYZ> >("pcl_filtered_2",
1);
planner_2.center_point_marker_pub = nh.advertise<visualization_msgs::Marker>
("center_marker_2", 1);
planner_2.right_point_marker_pub = nh.advertise<visualization_msgs::Marker>
("right_marker_2", 1);
planner_2.left_point_marker_pub = nh.advertise<visualization_msgs::Marker>
("left_x_marker_2", 1);
planner_2.marker_area_right_pub = nh.advertise<visualization_msgs::Marker>
("right_box_marker_2", 1);
planner_2.marker_area_left_pub = nh.advertise<visualization_msgs::Marker>
("left_box_marker_2", 1);
ros::Subscriber sub2 = nh.subscribe<pcl::PointCloud<pcl::PointXYZ> >("/fused_points", 1,
&Planner::Point_Filtering, &planner_2);
//endregion
ros::Rate r(15);
ros::Time test_time;
while (nh.ok()) {
ros::spinOnce();
r.sleep();
}
}
This code takes the original point clouds, filters it to relevant areas and then calculate centroid in those filtered point clouds.
I want to take this line :
pcl::PointCloudpcl::PointXYZ::Ptr cloud_filtered_r(new
pcl::PointCloudpcl::PointXYZ);
and to put it in the public part of the class so I will be able to change this name of the filtered points.
When I subscribe to the same msg twice the centroid of the second area is equal to the first and this is wrong for me.
Thanks for your help.
Related
Lot of code to post because I can't really tell where the issue is. I am trying to run this on an ESP32 chip and am writing the code in vscode with platformio.
The function
byte _previousPoint(){
for (byte point = 0; point < maxPoints; point ++){ //loop through active points.
if (_points[point + 1].getActive() != 1){
return point;
}
else {
long t1 = point_seconds(point);
long t2 = point_seconds(point + 1);
if (t1 <= currentTime){ //If current time is after this point.
if (t2 > currentTime){ //If current time is less than the next point (it is sandwiched).
return point;
}
}
}
}
return 0;
}
Is not behaving as I expect. And it seems the cause is that the function
bool getActive(){
return _active;
}
under the class point is returning not a bool but ascending numbers for each channel. point.getActive() should return a bool value, and that bool value should default to 0 (as it is set in the class definition), which is why this makes no sense. The point that is returning the erroneous values is the last one in the _points[maxPoints] array for each channel, and that value seems to match the channel numbers (for red it is 0, for green it is 1, for blue it is 2, etc.)
If I print the value _active upon running the point.setActive() function it comes out correctly. So something is wrong with "getting" it later.
Here is full code below. Let me know if you need some clarification because I know it's a lot. And thanks for anybody patient enough to help.
#include <Arduino.h>
long currentTime;
long lastUp;
byte totalChannels = 4;
const byte maxPoints = 3;
class point {
public:
point(){
}
void clear(){
_active = 0;
_day = 0;
_hour = 0;
_minute = 0;
_second = 0;
_intensity = 0;
_mode = 0;
}
bool getActive(){
return _active;
}
uint getDay(){
return _day;
}
byte getHour(){
return _hour;
}
byte getMinute(){
return _minute;
}
byte getSecond(){
return _second;
}
int getIntensity(){
return _intensity;
}
byte getMode(){
return _mode;
}
void setActive(bool active){
_active = active;
}
void setDay(uint day){
_day = day;
}
void setHour(byte hour){
_hour = hour;
}
void setMinute(byte minute){
_minute = minute;
}
void setSecond(byte second){
_second = second;
}
void setIntensity(byte intensity){
_intensity = intensity;
}
void setMode(byte mode){
_mode = mode;
}
private:
bool _active = 0;
uint _day = 0;
byte _hour = 0;
byte _minute = 0;
byte _second = 0;
int _intensity = 0;
byte _mode = 0;
};
class channel {
public:
channel(String color, byte pin){
this->_color = color;
this->_pin = pin;
init();
};
void setpoint(byte row, point &newPoint, uint day, byte hour, byte minute, byte second, byte intensity, byte mode){ //edits points (for debug)
newPoint.setDay(day);
newPoint.setHour(hour);
newPoint.setMinute(minute);
newPoint.setSecond(second);
newPoint.setIntensity(intensity);
newPoint.setMode(mode);
newPoint.setActive(1);
_points[row] = newPoint;
}
bool getPoint(byte point){
return _points[point + 1].getActive();
}
void clearAllPoints(){
for (byte point = 0; point < maxPoints; point ++ ){
_points[point].clear();
}
}
void setPin(byte pin){
_pin = pin;
}
byte getPin(){
return _pin;
}
uint getIntensity(){
byte point1 = _previousPoint();
byte point2 = _nextPoint(point1);
byte fade_mode = _points[point1].getMode();
uint intensity;
if (point2 != 0){
if (fade_mode == 0){
intensity = _interpolate_lin(point1, point2);
}
else if (fade_mode == 1){
intensity = _interpolate_sin(point1, point2);
}
}
else if (point2 != 1){
if (fade_mode == 0){
intensity = _interpolate_lin(point1, point2);
}
else if (fade_mode == 1){
intensity = _interpolate_sin(point1, point2);
}
}
return intensity;
}
private:
//class attributes
point _points[maxPoints]; //points maximum of 64 points per channel.
byte _pin; //PWM pin output for channel
String _color; //LED color
float _interpolate_lin(byte point1, byte point2){
float idiff = _points[point2].getIntensity() - _points[point1].getIntensity();
float tdiff = point_seconds(point2) - point_seconds(point1);
float m;
if (tdiff != 0){
m = idiff / tdiff;
}
else{
m = 0;
}
float t = currentTime - point_seconds(point1);
float b = _points[point1].getIntensity();
//linear equation result
float i = (m * t) + b;
return i;
}
float _interpolate_sin(byte point1, byte point2){
float amplitude = _points[point2].getIntensity() - _points[point1].getIntensity();
float tdiff = point_seconds(point2) - point_seconds(point1);
float a = (-0.5 * amplitude);
float b = (2 * PI) / (2 * tdiff);
float t = (currentTime - point_seconds(point1));
float d = 0.5 * abs(amplitude);
//cosine equation result
float i = (a * cos(b * t)) + d;
return i;
}
byte _previousPoint(){
for (byte point = 0; point < maxPoints; point ++){ //loop through active points.
if (_points[point + 1].getActive() != 1){
return point;
}
else {
long t1 = point_seconds(point);
long t2 = point_seconds(point + 1);
if (t1 <= currentTime){ //If current time is after this point.
if (t2 > currentTime){ //If current time is less than the next point (it is sandwiched).
return point;
}
}
}
}
return 0;
}
byte _nextPoint(byte point){
if (_points[point + 1].getActive() != 1){ //if next point is inactive, previous is last in cycle. Next point is 0.
return 0;
}
else if (_points[point + 1].getActive() == 1){ //if next point is active, return it as _nextPoint.
return point + 1;
}
return 0;
}
long point_seconds(byte point){
return ((_points[point].getHour() * 3600) + (_points[point].getMinute() * 60) + _points[point].getSecond());
}
};
//declaring channels and initializing channel array.
channel red("red", 0);
channel green("green", 1);
channel blue("blue", 2);
channel royal("royal blue", 3);
channel *channels[] = {
&red,
&green,
&blue,
&royal
};
void setIntensities(){
for (byte ch = 0; ch < totalChannels; ch ++){
channel ledChannel = *channels[ch];
byte intensity = ledChannel.getIntensity();
ledcWrite(ledChannel.getPin(), intensity);
}
}
void setup() {
Serial.begin(9600);
//set up LED outputs
ledcAttachPin(12, 0);
ledcAttachPin(13, 1);
ledcAttachPin(16, 2);
ledcSetup(0, 1000, 8);
ledcSetup(1, 1000, 8);
ledcSetup(2, 1000, 8);
//clear all points
for (byte ch = 0; ch < totalChannels; ch++){
channel ledChannel = *channels[ch];
ledChannel.clearAllPoints();
}
//Set points for testing purposes
point red1;
point red2;
point red3;
point green1;
point green2;
point green3;
point blue1;
point blue2;
point blue3;
point royal1;
point royal2;
point royal3;
red.setpoint(0, red1, 0, 0, 0, 0, 0, 0);
red.setpoint(1, red2, 0, 0, 0, 10, 255, 0);
red.setpoint(2, red3, 0, 0, 0, 20, 0, 0);
green.setpoint(0, green1, 0, 0, 0, 10, 0, 0);
green.setpoint(1, green2, 0, 0, 0, 20, 255, 0);
green.setpoint(2, green3, 0, 0, 0, 30, 0, 0);
blue.setpoint(0, blue1, 0, 0, 0, 20, 0, 0);
blue.setpoint(1, blue2, 0, 0, 0, 30, 255, 0);
blue.setpoint(2, blue3, 0, 0, 0, 40, 0, 0);
royal.setpoint(0, royal1, 0, 0, 0, 30, 0, 0);
royal.setpoint(1, royal2, 0, 0, 0, 40, 255, 0);
royal.setpoint(2, royal3, 0, 0, 0, 50, 0, 0);
Serial.print("red: "); // <----------These are to debug. The channels are returning ascending bool values for point 3 (which should all be 0)
for (byte point = 0; point < 3; point++){
Serial.print(red.getPoint(point));
}
Serial.print(" green: ");
for (byte point = 0; point < 3; point++){
Serial.print(green.getPoint(point));
}
Serial.print(" blue: ");
for (byte point = 0; point < 3; point++){
Serial.print(blue.getPoint(point));
}
Serial.print(" royal: ");
for (byte point = 0; point < 3; point++){
Serial.print(royal.getPoint(point));
}
}
void loop() {
currentTime = millis() / 1000;
if (currentTime > lastUp){
setIntensities();
lastUp = currentTime;
}
}
The problem is with your getPoint() method:
bool getPoint(byte point){
return _points[point + 1].getActive();
}
You're referencing the array with point + 1 instead of point so when you attempt to read the last item in the array you're actually reading off the end of the array and getting arbitary data.
Just change this to:
bool getPoint(byte point){
return _points[point].getActive();
}
You're also doing the same thing on your _previousPoint() method:
byte _previousPoint(){
for (byte point = 0; point < maxPoints; point ++){ //loop through active points.
if (_points[point + 1].getActive() != 1){
return point;
}
Again - I think you want to just replace [point + 1] with [point] to go through the list of points and prevent reading past the end of the array.
I create a wireframe mesh of two lines between three points:
By these functions:
Qt3DRender::QGeometryRenderer *Utils::createWireframeMesh()
{
Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer();
Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry(mesh);
Qt3DRender::QBuffer *vertexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer,
geometry);
Qt3DRender::QBuffer *indexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer,
geometry);
QByteArray vertexBufferData;
QByteArray indexBufferData;
int vertexCount = 3; // Three vertices at (0, -1, 0) and (1, 0, 0) and (0, 1, 0)
int lineCount = 2; // Two lines between three vertices
vertexBufferData.resize(vertexCount * 3 * sizeof(float));
indexBufferData.resize(lineCount * 2 * sizeof(ushort));
// Arrow triangle is 2D and is inside XY plane
float *vPtr = reinterpret_cast<float *>(vertexBufferData.data());
vPtr[0] = 0.0f; vPtr[1] = -1.0f; vPtr[2] = 0.0f; // First vertex at (0, -1, 0)
vPtr[3] = 1.0f; vPtr[4] = 0.0f; vPtr[5] = 0.0f; // Second vertex at (1, 0, 0)
vPtr[6] = 0.0f; vPtr[7] = +1.0f; vPtr[8] = 0.0f; // Third vertex at (0, 1, 0)
ushort *iPtr = reinterpret_cast<ushort *>(indexBufferData.data());
iPtr[0] = 0; iPtr[1] = 1; // First line from index 0 to index 1
iPtr[2] = 1; iPtr[3] = 2; // Second line from index 1 to index 2
vertexDataBuffer->setData(vertexBufferData);
indexDataBuffer->setData(indexBufferData);
addPositionAttributeToGeometry(geometry, vertexDataBuffer, vertexCount);
addIndexAttributeToGeometry(geometry, indexDataBuffer, lineCount * 2);
mesh->setInstanceCount(1);
mesh->setIndexOffset(0);
mesh->setFirstInstance(0);
// How to set vertex count here?
mesh->setVertexCount(vertexCount);
mesh->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
mesh->setGeometry(geometry);
return mesh;
}
void Utils::addPositionAttributeToGeometry(Qt3DRender::QGeometry *geometry,
Qt3DRender::QBuffer *buffer, int count)
{
Qt3DRender::QAttribute *posAttribute = new Qt3DRender::QAttribute();
posAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
posAttribute->setBuffer(buffer);
posAttribute->setDataType(Qt3DRender::QAttribute::Float);
posAttribute->setDataSize(3);
posAttribute->setByteOffset(0);
posAttribute->setByteStride(0);
posAttribute->setCount(count);
posAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
geometry->addAttribute(posAttribute);
}
void Utils::addIndexAttributeToGeometry(Qt3DRender::QGeometry *geometry,
Qt3DRender::QBuffer *buffer, int count)
{
Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute();
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
indexAttribute->setBuffer(buffer);
indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedShort);
indexAttribute->setDataSize(1);
indexAttribute->setByteOffset(0);
indexAttribute->setByteStride(0);
indexAttribute->setCount(count);
geometry->addAttribute(indexAttribute);
}
In above code, I tried three different statements at this line:
// How to set vertex count here?
mesh->setVertexCount(vertexCount);
mesh->setVertexCount(vertexCount * 2);
mesh->setVertexCount(vertexCount * 3);
With these results - I do some ray casting in my 3D scene which are surprisingly affected too:
Documentation explains vertexCount property of Qt3DRender::QGeometryRenderer as:
vertexCount : int
Holds the primitive count.
In my case, primitive count is line count, so I tried it but only one line is drawn:
I'm confused about setVertexCount API. Can anybody give me a hint?
vertexCount is the same value that you would pass to glDrawArrays or glDrawElements, ie it's the number of vertices involved in the drawing. Since you're using indexed rendering, that would typically be the number of indexes (assuming you're drawing all in data in the index array). So in the case above, it should be 4.
Please note we recently fixed a bug with line picking when using primitive restart, but that doesn't affect the code you included above.
help please, at Arduino Uno I receive a signal from the sensor and build a graph using processing 2.2.1, but you need to scale up without losing proportions. My attempts failed, the proportion was crumbling(I tried to multiply the values) Code:
Serial myPort;
int xPos = 1;
int yPos = 100;
float yOld = 0;
float yNew = 0;
float inByte = 0;
int lastS = 0;
PFont f;
void setup () {
size(1200, 500);
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);
myPort.bufferUntil('\n');
background(0xff);
}
void draw () {
int s = second();
PFont f = createFont("Arial",9,false);
textFont(f,9);
fill(0);
if (s != lastS){
stroke(0xcc, 0xcc, 0xcc);
line(xPos, yPos+10, xPos, yPos+30);
text(s + " Sec.", xPos+5, yPos+30);
lastS = s;
}
}
void mousePressed(){
save(lastS + "-heart.jpg");
}
void serialEvent (Serial myPort) {
String inString = myPort.readStringUntil('\n');
if (inString != null) {
inString = trim(inString);
if (inString.equals("!")) {
stroke(0, 0, 0xff); // blue
inByte = 1023;
} else {
stroke(0xff, 0, 0); //Set stroke to red ( R, G, B)
inByte = float(inString);
}
inByte = map(inByte, 0, 1023, 0, height);
yNew = inByte;
line(xPos-1, yPos-yOld, xPos, yPos-yNew);
yOld = yNew;
if (xPos >= width) {
xPos = 1;
yPos+=200;
if (yPos > height-200){
xPos = 1;
yPos=100;
background(0xff);
}
} else {
xPos++;
}
}
}
There are multiple ways to scale graphics.
A simple method to try is to simply scale() the rendering (drawing coordinate system).
Bare in mind currently the buffer is only cleared when the xPos reaches the right hand side of the screen.
The value from Arduino is mapped to Processing here:
inByte = map(inByte, 0, 1023, 0, height);
yNew = inByte;
you should try to map change height to a different value as you see fit.
This however will scale only the Y value. The x value is incremented here:
xPos++;
you might want to change this increment to a different value that works with the proportion you are trying maintain between x and y.
I am using lis3mdl magnetometer in my quadcopter project to compensate gyroscope drift. Unfortunatelly Im having problems probably with calibrating.
Ive achive max and min values (what is weird they are 14 bits instead of 16) and calculated biases like that :
biases[i] = (MAX_VALUES[i]+MIN_VALUES[i])/2;
(where i represent each of 3 axis).
Ive substracted biases from raw values x = (double)new_x-biases[0]; (etc), and then wanted to calculate heading like that :
heading = atan2(x,y);
heading += declinationAngle;
where declination angle is calculated.
Outcome are angles (conversion from radians heading*(180/M_PI)), and it does change when Iam rotating quad in yaw axi, BUT when I am rotating it in roll and pitch axi value change either. I want to achive stable yaw value which does not change when Iam rotating object in other axis. Maybe some type of fusing with accelerometer?
I am not sure when Ive made mistake in my calculations...
Whole class:
class Magnetometer {
int x=0,y=0,z=0;
LIS3MDL mag;
int running_min[3] = {32767, 32767, 32767}, running_max[3] = {-32768, -32768, -32768};
double mag_norm = 0.0;
double declinationAngle = 0.0;
double heading=0.0;
const int MAX_VALUES[3] = {3014,3439,10246};
const int MIN_VALUES[3] = {-4746, -4110, 492};
double biases[3] = {0.0};
double scales[3] = {0.0};
double avg_scale = 0.0;
ButterworthDLPF xyz_filter[3];
double DLPF_ON = true;
const float sample_rate = MAG_SAMPLE_RATE;
const float cutoff_freq = 4.0;
public:
Magnetometer() {}
void Init() {
declinationAngle = (6.0 + (8.0 / 60.0)) / (180.0 / M_PI);
for(int i=0; i<3; i++) {
biases[i] = (MAX_VALUES[i]+MIN_VALUES[i])/2;
scales[i] = (MAX_VALUES[i]-MIN_VALUES[i])/2;
}
avg_scale = (scales[0]+scales[1]+scales[2])/3.0;
for(int i=0; i<3; i++) scales[i] = avg_scale / scales[i];
Serial.println("Turning on magnetometer. . .");
if(!mag.init()) {
Serial.println("Failed to detect magnetometer!");
ESP.restart();
}
mag.enableDefault();
//Calibrate();
for(int i=0; i<3; i++) xyz_filter[i].Init(sample_rate, cutoff_freq);
Serial.println("9DOF readdy!");
}
void Calibrate() {
delay(100);
while(true) {
mag.read();
if(running_max[0]<mag.m.x) running_max[0] = mag.m.x;
if(running_max[1]<mag.m.y) running_max[1] = mag.m.y;
if(running_max[2]<mag.m.z) running_max[2] = mag.m.z;
if(running_min[0]>mag.m.x) running_min[0] = mag.m.x;
if(running_min[1]>mag.m.y) running_min[1] = mag.m.y;
if(running_min[2]>mag.m.z) running_min[2] = mag.m.z;
Serial.println((String)running_max[0]+" "+(String)running_max[1]+" "+(String)running_max[2]+ " "+(String)running_min[0] +" "+(String)running_min[1]+" "+(String)running_min[2]);
delay(20);
}
}
void Update(){
mag.read();
xyz_filter[0].Update(mag.m.x);
xyz_filter[1].Update(mag.m.y);
xyz_filter[2].Update(mag.m.z);
//Serial.println(xyz_filter[0].getData());
/*x = ((double)xyz_filter[0].getData()-biases[0])*scales[0];
y = ((double)xyz_filter[1].getData()-biases[1])*scales[1];
z = ((double)xyz_filter[2].getData()-biases[2])*scales[2];*/
x = ((double)mag.m.x-biases[0])*scales[0];
y = ((double)mag.m.y-biases[1])*scales[1];
z = ((double)mag.m.z-biases[2])*scales[2];
CalculateHeading();
}
void CalculateHeading() {
heading = atan2(y,x);
heading += declinationAngle;
//if(heading<0) heading += 2*PI;
//else if(heading>2*PI) heading -= 2*PI;
heading=MOD(heading*(180/M_PI));
}
double GetHeading() {return heading;}
void ShowRawValues(bool names=false) {
if(names) Serial.print("X: "+(String)x+" Y: "+ (String)y+ " Z: " + (String)z);
else Serial.print((String)x+" "+ (String)y+ " " + (String)z);
}
};
I have a CustomPieView which is made of several pie slices. I have to draw something in the middle of every pie section.
//Inside Activity's onCreate Method
public void onCreate(Bundle savedInstanceState){
int size = 400;
int bgColor = 0xffa11b1;
ViewPieChart piechart = (ViewPieChart) findViewById(R.id.pieChartView);
piechart.setCallBack(this);
piechart.setLayoutParams(new LayoutParams(size, size));
piechart.setGeometry(size, size, 2, 2, 2, 2, 2130837504);
piechart.setSkinparams(bgColor);
piechart.setData(piedata, maxCount);
piechart.invalidate();
}
//CustomPieView extends View
public void setGeometry(int width, int height, int gapleft, int gapright, int gaptop, int gapbottom, int overlayid) {
mWidth = width;
mHeight = height;
mGapleft = gapleft;
mGapright = gapright;
mGapBottm = gapbottom;
mGapTop = gaptop;
}
protected void onDraw(Canvas canvas){
canvas.drawColor(Color.DKGRAY);
mBagpaints.setAntiAlias(true);
mBagpaints.setStyle(Paint.Style.FILL);
mBagpaints.setColor(0x88FF0000);
mBagpaints.setStrokeWidth(0.0f);
mLinePaints.setAntiAlias(true);
mLinePaints.setColor(Color.WHITE);
mLinePaints.setStrokeWidth(3.0f);
mLinePaints.setStyle(Paint.Style.STROKE);
sLinePaint.setAntiAlias(true);
sLinePaint.setColor(Color.BLACK);
sLinePaint.setStrokeWidth(3.0f);
sLinePaint.setStyle(Paint.Style.STROKE);
RectF mOvals = new RectF(mGapleft, mGapTop, mWidth - mGapright, mHeight
- mGapBottm);
mStart = START_INC;
PieDetailsItem item;
for (int i = 0; i < mdataArray.size(); i++) {
item = (PieDetailsItem) mdataArray.get(i);
mBagpaints.setColor(item.color);
mSweep = (float) 360* ((float) item.count / (float) mMaxConnection);
canvas.drawArc(mOvals, mStart, mSweep, true, mBagpaints);
canvas.drawArc(mOvals, mStart, mSweep, true, mLinePaints);
// The function below is setting the global vars
cSegX, cSegY to the center of the segment. Not Working!!
calculateMidPointOfPieSegment(mSweep);
canvas.drawPoint(cSegX, cSegY, sLinePaint);
mStart = mStart + mSweep;
}
mState = IS_DRAW;
callBack.onDrawFinished(null);
}
private float calculateRadius(){
float width = mWidth/2;
float height = mHeight/2;
if(width < height){
return width;
}else{
return height;
}
}
private void calculateMidPointOfPieSegment(float sweepAngle){
cSegX = (float)((calculateRadius()/2)*Math.cos(Math.toRadians(sweepAngle/2))+(mWidth/2));
cSegY = (float)((calculateRadius()/2)*Math.sin(Math.toRadians(sweepAngle/2))+(mHeight/2));
}
Just see the dots in the image below, it has to be in the center of every arc.
Screenshot
Ref.
Complete Source
Let me know if this clears it up. This is the basic logic you want to implement.
//rimPoint = (rX, rY)
//centerPoint = (cX,cY)
//theta is the angle of the the midpoint measured anticlockwise from the x axis,
//or the average of the two angles making up the slice(measured anticlockwise from
//the x axis)
private void calculateMidPointOfPieSegment(cX,cY, theta)
{
float rX = cX + calculateRadius()*(cos(theta))
float rY = cY + calculateRadius()*(sin(theta))
cSegX = (rX+cX)/2;
cCegY = (rY+cY)/2;
}
If theta isn't in radians, sub it out for theta*Math.PI/180