Select list item: Attempt to get item number 2 of a list of length 1 (BLE)

Hi guys, I have successfully managed to establish a connection via BLE to MIT App Inventor from my Arduino. However, the problem that I’m currently facing has to do with my list blocks.

I’m using a 9-Axis IMU sensor… I want to display all 3 sensor readings (roll, pitch, yaw) but I kept getting the error that the length of my list is too short. I have seen many examples for those using just bluetoothclient but I’m using BLE. Is there any way I can display all 3 readings without having to “manipulate” them?

These are the global variables that I have declared

The blocks below gives me the notifcation that the list is incomplete. I did not add any clock timer for this function.

I have also included my Arduino codes below for reference.

#include <Wire.h>
#include “RTIMUSettings.h”
#include “RTIMU.h”
#include “RTFusionRTQF.h”
#include <SPI.h>
#include <STBLE.h>

#ifndef ARDUINO_ARCH_SAMD
#include <EEPROM.h>
#endif

//Debug output adds extra flash and memory requirements!
#ifndef BLE_DEBUG
#define BLE_DEBUG true
#endif

RTIMU *imu; // the IMU object
RTFusionRTQF fusion; // the fusion object
RTIMUSettings settings; // the settings object

// DISPLAY_INTERVAL sets the rate at which results are displayed

#define DISPLAY_INTERVAL 300 // interval between pose displays

// SERIAL_PORT_SPEED defines the speed to use for the debug serial port

#define SERIAL_PORT_SPEED 115200

#if defined(ARDUINO_ARCH_SAMD)
#define SerialMonitor SerialUSB
#else
#define SerialMonitor Serial
#endif

unsigned long lastDisplay;
unsigned long lastRate;
int sampleCount;

uint8_t sendLength = 0;
char sendBuffer[30] = " ";

uint8_t ble_rx_buffer[21];
uint8_t ble_rx_buffer_len = 0;
uint8_t ble_connection_state = false;
#define PIPE_UART_OVER_BTLE_UART_TX_TX 0

void setup() {
int errcode;

SerialMonitor.begin(SERIAL_PORT_SPEED);
BLEsetup();
Wire.begin();

imu = RTIMU::createIMU(&settings);                        // create the imu object
  SerialMonitor.print("ArduinoIMU starting using device "); SerialMonitor.println(imu->IMUName());
if ((errcode = imu->IMUInit()) < 0) {
    SerialMonitor.print("Failed to init IMU: "); SerialMonitor.println(errcode);
}

if (imu->getCalibrationValid())
    SerialMonitor.println("Using compass calibration");
else
    SerialMonitor.println("No valid compass calibration data");

lastDisplay = lastRate = millis();
sampleCount = 0;

// Slerp power controls the fusion and can be between 0 and 1
// 0 means that only gyros are used, 1 means that only accels/compass are used
// In-between gives the fusion mix.

fusion.setSlerpPower(0.02);

// use of sensors in the fusion algorithm can be controlled here
// change any of these to false to disable that sensor

fusion.setGyroEnable(true);
fusion.setAccelEnable(true);
fusion.setCompassEnable(true);

}

void loop() {

unsigned long now = millis();
unsigned long delta;

if (imu->IMURead()) { // get the latest data if ready yet
fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp());
sampleCount++;
if ((delta = now - lastRate) >= 1000) {
SerialMonitor.print(“Sample rate: “); SerialMonitor.print(sampleCount);
if (imu->IMUGyroBiasValid())
SerialMonitor.println(”, gyro bias valid”);
else
SerialMonitor.println(", calculating gyro bias - don’t move IMU!!");

  sampleCount = 0;
  lastRate = now;
}
if ((now - lastDisplay) >= DISPLAY_INTERVAL) {
  lastDisplay = now;

aci_loop();//Process any ACI commands or events

  RTVector3 accelData=imu->getAccel();
  RTVector3 fusionData=fusion.getFusionPose();
  //displayAxis("Accel:", accelData.x(), accelData.y(), accelData.z());        // accel data
  //displayAxis("Gyro:", gyroData.x(), gyroData.y(), gyroData.z());            // gyro data
  //displayAxis("Mag:", compassData.x(), compassData.y(), compassData.z());    // compass data
  //displayDegrees("Pose:", fusionData.x(), fusionData.y(), fusionData.z());   // fused output
  int x =(fusionData.x() * RTMATH_RAD_TO_DEGREE);
  int y =(fusionData.y() * RTMATH_RAD_TO_DEGREE);
  int z =(fusionData.z() * RTMATH_RAD_TO_DEGREE);
 
  if (x<0) {
    x = (x+360);
  }
    if (y<0) {
    y = (y+360);
     }
  if (z<0) {
    z = (z+360);
  }
  SerialMonitor.print(" x: "); SerialMonitor.print((x));
  SerialMonitor.print(" y: "); SerialMonitor.print((y));
  SerialMonitor.print(" z: "); SerialMonitor.print((z));

SerialMonitor.println();
sendLength = sprintf(sendBuffer, “%d”, (x), (y), (z));
lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, (uint8_t*)sendBuffer, sendLength);
}
}
}

void displayAxis(const char *label, float x, float y, float z)
{
SerialMonitor.print(label);
SerialMonitor.print(" x: “); SerialMonitor.print(x);
SerialMonitor.print(”|");
SerialMonitor.print(" y: “); SerialMonitor.print(y);
SerialMonitor.print(”|");
SerialMonitor.print(" z: "); SerialMonitor.print(z);
}

Will greatly appreciate all feedback and input. Many thanks in advance.

ble sends the data in 20-byte packets.
Don't send "x:" "y:" "z:"
uses comma as separator instead of |

x + "," + y + "," + z
try sending only one variable, for example the x

Thanks for the help Juan!

When you mention use comma as separator instead of |, is it as shown in the adjusted codes below?

I’m able to send at least one variable over… but in my MIT AI2, it only shows the x-axis values. Same goes when my blocks are arranged like this

All 3 values that appear are the same which is the x-axis value.

Look example 7

I have done the adjustments as advised... but i dont see the comma in the serial monitor... Did I do it correctly?

Update: I tried it on my MIT Ai2... and the length of the list seems much longer now. I'm unable to send even a single variable...

1 Like

String datos ="";

datos = (String) x + “,” + (String) y + “,” + (String) z;
SerialMonitor.println(datos);

Comments // all others SerialMonitors.

Done…

Now it shows that I cannot paarse text argument…? I declared my global list as “create an empty list.”

first
datos = (String) ......
then
SerialMonitor.println....

Comment all others SerialMonitor in code

Sorry for the spam… I’m still not very familiar with BLE and lists functions so i’m really thankful for the help. :frowning: Anyway, this is thelatest adjustments I have made to the section of the code… I have commented all the SerialMonitor with regards to the angle values…

However, I cannot comment the SerialMonitor for the following as it’ll result to an error in compilation of the program.

SerialMonitor.print("ArduinoIMU starting using device "); SerialMonitor.println(imu->IMUName());
if ((errcode = imu->IMUInit()) < 0) {
SerialMonitor.print("Failed to init IMU: "); SerialMonitor.println(errcode);
}

if (imu->getCalibrationValid())
    SerialMonitor.println("Using compass calibration");

else
SerialMonitor.println(“No valid compass calibration data”);

lastDisplay = lastRate = millis();
sampleCount = 0;

// Slerp power controls the fusion and can be between 0 and 1
// 0 means that only gyros are used, 1 means that only accels/compass are used
// In-between gives the fusion mix.

fusion.setSlerpPower(0.02);

// use of sensors in the fusion algorithm can be controlled here
// change any of these to false to disable that sensor

fusion.setGyroEnable(true);
fusion.setAccelEnable(true);
fusion.setCompassEnable(true);

}

void loop()
{
unsigned long now = millis();
unsigned long delta;

if (imu->IMURead()) { // get the latest data if ready yet
fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp());
sampleCount++;
if ((delta = now - lastRate) >= 1000) {
SerialMonitor.print(“Sample rate: “); SerialMonitor.print(sampleCount);
if (imu->IMUGyroBiasValid())
SerialMonitor.println(”, gyro bias valid”);
else
SerialMonitor.println(", calculating gyro bias - don’t move IMU!!");

The current error that MIT AI2 shows is this

Are my MIT Ai2 codes correct…?

declaration

Many thanks for the help again.

Look example 21.- Arduino sends three random numbers to App.

Does this only apply for bluetoothclient? For BLE, do i need to avoid using StringsReceived then?

StringsReceiver is similar to stringValues in ClientBluetooth.

For BLE I use other codes different from yours.

But if the app receives the data string as indicated in tutorial 21.- Arduino sends three..., you can separate the data as indicated in the mentioned tutorial

Hmm, cause for my project, it's important that I strictly use BLE. I tried to follow the codes as stated in your tutorial (example 21) but it seems that it's hard / (impossible?) for me to switch between enabling ClientBluetooth and BLE.

I have no problem sending the data over from Arduino... It appears as one long string.

But now when i try to edit my MIT AI2 codes using list from csv row text/list, it shows me this same error:

My BLE codes for MIT AI2 are as follows. I cant figure out why the list codes are not working...

Can you upload the full Arduino code in text here?

Here’s my full Arduino code!

/*
TinyCircuits LSM9DS1 9 Axis TinyShield Example Sketch

This demo is intended for the ASD2511 Sensor Board TinyShield with a LSM9DS1
9 axis sensor populated. It shows basic use of a modified RTIMULib with the
sensor.

This program now includes an EEPROM compatibility file for TinyScreen+.
Using it will lock the last 16KB of flash for EEPROM emulation and prevent
the bootloader from erasing or writing that section. This should not affect
other programs unless they are trying to use the last 16KB of flash.

Written 11 July 2016
By Ben Rose
Modified 07 January 2019
By Hunter Hykes

https://TinyCircuits.com
*/

////////////////////////////////////////////////////////////////////////////
//
// This file is part of RTIMULib-Arduino
//
// Copyright © 2014-2015, richards-tech
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the “Software”), to deal in
// the Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
////////////////////////////////////////////////////////////////////////////

#include <Wire.h>
#include “RTIMUSettings.h”
#include “RTIMU.h”
#include “RTFusionRTQF.h”
#include <SPI.h>
#include <STBLE.h>

#ifndef ARDUINO_ARCH_SAMD
#include <EEPROM.h>
#endif

//Debug output adds extra flash and memory requirements!
#ifndef BLE_DEBUG
#define BLE_DEBUG true
#endif

RTIMU *imu; // the IMU object
RTFusionRTQF fusion; // the fusion object
RTIMUSettings settings; // the settings object

// DISPLAY_INTERVAL sets the rate at which results are displayed

#define DISPLAY_INTERVAL 300 // interval between pose displays

// SERIAL_PORT_SPEED defines the speed to use for the debug serial port

#define SERIAL_PORT_SPEED 115200

#if defined(ARDUINO_ARCH_SAMD)
#define SerialMonitor SerialUSB
#else
#define SerialMonitor Serial
#endif

unsigned long lastDisplay;
unsigned long lastRate;
int sampleCount;
String data ="";

uint8_t sendLength = 0;
char sendBuffer[30] = " ";

uint8_t ble_rx_buffer[21];
uint8_t ble_rx_buffer_len = 0;
uint8_t ble_connection_state = false;
#define PIPE_UART_OVER_BTLE_UART_TX_TX 0

void setup()
{
int errcode;

SerialMonitor.begin(SERIAL_PORT_SPEED);
BLEsetup();
Wire.begin();

imu = RTIMU::createIMU(&settings);                        // create the imu object

SerialMonitor.print("ArduinoIMU starting using device "); SerialMonitor.println(imu->IMUName());
if ((errcode = imu->IMUInit()) < 0) {
    SerialMonitor.print("Failed to init IMU: "); SerialMonitor.println(errcode);
}

if (imu->getCalibrationValid())
    SerialMonitor.println("Using compass calibration");

else
SerialMonitor.println(“No valid compass calibration data”);

lastDisplay = lastRate = millis();
sampleCount = 0;

// Slerp power controls the fusion and can be between 0 and 1
// 0 means that only gyros are used, 1 means that only accels/compass are used
// In-between gives the fusion mix.

fusion.setSlerpPower(0.02);

// use of sensors in the fusion algorithm can be controlled here
// change any of these to false to disable that sensor

fusion.setGyroEnable(true);
fusion.setAccelEnable(true);
fusion.setCompassEnable(true);

}

void loop()
{
unsigned long now = millis();
unsigned long delta;

if (imu->IMURead()) { // get the latest data if ready yet
fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp());
sampleCount++;
if ((delta = now - lastRate) >= 1000) {
SerialMonitor.print(“Sample rate: “); SerialMonitor.print(sampleCount);
if (imu->IMUGyroBiasValid())
SerialMonitor.println(”, gyro bias valid”);
else
SerialMonitor.println(", calculating gyro bias - don’t move IMU!!");

  sampleCount = 0;
  lastRate = now;
}
if ((now - lastDisplay) >= DISPLAY_INTERVAL) {
  lastDisplay = now;
  aci_loop();
  RTVector3 accelData=imu->getAccel();
  RTVector3 gyroData=imu->getGyro();
  RTVector3 compassData=imu->getCompass();
  RTVector3 fusionData=fusion.getFusionPose();
  //displayAxis("Accel:", accelData.x(), accelData.y(), accelData.z());        // accel data
  //displayAxis("Gyro:", gyroData.x(), gyroData.y(), gyroData.z());            // gyro data
  //displayAxis("Mag:", compassData.x(), compassData.y(), compassData.z());    // compass data
  //displayDegrees("Pose:", fusionData.x(), fusionData.y(), fusionData.z());   // fused output
  int x =(fusionData.x() * RTMATH_RAD_TO_DEGREE);
  int y = (fusionData.y() * RTMATH_RAD_TO_DEGREE);
  int z = (fusionData.z() * RTMATH_RAD_TO_DEGREE);

  if (x<0) {
    x = (x+360);
  }
  if (y<0) {
    y = (y+360);
  }
  if (z<0) {
    z = (z+360);
  }
  //SerialMonitor.print("x:"); SerialMonitor.print((x));
  //SerialMonitor.print("y:"); SerialMonitor.print((y));
  //SerialMonitor.print("z:"); SerialMonitor.print((z));
  data = (String) x + "," + (String) y + "," + (String) z;
  SerialMonitor.println(data);
  sendLength = sprintf(sendBuffer, "%d", data);
  lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, (uint8_t*)sendBuffer, sendLength);
}

}
}

void displayAxis(const char *label, float x, float y, float z)
{
//SerialMonitor.print(label);
//SerialMonitor.print(“x:”); SerialMonitor.print(x);
//SerialMonitor.print(“y:”); SerialMonitor.print(y);
//SerialMonitor.print(“z:”); SerialMonitor.print(z);
}

What do you get directly with StringValues?

Label.text = StringValues

Sorry, do you mean StringValues in the MIT App Inventor? If directly with Stringvalues, I got 536871556 as shown in the image below.