If I create a very basic sketch with both WIFI and UWB configured, I am able to …transmit the udp packets without any problems.
Here is the test code:
```c++
#include <WiFiC3.h>
#include <WiFiUdp.h>
#include <PortentaUWBShield.h>
#define WIFI_SSID "SSID"
#define WIFI_PASS "PASSWORD"
#define UDP_HOST "192.168.1.100"
#define UDP_PORT 5000
WiFiUDP udp;
void setup() {
Serial.begin(115200);
delay(3000);
// Now start UWB
Serial.println("Starting UWB...");
UWB.begin();
while (UWB.state() != 0)
delay(10);
Serial.println("UWB ready.");
delay(2000);
// WiFi first
Serial.println("Connecting to WiFi...");
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("\nConnected! IP: ");
Serial.println(WiFi.localIP());
udp.begin(UDP_PORT);
// Test UDP before UWB
Serial.println("Testing UDP before UWB...");
udp.beginPacket(UDP_HOST, UDP_PORT);
udp.print("{\"stage\":\"pre-uwb\"}");
udp.endPacket();
delay(1000);
// Test UDP after UWB
Serial.println("Testing UDP after UWB...");
udp.beginPacket(UDP_HOST, UDP_PORT);
udp.print("{\"stage\":\"post-uwb\"}");
udp.endPacket();
delay(1000);
}
void loop() {
udp.beginPacket(UDP_HOST, UDP_PORT);
udp.print("{\"ping\":true}");
udp.endPacket();
delay(500);
}
```
However, the moment I start adding code for configuring sessions, WIFI says its connected but udp transmission stops completely.
Here is my actual anchor code:
```c++
/*
* UWB_MulticastAnchor.ino
*
* Platform : Arduino Portenta C33 + UWB Shield (Truesense DCU150)
* Library : PortentaUWBShield
* https://github.com/Truesense-it/PortentaUWBShield
*
* Role : UWB Ranging Controller (one-to-many) — acts as a fixed
* anchor that ranges to up to 12 Stella tags split across
* two multicast sessions (6 tags each).
*
* Transport: Each ranging result is sent as a JSON UDP datagram to
* the ROS2 host, matching the format expected by the
* UDPRangeReader in the uwb_localization package:
* {"anchor_id":0,"tag_id":3,"distance_cm":142,"timestamp_ms":48230}
*
* ── CONFIGURATION ──────────────────────────────────────────────────
* Change ONLY the defines in the "CHANGE THESE" section below.
* - ANCHOR_ID : unique per anchor (0–3)
* - WIFI_SSID : your WiFi network name
* - WIFI_PASS : your WiFi password
* - UDP_HOST : IP of the machine running the ROS2 node
* - UDP_PORT : port the UDPRangeReader listens on (default 5000)
*
* ── ADDRESSING SCHEME ──────────────────────────────────────────────
* Anchor MAC : { 0xA0, ANCHOR_ID }
* Tag MAC : { 0x00, TAG_ID } TAG_ID ∈ [1..12]
* Session ID : ANCHOR_ID * 100 + GROUP_INDEX + 1
* Group 0 (tags 1– 6) → session ANCHOR_ID*100 + 1
* Group 1 (tags 7–12) → session ANCHOR_ID*100 + 2
*
* ── SESSION BUDGET ─────────────────────────────────────────────────
* 2 sessions per anchor (limit: 5 on SR150) ✔
* 4 sessions per tag (limit: 5 on DCU040) ✔
* ───────────────────────────────────────────────────────────────────
*/
#include <PortentaUWBShield.h>
#include <WiFiC3.h>
#include <WiFiUdp.h>
// ===================== CHANGE THESE ===============================
#define ANCHOR_ID 3 // 0, 1, 2, or 3
//#define WIFI_SSID "ghibli-IoT" // WiFi SSID
//#define WIFI_PASS "s00tSpr1t3s@0141" // WiFi password
#define WIFI_SSID "ghibli" // WiFi SSID
#define WIFI_PASS "myNeighbortotoro@1123" // WiFi password
#define UDP_HOST "192.168.1.100" // ROS2 host IP
#define UDP_PORT 5000 // UDPRangeReader port
// ==================================================================
// Uncomment to echo JSON lines to Serial for USB debugging
// #define SERIAL_DEBUG
#define NUM_TAGS 12
#define TAGS_PER_GROUP 6 // max 8 controlees per multicast session
#define NUM_GROUPS ((NUM_TAGS + TAGS_PER_GROUP - 1) / TAGS_PER_GROUP)
#define WIFI_RETRY_MS 5000 // ms between reconnection attempts
#define WIFI_TIMEOUT_MS 10000 // ms to wait during initial connect
// ── File-static state ────────────────────────────────────────────
// Heap-allocated session objects — survive beyond setup()
static UWBRangingOneToMany* sessions[NUM_GROUPS] = { nullptr };
// WiFi / UDP
static WiFiUDP udp;
static volatile bool wifiConnected = false;
static unsigned long lastWifiAttempt = 0;
// ── WiFi management ──────────────────────────────────────────────
bool connectWiFi() {
Serial.print("WiFi: connecting to ");
Serial.print(WIFI_SSID);
Serial.print(" ...");
#if defined(ARDUINO_PORTENTA_C33)
// Blue LED while connecting
digitalWrite(LEDR, HIGH);
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, LOW);
#endif
WiFi.begin(WIFI_SSID, WIFI_PASS);
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED) {
if (millis() - start > WIFI_TIMEOUT_MS) {
Serial.println(" TIMEOUT");
#if defined(ARDUINO_PORTENTA_C33)
digitalWrite(LEDB, HIGH);
digitalWrite(LEDR, LOW); // red = failed
#endif
wifiConnected = false;
lastWifiAttempt = millis();
return false;
}
delay(250);
Serial.print(".");
}
Serial.print(" OK IP=");
Serial.println(WiFi.localIP());
#if defined(ARDUINO_PORTENTA_C33)
digitalWrite(LEDB, HIGH);
digitalWrite(LEDG, LOW); // green = connected
#endif
wifiConnected = true;
lastWifiAttempt = millis();
return true;
}
// ── Send one range measurement as a JSON UDP datagram ────────────
void sendRangeUDP(int tagId, uint16_t distance_cm) {
// Serial.print("sendRangeUDP: wifiConnected=");
// Serial.println(wifiConnected ? "true" : "false");
if (!wifiConnected) {
Serial.println(" -> RETURNING (wifi check failed)");
return;
}
// Serial.println(" -> proceeding to send");
char buf[128];
snprintf(buf, sizeof(buf),
"{\"anchor_id\":%d,\"tag_id\":%d,\"distance_cm\":%u,\"timestamp_ms\":%lu}",
ANCHOR_ID, tagId, (unsigned int)distance_cm, millis());
udp.beginPacket(UDP_HOST, UDP_PORT);
udp.write((const uint8_t*)buf, strlen(buf));
udp.endPacket();
delay(100);
#ifdef SERIAL_DEBUG
Serial.println(buf);
#endif
}
struct PendingRange {
int tagId;
uint16_t distance_cm;
bool ready;
};
#define RANGE_BUFFER_SIZE 16
static volatile PendingRange rangeBuffer[RANGE_BUFFER_SIZE];
static volatile uint8_t rangeWriteIdx = 0;
static uint8_t rangeReadIdx = 0;
// ── Ranging callback ─────────────────────────────────────────────
//
// Called asynchronously by the UWB stack each time a ranging round
// completes. Within a multicast session the index j corresponds to
// the j-th controlee added to the destination list (i.e. the j-th
// tag in that group, 0-indexed).
//
void rangingHandler(UWBRangingData &rangingData) {
uint8_t measType = rangingData.measureType();
uint8_t twoWay = (uint8_t)uwb::MeasurementType::TWO_WAY;
uint8_t prevWriteIdx = rangeWriteIdx;
if (measType != twoWay) {
Serial.println("incorrect measurement received");
return;
}
uint32_t sessionHandle = rangingData.sessionHandle();
// Determine which group produced this callback
int groupIndex = (int)(sessionHandle % 100) - 1; // 0 or 1
int tagBase = groupIndex * TAGS_PER_GROUP + 1; // first TAG_ID in group
RangingMeasures twr = rangingData.twoWayRangingMeasure();
for (int j = 0; j < rangingData.available(); j++) {
if (twr[j].status == 0 && twr[j].distance != 0xFFFF) {
uint8_t idx = rangeWriteIdx % RANGE_BUFFER_SIZE;
rangeBuffer[idx].tagId = tagBase + j;
rangeBuffer[idx].distance_cm = twr[j].distance;
rangeBuffer[idx].ready = true;
rangeWriteIdx++;
}
}
}
// ── Setup ────────────────────────────────────────────────────────
void setup() {
#if defined(ARDUINO_PORTENTA_C33)
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
digitalWrite(LEDR, HIGH); // all LEDs off (active-low)
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, HIGH);
digitalWrite(LEDR, LOW); // red on during init
#endif
Serial.begin(115200);
delay(1000);
Serial.println("Starting UWB ...");
// ── Anchor MAC address ──
uint8_t anchorAddrBytes[] = { 0xA0, (uint8_t)ANCHOR_ID };
UWBMacAddress anchorMac(UWBMacAddress::Size::SHORT, anchorAddrBytes);
// Register callback before starting the stack
UWB.registerRangingCallback(rangingHandler);
UWB.begin();
delay(3000);
Serial.println("=========================================");
Serial.print(" Multicast Anchor A");
Serial.print(ANCHOR_ID);
Serial.print(" MAC {0xA0, 0x0");
Serial.print(ANCHOR_ID);
Serial.println("}");
Serial.print("Waiting for UWB state to stabilize...");
while (UWB.state() != 0)
{
Serial.print(".");
delay(10);
}
Serial.println("UWB stack ready.");
// ── Create one multicast session per group ──
for (int g = 0; g < NUM_GROUPS; g++) {
int firstTag = g * TAGS_PER_GROUP + 1;
int lastTag = min(firstTag + TAGS_PER_GROUP - 1, NUM_TAGS);
// Build destination list for this group
UWBMacAddressList destList(UWBMacAddress::Size::SHORT);
for (int t = firstTag; t <= lastTag; t++) {
uint8_t tagAddrBytes[] = { 0x00, (uint8_t)t };
UWBMacAddress tagMac(UWBMacAddress::Size::SHORT, tagAddrBytes);
destList.add(tagMac);
}
uint32_t sessionId = (uint32_t)(ANCHOR_ID * 100 + g + 1);
Serial.print(" Session ");
Serial.print(sessionId);
Serial.print(" → T");
Serial.print(firstTag);
Serial.print("–T");
Serial.println(lastTag);
// Heap-allocate so the object outlives setup()
sessions[g] = new UWBRangingOneToMany(sessionId, anchorMac, destList);
UWBSessionManager.addSession(*sessions[g]);
delay(100);
sessions[g]->init();
delay(100);
sessions[g]->start();
delay(100);
}
Serial.println("All multicast sessions active.");
Serial.println("-----------------------------------------");
Serial.print("Anchor A");
Serial.print(ANCHOR_ID);
Serial.println(" ready.");
Serial.println("-----------------------------------------");
// ── WiFi + UDP ──
connectWiFi();
Serial.println("=== WiFi Debug ===");
Serial.print("Status: ");
Serial.println(WiFi.status());
Serial.print("Local IP: ");
Serial.println(WiFi.localIP());
Serial.print("Gateway: ");
Serial.println(WiFi.gatewayIP());
Serial.print("Subnet: ");
Serial.println(WiFi.subnetMask());
// MAC address for WiFiC3
uint8_t mac[6];
WiFi.macAddress(mac);
Serial.print("MAC: ");
for (int i = 5; i >= 0; i--) {
if (mac[i] < 0x10) Serial.print("0");
Serial.print(mac[i], HEX);
if (i > 0) Serial.print(":");
}
Serial.println();
udp.begin(UDP_PORT); // bind local port (required by some WiFi stacks)
delay(1000);
Serial.print("Testing gateway connectivity...");
int b = udp.beginPacket(WiFi.gatewayIP(), 53); // DNS port on gateway
int w = udp.write((const uint8_t*)"test", 4);
int e = udp.endPacket();
delay(100);
}
// ── Loop: WiFi watchdog + heartbeat ─────────────────────────────
void loop() {
// Process any buffered ranges
while (rangeReadIdx != rangeWriteIdx) {
uint8_t idx = rangeReadIdx % RANGE_BUFFER_SIZE;
if (rangeBuffer[idx].ready) {
sendRangeUDP(rangeBuffer[idx].tagId, rangeBuffer[idx].distance_cm);
rangeBuffer[idx].ready = false;
}
rangeReadIdx++;
}
// Reconnect WiFi if dropped
if (WiFi.status() != WL_CONNECTED) {
wifiConnected = false;
#if defined(ARDUINO_PORTENTA_C33)
digitalWrite(LEDG, HIGH);
digitalWrite(LEDR, LOW); // red = disconnected
#endif
if (millis() - lastWifiAttempt > WIFI_RETRY_MS) {
connectWiFi();
}
}
// Heartbeat every second (Serial only — not sent over UDP)
static unsigned long lastHeartbeat = 0;
if (millis() - lastHeartbeat > 1000) {
lastHeartbeat = millis();
// Serial.print("A");
// Serial.print(ANCHOR_ID);
// Serial.print(" WiFi=");
// Serial.print(wifiConnected ? "OK" : "DOWN");
//if (wifiConnected) {
// Serial.print(" RSSI=");
// Serial.print(WiFi.RSSI());
// Serial.print("dBm");
//}
// Serial.println();
#if defined(ARDUINO_PORTENTA_C33)
if (wifiConnected)
digitalWrite(LEDG, !digitalRead(LEDG)); // blink green as heartbeat
#endif
}
delay(50);
}
```
I have tried multiple things:
1. Basic sketches where I only configure WIFI on the board - UDP WORKS
2. Basic sketches where I configure WIFI and then UWB - UDP stops working
3. Basic sketches where I configure UWB first and then WIFI after a long delay - UDP works