Callback function not executed arduino code
Hello all I have a simple Arduino code to control a servo. I used the following code for my teensy board. I just find I cannot publish the command from ros and send it to the teensy board. The communication between the teensy board and the servo is correct as I can directly send commands to the servo by seting some constant commands in the Arduino code.
Then I used a dummy topic to test whether the callback function to subscribe the command from ros is called or not (shown in the following code). The value of the dummy topic "truck/manual/throttle" is always zero. Clearly, spinonce() function doesn't call the callback function to get the command I sent otherwise the value should be 10. The following is the code. Can anyone help with this
#include <ros.h>
#include <std_msgs/Float32.h>
#include <sensor_msgs/Imu.h>
#include <std_srvs/SetBool.h>
#include <std_srvs/Empty.h>
#include <Encoder.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Servo.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include "TeensyThreads.h"
#define USE_TEENSY_HW_SERIAL
/****PIN CONNECTION MACROS****/
#define _SERVO 1
#define _ESC 3
/*******Reciever PWM range macros*********/
#define _REC_ESC_MIN 1065
#define _REC_ESC_MAX 2006
#define _ESC_NEUTRAL 1514
#define _SERVO_NEUTRAL 1610
/************STRUCT DEFINTIONS************/
std_msgs::Float32 manualThrottle;
std_msgs::Float32 cmdThrottle;
/*********PROTOTYPES**************/
void cmdThrottleCb(const std_msgs::Float32 &msg);
/************VARIABLES********************/
Servo esc;
Servo steer;
ros::NodeHandle nh;
ros::Publisher pub_manual_throttle_command("truck/manual/throttle", &manualThrottle);
ros::Subscriber<std_msgs::Float32> sub_cmdThrottle("truck/cmd/throttle", &cmdThrottleCb);
/************************************************/
int Flag = 0;
int Cmd_esc = 0;
void setup(){
esc.attach(_ESC);
steer.attach(_SERVO);
steer.writeMicroseconds(_SERVO_NEUTRAL); //send neutral commands for safety
esc.writeMicroseconds(_ESC_NEUTRAL);
nh.initNode();
nh.advertise(pub_manual_throttle_command);
nh.subscribe(sub_cmdThrottle); //control command
delay(20);
}
void loop()
{
manualThrottle.data=Flag; // publish this data to test callback function
pub_manual_throttle_command.publish(&manualThrottle);
esc.writeMicroseconds(Cmd_esc);
nh.spinOnce();
delay(10);
}
void cmdThrottleCb(const std_msgs::Float32 &msg){
Cmd_esc=msg.data;
Flag=10;// test if this function is called
}
Asked by FengHan on 2021-12-01 21:55:52 UTC
Answers
You can not assume that a single spinOnce() will handle all the background activity that ros has pending.
I have never seen an arduino run "full size" ros (hint: that requires a network stack.) Instead, what people do is split the implementation into two pieces using
rosserial
. The arduino side runs a cut-down subset of ros functions, optimized for the limited abilities of this cpu, and the arduino app you end up with is NOT a real ros node, because it requires the rosserial-master to do any work. You have to compile this arduino application using a special procedure.
See:
http://wiki.ros.org/rosserial_embeddedlinux/Tutorials/Example%20Subscriber
Using rosserial
can be a little confusing, so it's not a good place for someone new to ros to start with. The experience will go much easier if you learn the ros APIs on a desktop pc first.
Asked by Mike Scheutzow on 2021-12-02 07:31:13 UTC
Comments
Thanks for your answer. My system contains a Linux computer with ros, a teensy 4.0 microcontroller, and a servo. The command for the servo is sent from ros to teensy and teensy will do the low-level control.
The code I provided above in my question is loaded into teensy 4.0. But I just find that the command sent from ros cannot be received by the subscriber. Then I used the above code to test and find the callback function in teensy is not executed.
We used a similar code before to control three step-motors (Linux ros+teensy+motors). It worked. Also you can see a similar code in GitHub: https://gist.github.com/jones2126/13865f3d3e09f9fbec329a250bd0ef80 and https://github.com/nr-parikh/rosserial_tutorials/blob/master/microcontroller_code/servo_with_pub.ino
I test the second code and it still doesn't work (still defined a dummy topic to test callback function).
Asked by FengHan on 2021-12-02 11:09:17 UTC
Comments
Just two quick observations. You send a float but Cmd_esc is of type int. I have seen issues where arduino basic types do not match "ros"/PC types(there were different "double" types I think), causing trouble/errors. Iam not sure how well implicit casting works here. Way back I also seen that declaring a function below void loop() didnt work for some code. I dont get why there is a prototype of cmdThrottleCb at the top and the implementation at the bottom. Get rid of the prototype?
Asked by Dragonslayer on 2021-12-02 07:06:08 UTC
Thanks. I revised my code, just change "Flag" to float type. The "cmdThrottleCb" function is used to create the publisher:
But this still doesn't work, the teensy 4.0 microcontroller cannot receive the command and the servo doesn't rotate correspondingly.
Asked by FengHan on 2021-12-02 10:59:36 UTC
I would still try to implement the cmdthrottlecb() up where the prototype is. All your linked code does it this way as well. I would also build a led on/off trigger into the callback. I checked some of my old code and this should work. What does your rosserial launchfile look like on the PC side? Also regarding "#define USE_TEENSY_HW_SERIAL", does your libraries etc comply with this and is 4.0 adapted? How do you connect to the PC? Did any other rosserial scetch work on this teensy 4.0 for you?
Asked by Dragonslayer on 2021-12-02 14:20:45 UTC
Thanks. I tried what you said. It still doesn't work. I tried to publish command from the terminal for the topic truck/cmd/throttle as
The terminal then displays the following info
If I didn't Ctr+c, the info is always there.
Asked by FengHan on 2021-12-02 21:35:48 UTC
You could "rostopic info" and "rostopic hz" the topics to at least see whats going on the PC side. But whats with my questions about teensy serial setup? I had issues with it way back. Did you use the LED to confirm that anything ever reaches the teensy via serial? How do you connect USB? Did this setup ever work with rosserial?
Asked by Dragonslayer on 2021-12-03 07:08:45 UTC