How to publish Int16MultiArray from rosserial arduino - c++

I am trying to publish an Int16MultiArray for the ros package mecanum_drive: https://github.com/dudasdavid/mecanum_drive
My issue is that I cant seem to publish the array from my arduino. (I am using Teensy 4.1)
#include <std_msgs/Int16MultiArray.h>
ros::NodeHandle nh;
std_msgs::Int16MultiArray wheel_ticks;
ros::Publisher wheel_ticks_pub("wheel_ticks", &wheel_ticks);
void setup() {
nh.getHardware()->setBaud(115200); //was 115200
nh.initNode(); // init ROS
nh.advertise(wheel_ticks_pub);
}
void loop() {
// put your main code here, to run repeatedly:
//I have tried the code below which uploads to the arduino, but rostopic then says that it dosnt contain any data
/*
short value[4] = {0,100,0,0};
wheel_ticks.data = value;
*/
//I also tryed the code below which uploads, but then the teensy looses its serial port (arduino port says"[no_device] Serial(Teensy4.1)":
/*
wheel_ticks.data[0] = 10;
wheel_ticks.data[1] = 5;
*/
//below gives this error: cannot convert '<brace-enclosed initializer list>' to 'std_msgs::Int16MultiArray::_data_type* {aka short int*}' in assignment
/*
wheel_ticks.data = {0,0,0,1};
*/
wheel_ticks_pub.publish(&wheel_ticks);
nh.spinOnce();
}
Everything I have tried has either not uploaded, uploaded but with serial being messed up, or with it uploading and rostopic echo saying it is empty.
Thanks for looking at this, I hope you can help!

A very specific limitation of rosserial is arrays have an extra field specifically for data length. This is needed since the data field is implemented as a pointer, thus having no real good way to get data length. The message type actually looks like this
class Int16MultiArray{
Header header;
int data_length;
int16_t * data;
};
So, all you have to do is set the data field before sending a message
#include <std_msgs/Int16MultiArray.h>
ros::NodeHandle nh;
std_msgs::Int16MultiArray wheel_ticks;
ros::Publisher wheel_ticks_pub("wheel_ticks", &wheel_ticks);
void setup() {
nh.getHardware()->setBaud(115200); //was 115200
nh.initNode(); // init ROS
nh.advertise(wheel_ticks_pub);
}
void loop() {
short value[4] = {0,100,0,0};
wheel_ticks.data = value;
wheel_ticks.data_length = 4;
wheel_ticks_pub.publish(&wheel_ticks);
nh.spinOnce();
}

Related

BLE using ESP 32

I am trying to program a BLE client using an ESP32. I have used the attached code (which is the example code from the example section). My problem right now is, how do I get it to show the MAC address of the scanned device only, and how do I change this MAC address into a JSON format for a LoRa chip to transmit? Thank you so much for your time to read this post.
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
Ported to Arduino ESP32 by Evandro Copercini
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
int scanTime = 5; //In seconds
BLEScan* pBLEScan;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};
void setup() {
Serial.begin(115200);
Serial.println("Scanning...");
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(100);
pBLEScan->setWindow(99); // less or equal setInterval value
}
void loop() {
// put your main code here, to run repeatedly:
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Devices found: ");
Serial.println(foundDevices.getCount());
Serial.println("Scan done!");
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
delay(2000);
}
The result of your scan is foundDevices, which contains a list of all found devices. We can iterate through it to access the devices. The List contains BLEAdvertisedDevices which have a method called getAddress(). The address can be converted to a string using toString(). You can print the string or put it into your json container.
Your loop-code could look like this:
void loop() {
// put your main code here, to run repeatedly:
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Devices found: ");
for (int i = 0; i < foundDevices.getCount(); ++i)
{
std::string address = foundDevices.getDevice(i).getAddress().toString();
int rssi = foundDevices.getDevice(i).getRSSI();
Serial.print(address.c_str());
Serial.print(rssi);
// TODO: Insert into JSON
}
Serial.println(foundDevices.getCount());
Serial.println("Scan done!");
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
delay(2000);
}

ESP32 > using esp_console + argtable3 in a C++ project

I'am developping a C++ project on an ESP32.
I'd like to use esp_console + argtable3 (C libraries) in it.
I'm trying to use argtable3 in my members functions.
To do so, I'm creating callback functions to my members functions with a global pointer.
I'm sure my class is going to be instanced only once so I assume it's ok to create callback functions.
The problem is that argtable isn't giving me back the parameters entered by the user.
It checks for them successfully (number of args and their type) but the data it gives me back is random.
I've tested my code outside of members functions and it works well. But I want to use it inside members functions to access other parts of my object.
Here is my code :
// Pointer for my callback functions
MyClass * _callback;
struct arg_int *argInt;
struct arg_end *endPage;
// My callback function (GLOBAL)
int _setInt(int argc, char *argv[])
{
return _callback->setInt(argc, argv);
}
// Tab of struct for argtable lib (GLOBAL)
void *setInt_argtable[] =
{
argInt = arg_int1(NULL, NULL, "<0-12>", "Integer argument"),
endInt = arg_end(10)
};
// Function I'm calling back
int MyClass::setInt(int argc, char *argv[])
{
int nerrors = arg_parse(argc,argv,setInt_argtable);
if (nerrors > 0)
{
arg_print_errors(stdout, endPage, "myprog");
return 0;
}
printf("argc = %d\n", argc); // argc gives the correct number of args
printf("argv[0] = %s\n", argv[0]); // argv[0] gives the correct command name
printf("argv[1] = %s\n", argv[1]); // argv[1] gives the correct value
printf("argInt->ival[0] = %d\n", argInt->ival[0]); // argInt->ival[0] gives random value
return 0;
}
void MyClass::main(void)
{
// Callback pointer initialisation
_callback = this;
/* Initializing the console */
esp_console_config_t console_config
{
256,
8,
atoi(LOG_COLOR_CYAN),
0
};
ESP_ERROR_CHECK( esp_console_init(&console_config) );
/* Configure linenoise line completion library */
/* Enable multiline editing. If not set, long commands will scroll within
* single line.
*/
linenoiseSetMultiLine(1);
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(100);
esp_console_register_help_command();
//
// Feeding my console with argtable parameters
//
esp_console_cmd_t consoleCmd;
consoleCmd.command = "setInt";
consoleCmd.func = &_setInt;
consoleCmd.help = "Trying to set a integer argument";
consoleCmd.argtable = setInt_argtable;
esp_console_cmd_register(&consoleCmd);
/* Main loop */
while(true)
{
// Getting command from user
}
}
Is my approach of using callback member function good ?
Any idea of what is my problem and how I could solve it ?
Thanks in advance for your answers.
After being copying/pasting very simple sample codes found on internet, I finally found what was the problem :
I was including <argtable3/argtable3.h> after "myclass.h"
It took me almost 2 days for a dumb error...
But if somebody has an explanation about why the inclusion order was allowing me to compile the program but making a "corrupted" binary, feel free to answer !

Adafruit Fona establishes connection with echo server, but doesn't send over any data

Using mbed OS and stm32 nucleo board with Adafruit Fona 3g, I am trying to send data to a server via 3g connection. I am using the .cpp file and .h file posted here: https://os.mbed.com/users/Nels885/code/Adafruit_FONA_3G/file/b18cfba4283a/
The code seems to get stuck on getTCPtimeout. I am having trouble figuring out why this is the case.
I have tried commenting out the getTCPtimeout function to see the results and the code runs through completely, but never establishes a connection with the server.
#include "mbed.h"
#include "Adafruit_FONA.h"
#define FONA_RST D4
#define FONA_TX D1
#define FONA_RX D0
#define FONA_RI D7 //not used
char replybuffer[255];
Adafruit_FONA_3G fona(FONA_TX, FONA_RX, FONA_RST, FONA_RI);
Serial pc(USBTX, USBRX);
int main()
{
fona.TCPinitialize();
pc.printf ("initialize \n");
char *Timeout = "10000000";
fona.getTCPtimeout(Timeout);
pc.printf ("timeout \n");
char * Server = "47.218.188.133";
uint16_t Port = 23;
fona.TCPconnect(Server,Port);
pc.printf ("connect \n");
char * Packet = "Pick Up %";
fona.TCPsend(Packet);
pc.printf ("send \n");
fona.TCPclose();
pc.printf ("close \n");
}
Edit: I was running the code and noticed that after fixing the above issue, the code would get stuck TCPSend function, specifically right before
packet[0] = 0;
which is shown down here:
bool Adafruit_FONA_3G::TCPsend(char *packet)
{
if (strlen(packet) > 0) {
mySerial.printf("%s", packet);
//mySerial.printf("%s\r\n", packet);
readline();
packet[0] = 0;
return true;
} else return false;
}
When commenting out the line, the code would run all the way through. I am still in the process of testing to see if the code still functions as intended, but my question is what exactly is the purpose of packet[0] = 0;?
Adafruit_FONA_3G::getTCPtimeout() assumes that you pass it a writable buffer of size > 20. You're passing a read-only buffer of smaller size. So, replace
char *Timeout = "10000000";
with
char Timeout[21];

Boost.Asio local TCP Sockets in C++ - cannot write successfully more than once?

I'm trying to make an audio plugin which can connect to a local Java server and send it data through a socket (TCP). As I heard many nice things about it, I'm using Boost's ASIO library to do the work.
I'm having quite a strange bug in my code : my AudioUnit C++ client (which I use from inside a DAW, I'm testing with Ableton Live and Logic Pro) can connect to my Java server alright, but when I do a write operation, it seems my write is correctly executed only once (as in, I can monitor any incoming message on my Java server, and only the first message is seen)
I'm using the following code :
-- Inside the header :
boost::asio::io_service io_service;
boost::asio::ip::tcp::socket mySocket(io_service);
boost::asio::ip::tcp::endpoint myEndpoint(boost::asio::ip::address::from_string("127.0.0.1"), 9001);
boost::system::error_code ignored_error;
-- Inside my plugin's constructor
mySocket.connect(myEndpoint);
-- And when I try to send :
boost::asio::write(mySocket, boost::asio::buffer(datastring), ignored_error);
(you will notice that I do not close my socket, because I'd like it to live forever)
I don't think the problem comes from my Java server (though I could be wrong !), because I found out a way to make my C++ plugin "work correctly" and send all the messages I want :
If I don't open my socket upon initializing my plugin, but directly when I try sending the message, every message is received by my remote server. Ie, every time I call sendMessage(), I do the following :
try {
// Connect to the Java application
mySocket.connect(myEndpoint);
// Write the data
boost::asio::write(mySocket, boost::asio::buffer(datastring), ignored_error);
// Disconnect
mySocket.close();
} catch (const std::exception & e) {std::cout << "Couldn't initialize socket\n";}
Still, I'm not too happy with this code : I have to send about 1000 messages per second - while that might not be humongous, but I don't think opening the socket and connecting to the end point everytime is efficient (it's a blocking operation too)
Any input which could lead me in the right direction would be greatly appreciated !
For more information, here's my code in a slightly more complete version (with the useless stuff trimmed to keep it short)
#include <cstdlib>
#include <fstream>
#include "PluginProcessor.h"
#include "PluginEditor.h"
#include "SignalMessages.pb.h"
using boost::asio::local::stream_protocol;
//==============================================================================
// Default parameter values
const int defaultAveragingBufferSize = 256;
const int defaultMode = 0;
const float defaultInputSensitivity = 1.0;
const int defaultChannel = 1;
const int defaultMonoStereo = 1; //Mono processing
//==============================================================================
// Variables used by the audio algorithm
int nbBufValProcessed = 0;
float signalSum = 0;
// Used for beat detection
float signalAverageEnergy = 0;
float signalInstantEnergy = 0;
const int thresholdFactor = 5;
const int averageEnergyBufferSize = 11025; //0.25 seconds
//==============================================================================
// Socket used to forward data to the Processing application, and the variables associated with it
boost::asio::io_service io_service;
boost::asio::ip::tcp::socket mySocket(io_service);
boost::asio::ip::tcp::endpoint myEndpoint(boost::asio::ip::address::from_string("127.0.0.1"), 9001);
boost::system::error_code ignored_error;
//==============================================================================
SignalProcessorAudioProcessor::SignalProcessorAudioProcessor()
{
averagingBufferSize = defaultAveragingBufferSize;
inputSensitivity = defaultInputSensitivity;
mode = defaultMode;
monoStereo = defaultMonoStereo;
channel = defaultChannel;
// Connect to the remote server
// Note for stack overflow : this is where I'd like connect to my server !
mySocket.connect(myEndpoint);
}
SignalProcessorAudioProcessor::~SignalProcessorAudioProcessor()
{
}
//==============================================================================
void SignalProcessorAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
// In case we have more outputs than inputs, clear any output
// channels that doesn't contain input data
for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)
buffer.clear (i, 0, buffer.getNumSamples());
//////////////////////////////////////////////////////////////////
// This is the most important part of my code, audio processing takes place here !
// Note for stack overflow : this shouldn't be very interesting, as it is not related to my current problem
for (int channel = 0; channel < std::getNumInputChannels(); ++channel)
{
const float* channelData = buffer.getReadPointer (channel);
for (int i=0; i<buffer.getNumSamples(); i++) {
signalSum += std::abs(channelData[i]);
signalAverageEnergy = ((signalAverageEnergy * (averageEnergyBufferSize-1)) + std::abs(channelData[i])) / averageEnergyBufferSize;
}
}
nbBufValProcessed += buffer.getNumSamples();
if (nbBufValProcessed >= averagingBufferSize) {
signalInstantEnergy = signalSum / (averagingBufferSize * monoStereo);
// If the instant signal energy is thresholdFactor times greater than the average energy, consider that a beat is detected
if (signalInstantEnergy > signalAverageEnergy*thresholdFactor) {
//Set the new signal Average Energy to the value of the instant energy, to avoid having bursts of false beat detections
signalAverageEnergy = signalInstantEnergy;
//Create an impulse signal - note for stack overflow : these are Google Protocol buffer messages, serialization is faster this way
Impulse impulse;
impulse.set_signalid(channel);
std::string datastringImpulse;
impulse.SerializeToString(&datastringImpulse);
sendMessage(datastringImpulse);
}
nbBufValProcessed = 0;
signalSum = 0;
}
}
//==============================================================================
void SignalProcessorAudioProcessor::sendMessage(std::string datastring) {
try {
// Write the data
boost::asio::write(mySocket, boost::asio::buffer(datastring), ignored_error);
} catch (const std::exception & e) {
std::cout << "Caught an error while trying to initialize the socket - the Java server might not be ready\n";
std::cerr << e.what();
}
}
//==============================================================================
// This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new SignalProcessorAudioProcessor();
}

audio synthesis with MoMu STK

Has anybody successfully implemented an Instrument using MoMu STK on iOS? I am bit stacked with initialization of a stream for Instrument.
I am using tutorial code and looks like something missing
RtAudio dac;
// Figure out how many bytes in an StkFloat and setup the RtAudio stream.
RtAudio::StreamParameters parameters;
parameters.deviceId = dac.getDefaultOutputDevice();
parameters.nChannels = 1;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
unsigned int bufferFrames = RT_BUFFER_SIZE;
dac.openStream( & parameters, NULL, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&data );
Error description says that output parameters for output device are invalid, but when I skip to assign device id then it's not working as well.
Any idea would be great.
RtAudio is only for desktop apps and there is no need to open stream when implementing on iOS.
example:
Header file:
#import "Simple.h"
// make struct to hold
struct TickData {
Simple *synth;
};
// Make instance of the struct in #interface=
TickData data;
Implementation file:
// init the synth:
data.synth = new Simple();
data.synth->keyOff();
// to trigger note on/off:
data.synth->noteOn(frequency, velocity);
data.synth->noteOff(velocity);
// audio callback method:
for (int i=0; i < FRAMESIZE; i++) {
buffer[i] = data.synth -> tick();
}
Yep, I have a couple of apps in the store with STK classes running on them. Bear in mind that the setup required to run STK on iOS is different from the one required to run it on your desktop.
Here's a tutorial on how to use STK classes inside an iOS app:
https://arielelkin.github.io/articles/mandolin