rosserial on MONSTER M4SK
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

rosserial on MONSTER M4SK

by bebement on Mon Oct 28, 2019 5:59 am

I am trying to get rosserial to work on my Monster M4SK. The goal is to be able to control the eye position and behavior using ROS messages with the M4SK connected [only] via its USB port. The current problem I am facing seems to be with the Serial architecture of the M4SK arduino setup.

... Arduino/libraries/ros_lib/ArduinoHardware.h:75:19: error: 'Serial1' was not declared in this scope
iostream = &Serial1;

I can't find anything related to Serial1 other than the following #defines in the .../.arduino15/packages/adafruit/hardware/samd/1.5.4/variants/monster_m4sk/variant.h file:
Code: Select all | TOGGLE FULL SIZE
// Serial1
#define PIN_SERIAL1_RX       (0ul)      // sercom3
#define PIN_SERIAL1_TX       (1ul)      // sercom3
#define PAD_SERIAL1_RX       (SERCOM_RX_PAD_1)
#define PAD_SERIAL1_TX       (UART_TX_PAD_0)

I have found the following code related to Serial1 in the variant.cpp file for the hallowing_m4, which is also based on a SAMD51 processor, but I do not understand the serial architecture enough to know whether this, or some adaptation might work on the M4SK or not. I am concerned about its compatibility with TinyUSB.
Code: Select all | TOGGLE FULL SIZE

void SERCOM4_0_Handler()
void SERCOM4_1_Handler()
void SERCOM4_2_Handler()
void SERCOM4_3_Handler()

I am not sure whether it is even appropriate for the rosserial code to be trying to use Serial1 instead of Serial in the first place.
If anyone could offer any suggestions as to how I might proceed, or whether trying to run rosserial on this platform is crazy, it would be greatly appreciated.

Posts: 4
Joined: Mon Oct 28, 2019 5:21 am

Re: rosserial on MONSTER M4SK

by bebement on Wed Oct 30, 2019 11:58 am

Made some progress on this.
Hacked the Arduino ros_lib/ArduinoHardware.h so that it accomplishes the following:
Code: Select all | TOGGLE FULL SIZE
  #include "Adafruit_USBD_CDC.h"
  #define SERIAL_CLASS Adafruit_USBD_CDC
 iostream = &Serial;

I have not yet figured out a clean way to integrate the above changes into ArduinoHardware.h. It is a mess of #if, #elif, etc.
After doing this, I have been able to write and test some simple code to control the direction of the eyes using a ROS topic.
I may publish more here after I develop it further.

Posts: 4
Joined: Mon Oct 28, 2019 5:21 am

Re: rosserial on MONSTER M4SK

by bebement on Wed Nov 06, 2019 11:53 am

Here is the code I have been experimenting with. I was able to configure/trick the ArduinoHardware.h used by ros.h into working with the monster m4sk without modifying the file. The code receives ros eye_target messages and aims the eyes accordingly.
Link to code on github:
https://github.com/vatbrain/Adafruit_Le ... serial.cpp

Code: Select all | TOGGLE FULL SIZE
#if 0 // Change to 1 to enable this code (must enable ONE user*.cpp only!)

// This file provides a crude way to "drop in" user code to the eyes,
// allowing concurrent operations without having to maintain a bunch of
// special derivatives of the eye code (which is still undergoing a lot
// of development). Just replace the source code contents of THIS TAB ONLY,
// compile and upload to board. Shouldn't need to modify other eye code.

// User globals can go here, recommend declaring as static, e.g.:
// static int foo = 42;

#include "globals.h"

// In the ardunio .../libraries/ros_lib/ArduinoHardware.h file,
// which is included by ros.h, there is a bunch of conditional
// compilation based on Arduino type that ultimately results in
// SERIAL_CLASS being #defined to the class of the appropriate
// Serial object, and iostream being assigned to a pointer to
// the appropriate Serial object in the constructor for class
// ArduinoHardware.
// In the case of the Monster M4SK, "Serial" is the appropriate
// Serial object.
// Serial is declared as type Adafruit_USBD_CDC in file
// Adafruit_USB_CDC.cpp.
// Class Adafruit_USBD_CDC is defined in file Adafruit_USBD_CDC.h
// Both of these files reside in:
// ~/.arduino15/packages/adafruit/hardware/samd/1.5.4/cores/arduino/Adafruit_TinyUSB_Core/
// So the file ArduinoHardware.h (included by ros.h) either needs to be modified
// or tricked/configured into:
//   #defining SERIAL_CLASS as Adafruit_USBD_CDC
//   and assiging iostream to &Serial in the ArduinoHardware constructor.
// Currently this can be accomplished by including the following code
// before the #include of ros.h:
//   #define USE_USBCON
//   #include <Adafruit_USBD_CDC.h>
//   #define Serial_ Adafruit_USBD_CDC
// to trick/configure ArduinoHardware.h properly.
// There is no guarantee this will continue to work in the future.

#define USE_USBCON
#include <Adafruit_USBD_CDC.h>
#define Serial_ Adafruit_USBD_CDC
#include <ros.h>
#include <geometry_msgs/Point.h>

ros::NodeHandle nh;

void eye_cb(const geometry_msgs::Point& cmd_msg){
   eyeTargetX = cmd_msg.x;
   eyeTargetY = cmd_msg.y;

ros::Subscriber<geometry_msgs::Point> sub("eye_target", eye_cb);

// Called once near the end of the setup() function. If your code requires
// a lot of time to initialize, make periodic calls to yield() to keep the
// USB mass storage filesystem alive.
void user_setup(void) {
   // showSplashScreen = false;
   moveEyesRandomly = true;

// Called periodically during eye animation. This is invoked in the
// interval before starting drawing on the last eye (left eye on MONSTER
// M4SK, sole eye on HalloWing M0) so it won't exacerbate visible tearing
// in eye rendering. This is also SPI "quiet time" on the MONSTER M4SK so
// it's OK to do I2C or other communication across the bridge.
// This function BLOCKS, it does NOT multitask with the eye animation code,
// and performance here will have a direct impact on overall refresh rates,
// so keep it simple. Avoid loops (e.g. if animating something like a servo
// or NeoPixels in response to some trigger) and instead rely on state
// machines or similar. Additionally, calls to this function are NOT time-
// constant -- eye rendering time can vary frame to frame, so animation or
// other over-time operations won't look very good using simple +/-
// increments, it's better to use millis() or micros() and work
// algebraically with elapsed times instead.
void user_loop(void) {
   if (nh.connected())
      moveEyesRandomly = false;
   else {
      moveEyesRandomly = true;
  Suppose we have a global bool "animating" (meaning something is in
  motion) and global uint32_t's "startTime" (the initial time at which
  something triggered movement) and "transitionTime" (the total time
  over which movement should occur, expressed in microseconds).
  Maybe it's servos, maybe NeoPixels, or something different altogether.
  This function might resemble something like (pseudocode):

  if(!animating) {
    Not in motion, check sensor for trigger...
    if(read some sensor) {
      Motion is triggered! Record startTime, set transition
      to 1.5 seconds and set animating flag:
      startTime      = micros();
      transitionTime = 1500000;
      animating      = true;
      No motion actually takes place yet, that will begin on
      the next pass through this function.
  } else {
    Currently in motion, ignore trigger and move things instead...
    uint32_t elapsed = millis() - startTime;
    if(elapsed < transitionTime) {
      Part way through motion...how far along?
      float ratio = (float)elapsed / (float)transitionTime;
      Do something here based on ratio, 0.0 = start, 1.0 = end
    } else {
      End of motion reached.
      Take whatever steps here to move into final position (1.0),
      and then clear the "animating" flag:
      animating = false;

#endif // 0

Posts: 4
Joined: Mon Oct 28, 2019 5:21 am

Re: rosserial on MONSTER M4SK

by pbuelow on Thu Sep 16, 2021 11:53 am

Hey, just found this. I'm trying to do something similar. This is over USB, correct? What is the format of the serial messages? Any other pointers you have, and did you ever get it working correctly?

Posts: 75
Joined: Sat Oct 04, 2014 2:43 pm

Re: rosserial on MONSTER M4SK

by bebement on Fri Sep 17, 2021 7:37 am

Yes, this was done over USB. The format of the serial messages is dictated by ROS and should be documented somewhere in the ROS documentation. My experiments stayed within ROS, so the low level details of the serial message/frame format were not important to me. I did have it working correctly at the time of the forum posts, but it has been close to two years since I have experimented with it. Some of the dependencies may have changed since then.

Posts: 4
Joined: Mon Oct 28, 2019 5:21 am

Please be positive and constructive with your questions and comments.