0

Im having trouble in sending float number and multiple float numbers. Im currently working on project matlab and arduino mkr1000. The situation is that i want to send float number and multiple float numbers through communication(which in client.available() code) and view it in Serial Monitor. I have been searching throughout the internet but unfortunately could not receive it. The more i read the more confused i became. Im new to this environment. I do need consider bitshifting right?. Is there any similar examples and guidances from others would be really highly appreciated. Thank you.

Arduino Ide

    /* Latest Progress of the Project*/
#include <SPI.h>
#include <WiFi101.h>

// sensitive data placed in arduino_secrets.h
#include "arduino_secrets.h"
char ssid[] = SECRET_SSID; // name wifi
char pass[] = SECRET_PASS; // password
int status = WL_IDLE_STATUS; // status of wifi

// variables used
float value;

IPAddress ipserver(192, 168, 1, 109); // home wifi ip address

// initialize the client library
WiFiClient client;

void setup()
{
  // initialize serial and wait for port to open:
  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.println("Attempting to connect to WPA network...");
  Serial.print("SSID:");
  Serial.println(ssid);

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED)
  {
    // will keep trying until connected
    Serial.print("Attempting to connect to network: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds(enough time) for connection:
    delay(10000);
  }

  // if you're connected now, so print the data status:
  Serial.println("You're connected to the network");
  Serial.println("------------------------------------");
  Serial.println("Hi FYP63333 Group");
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  Serial.println("------------------------------------");
  Serial.println("\nStarting connection to server...");
}

void loop()
{
  // Client connect or not connect in serial monitor:
  if (!client.connect(ipserver, 1234))
  {
    // if you didnt't get a connection to the server:
    Serial.println("Can't connect to server, try again.");
    delay(5000);
    return;
  }
  else
  {
    // if you get connection to the server:
    Serial.println("Connected to server!!!");
    Serial.println("MATLAB READY");
    //client.println("Hello from MKR1000");
  }

  // If there are incoming bytes available from the server, read and print them
  // Read all the lines of the reply from server and print them inside Serial Monitor:
  Serial.println();
  Serial.println("Incoming and receiving data from remote server:");
  while (client.connected() || client.available() || Serial.available())
  {
    while (Serial.available())
    {
      char data;
      data = Serial.read();
      if (client.connected())
      {
        client.print(data);
      }
    }
    while (client.available())
    {

      //------------------main-code(works)--------------for string//
      char ch = static_cast<char>(client.read());
      Serial.println(ch);
    }
  }

  // if the server's disconnected, stop the client:
  if (!client.connected())
  {
    Serial.println();
    Serial.println("Disconnecting from the server.");
    client.stop();
  }
}

Matlab code

clear; 
clc;
%% Connecting matlab and Arduino IDE(TCP/IP Server)
t = tcpserver("192.168.1.109",1234);
t.ByteOrder = "big-endian";
3
  • 2
    I would highly recommend sending all data as text. Then you don't have to worry about bit-shifting, byte order and such. See String::toFloat(). Apr 24, 2022 at 11:46
  • trouble in sending float number and multiple float numbers ... it appears that you may not be thinking clearly about the problem you are facing ... the success in sending multiple numbers is dependent on the success in sending a single number ... it may be time to go for a break and clear your head
    – jsotola
    Apr 24, 2022 at 15:32
  • i can read the single number send from MATLAB to Arduino IDE by just using serial.println(ch,DEC) but when it comes to float numbers im having trouble about it. Apr 24, 2022 at 23:49

3 Answers 3

2

Sending numerical values between systems is fraught with difficulty. Not only do you have to ensure that both ends agree on the size of the data (16 bit vs 32 bit ints, float vs double, etc) but that the byte ordering is handled correctly. On top of that is knowing where a number is in the stream of data. With nothing to delimit each value (and when you have 8 bits of communication width and 8 bits of data there's no room for "out of band" control signals) yo have no way of knowing which byte in the data stream corresponds to which byte in a value's raw data.

It's far better to encode the data into some other format that leaves you room to add delimiting control signals and has a predefined machine-agnostic data format.

The simplest encoding: ASCII. Simply "print" the numbers as text with the precision you desire (number of decimal places) as one number per line. Then on the Arduino you can read text data a line at a time then use the internal float conversion routines to turn that data into an actual floating point value again.

Some references:

1
  • thank you and i will try Apr 24, 2022 at 23:47
0

Check out the I2C_Anything library. It is used to transfer any data type bit-by-bit using the I2C serial protocol, but the algorithms could be just as easily used over ANY serial connection. You do have to make sure that the size of a particular datatype is the same on both ends, but that's about it.

Here's my subroutine running on a Teensy 3.5 that acquires VL53L0X LIDAR data from another Arduino processor (actually a Teensy 3.2).

    bool GetRequestedVL53l0xValues(VL53L0X_REQUEST which)
{
  //Purpose: Obtain VL53L0X ToF sensor data from Teensy sensor handler
  //Inputs: 
  //    which = VL53L0X_REQUEST value denoting which combination of value to retrieve
  //        VL53L0X_CENTERS_ONLY -> Just the left/right center sensor values
  //        VL53L0X_RIGHT -> All three right sensor values, in front/center/rear order
  //        VL53L0X_LEFT -> All three left sensor values, in front/center/rear order
  //        VL53L0X_ALL -> All seven sensor values, in left/right front/center/rear/rear order
  //        VL53L0X_REAR_ONLY -> added 10/24/20 Just the rear sensor reading

  //Outputs: 
  //    Requested sensor values, obtained via I2C from the VL53L0X sensor handler
  //    Returns TRUE if data retrieval successful, otherwise FALSE
  //Plan:
  //    Step1: Send request to VL53L0X handler
  //    Step2: get the requested data
  //Notes:
  // Copied from FourWD_WallE2_V4.ino's IsIRBeamAvail() and adapted
    // 08/05/20 added a VL53L0X_ALL request type
    // 01/24/21 added error detection/reporting
    // 01/16/22 rev to use I2C_Anything1 functions for Wire1

  //Step1: Send request to VL53L0X handler
  //DEBUG!!
    //myTeePrint.printf("Sending %d to slave\n", which);
  //DEBUG!!

  //myTeePrint.printf("In GetRequestedVL53l0xValues(%d)\n", (int)which);

  //03/01/22 rev to cvt all readings to cm
  uint16_t Lidar_RightFrontMM = 0;
  uint16_t Lidar_RightCenterMM = 0;
  uint16_t Lidar_RightRearMM = 0;
  uint16_t Lidar_RearMM = 0;

  uint16_t Lidar_LeftFrontMM = 0;
  uint16_t Lidar_LeftCenterMM = 0;
  uint16_t Lidar_LeftRearMM = 0;


  Wire1.beginTransmission(VL53L0X_I2C_SLAVE_ADDRESS);
  I2C_writeAnything((uint8_t)which, &Wire1);
  Wire1.endTransmission();


  //Step2: get the requested data
  int readResult = 0;
  int data_size = 0;
  switch (which)
  {
  case VL53L0X_READYCHECK: //11/10/20 added to prevent bad reads during Teensy setup()
    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, (uint16_t)(sizeof(bVL53L0X_TeensyReady)));
    readResult = I2C_readAnything(bVL53L0X_TeensyReady, &Wire1);
    break;

  case VL53L0X_CENTERS_ONLY:
    //just two data values needed here
    data_size = 2 * sizeof(uint16_t);
    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, (uint16_t)(2 * sizeof(Lidar_RightCenterMM)));
    readResult = I2C_readAnything(Lidar_RightCenterMM, &Wire1);
    glRightCenterCm = Lidar_RightCenterMM / 10; //integer truncation OK

    if (readResult > 0)
    {
      I2C_readAnything(Lidar_LeftCenterMM, &Wire1);
      glLeftCenterCm = Lidar_LeftCenterMM / 10; //integer truncation OK
    }

    //DEBUG!!
        //myTeePrint.printf("VL53L0X_CENTERS_ONLY case: Got LC/RC = %d, %d\n", Lidar_LeftCenterMM, Lidar_RightCenterMM);
    //DEBUG!!

    break;
  case VL53L0X_RIGHT:
    //four data values needed here
    data_size = 3 * sizeof(uint16_t) + sizeof(float);

    //DEBUG!!
        //myTeePrint.printf("data_size = %d\n", data_size);
    //DEBUG!!

    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, data_size);
    readResult = I2C_readAnything(Lidar_RightFrontMM, &Wire1);
    glRightFrontCm = Lidar_RightFrontMM / 10; //integer truncation OK

    if (readResult > 0)
    {
      readResult = I2C_readAnything(Lidar_RightCenterMM, &Wire1);
      glRightCenterCm = Lidar_RightCenterMM / 10; //integer truncation OK
    }
    if (readResult > 0)
    {
      readResult = I2C_readAnything(Lidar_RightRearMM, &Wire1);
      glRightRearCm = Lidar_RightRearMM / 10; //integer truncation OK
    }
    if (readResult > 0)
    {
      readResult = I2C_readAnything(glRightSteeringVal, &Wire1);
    }

    //DEBUG!!
        //myTeePrint.printf("VL53L0X_RIGHT case: Got L/C/R/S = %d, %d, %d, %3.2f\n",
        //  glRightFrontCm, Lidar_RightCenterMM, Lidar_RightRearMM, ToFSteeringVal);
    //DEBUG!!

    break;
  case VL53L0X_LEFT:
    //four data values needed here
    //data_size = 3 * sizeof(int) + sizeof(float);
    data_size = 3 * sizeof(uint16_t) + sizeof(float);

    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, data_size);
    readResult = I2C_readAnything(Lidar_LeftFrontMM, &Wire1);
    glLeftFrontCm = Lidar_LeftFrontMM / 10; //integer truncation OK

    if (readResult > 0)
    {
      readResult = I2C_readAnything(Lidar_LeftCenterMM, &Wire1);
      glLeftCenterCm = Lidar_LeftCenterMM / 10; //integer truncation OK
    }
    if (readResult > 0)
    {
      readResult = I2C_readAnything(Lidar_LeftRearMM, &Wire1);
      glLeftRearCm = Lidar_LeftRearMM / 10; //integer truncation OK
    }
    if (readResult > 0)
    {
      readResult = I2C_readAnything(glLeftSteeringVal, &Wire1);
    }

    //DEBUG!!
        //myTeePrint.printf("VL53L0X_RIGHT case: Got L/C/R/S = %d, %d, %d, %3.2f\n",
        //  Lidar_LeftFrontMM, Lidar_LeftCenterMM, Lidar_LeftRearMM, ToFSteeringVal);
    //DEBUG!!

    break;
  case VL53L0X_ALL: //added 08/05/20, chg to VL53L0X_ALL 10/31/20
    //nine data values needed here - 7 ints and 2 floats
    data_size = 7 * sizeof(uint16_t) + 2 * sizeof(float); //10/31/20 added rear distance

    //myTeePrint.printf("In VL53L0X_ALL case with data_size = %d\n", data_size);

    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, data_size);

    //Lidar_LeftFrontMM
    readResult = I2C_readAnything(Lidar_LeftFrontMM, &Wire1);
    glLeftFrontCm = Lidar_LeftFrontMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_LeftFrontMM))
    {
      myTeePrint.printf("Error reading Lidar_LeftFrontMM\n");
    }

    //Lidar_LeftCenterMM
    readResult = I2C_readAnything(Lidar_LeftCenterMM, &Wire1);
    glLeftCenterCm = Lidar_LeftCenterMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_LeftCenterMM))
    {
      myTeePrint.printf("Error reading Lidar_LeftCenterMM\n");
    }

    //Lidar_LeftRearMM
    readResult = I2C_readAnything(Lidar_LeftRearMM, &Wire1);
    glLeftRearCm = Lidar_LeftRearMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_LeftRearMM))
    {
      myTeePrint.printf("Error reading Lidar_LeftRearMM\n");
    }

    //glLeftSteeringVal
    readResult = I2C_readAnything(glLeftSteeringVal, &Wire1);
    if (readResult != sizeof(glLeftSteeringVal))
    {
      myTeePrint.printf("Error reading glLeftSteeringVal\n");
    }

    //Lidar_RightFrontMM
    readResult = I2C_readAnything(Lidar_RightFrontMM, &Wire1);
    glRightFrontCm = Lidar_RightFrontMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_RightFrontMM))
    {
      myTeePrint.printf("Error reading Lidar_RightFrontMM\n");
    }

    //Lidar_RightCenterMM
    readResult = I2C_readAnything(Lidar_RightCenterMM, &Wire1);
    glRightCenterCm = Lidar_RightCenterMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_RightCenterMM))
    {
      myTeePrint.printf("Error reading Lidar_RightCenterMM\n");
    }

    //Lidar_RightRearMM
    readResult = I2C_readAnything(Lidar_RightRearMM, &Wire1);
    glRightRearCm = Lidar_RightRearMM / 10; //integer truncation OK

    if (readResult != sizeof(Lidar_RightRearMM))
    {
      myTeePrint.printf("Error reading Lidar_RightRearMM\n");
    }

    //Lidar_RearMM
    readResult = I2C_readAnything(Lidar_RearMM, &Wire1);
    glRearCm = Lidar_RearMM / 10; //integer truncation OK
    if (readResult != sizeof(Lidar_RearMM))
    {
      myTeePrint.printf("Error reading Lidar_RearMM\n");
    }

    //glRightSteeringVal
    readResult = I2C_readAnything(glRightSteeringVal, &Wire1);
    if (readResult != sizeof(glRightSteeringVal))
    {
      myTeePrint.printf("Error reading glLeftSteeringVal\n");
    }

    //myTeePrint.printf("%lu: VL53l0x - %d, %d, %d, %d, %d, %d, %d\n",
    //  millis(), 
    //  Lidar_LeftFrontMM, Lidar_LeftCenterMM, Lidar_LeftRearMM,
    //  glRightFrontCm, Lidar_RightCenterMM, Lidar_RightRearMM,
    //  Lidar_RearMM);
    break; //10/31/20 bugfix

  case VL53L0X_REAR_ONLY:
    //just ONE data value needed here
    data_size = sizeof(uint16_t);
    Wire1.requestFrom(VL53L0X_I2C_SLAVE_ADDRESS, (uint16_t)(sizeof(Lidar_RearMM)));
    readResult = I2C_readAnything(Lidar_RearMM, &Wire1);
    glRearCm = Lidar_RearMM / 10; //integer truncation OK

    //DEBUG!!
        //myTeePrint.printf("VL53L0X_REAR_ONLY case: Got Rear = %d\n", Lidar_RearMM);
    //DEBUG!!

    break;

  default:
    break;
  }
  //myTeePrint.printf("GetRequestedVL53l0xValues(): LR/LC/LF/RR/RC/RF/R = %d\t%d\t%d\t%d\t%d\t%d\t%d\n",
  //  Lidar_LeftRearMM, Lidar_LeftCenterMM, Lidar_LeftFrontMM,
  //  Lidar_RightRearMM, Lidar_RightCenterMM, glRightFrontCm, Lidar_RearMM);

  return readResult > 0; //this is true only if all reads succeed
}

and here's the corresponding code on the other end of the I2C link:

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  //Purpose: Send requested sensor data to the Mega controller via main I2C bus
  //Inputs: 
  //  request_type = uint8_t value denoting type of data requested (from receiveEvent())
  //      0 = left & right center distances only
  //      1 = right side front, center and rear distances, plus steering value
  //      2 = left side front, center and rear distances, plus steering value
  //      3 = both side front, center and rear distances, plus both steering values
//Outputs:
  //  Requested data sent to master
  //Notes:
  //  08/05/20 added VL53L0X_ALL request type to get both sides at once
  //  10/24/20 added VL53L0X_REAR_ONLY request type
  //  11/09/20 added write to pin for O'scope monitoring

  int data_size = 0;

//DEBUG!!
    //Serial.printf("RequestEvent() with request_type = %d: VL53L0X Front/Center/Rear distances = %d, %d, %d\n", 
    //    request_type, RF_Dist_mm, RC_Dist_mm, RR_Dist_mm);
//DEBUG!!

  //digitalWrite(LED_BUILTIN, HIGH);//added 01/22/22
  digitalWrite(REQUEST_EVENT_DURATION_OUTPUT_PIN, HIGH);

  digitalToggle(LED_BUILTIN);//2/21/22 added for visual indication of I2C activity
  switch (request_type)
  {
  case  VL53L0X_READYCHECK: //added 11/10/20 to prevent bad reads during Teensy setup()
    //Serial.printf("in VL53L0X_READYCHECK case at %lu with bTeensyReady = %d\n", millis(), bTeensyReady);
    I2C_writeAnything(bTeensyReady);
    break;

  case VL53L0X_CENTERS_ONLY:

    //DEBUG!!
      //data_size = 2*sizeof(uint16_t);
      //Serial.printf("Sending %d bytes LC_Dist_mm = %d, RC_Dist_mm = %d to master\n", data_size, LC_Dist_mm, RC_Dist_mm);
    //DEBUG!!

    I2C_writeAnything(RC_Dist_mm);
    I2C_writeAnything(LC_Dist_mm);
    break;

  case VL53L0X_RIGHT:

    //DEBUG!!
            //data_size = 3 * sizeof(uint16_t) + sizeof(float);
            //Serial.printf("Sending %d bytes RF/RC/RR/RS vals = %d, %d, %d, %3.2f to master\n",
            //    data_size, RF_Dist_mm, RC_Dist_mm, RR_Dist_mm, RightSteeringVal);
    //DEBUG!!

    I2C_writeAnything(RF_Dist_mm);
    I2C_writeAnything(RC_Dist_mm);
    I2C_writeAnything(RR_Dist_mm);
    I2C_writeAnything(RightSteeringVal);
    break;

  case VL53L0X_LEFT:

    //DEBUG!!
            //data_size = 3 * sizeof(uint16_t) + sizeof(float);
            //Serial.printf("Sending %d bytes LF/LC/LR/LS vals = %d, %d, %d, %3.2f to master\n",
            //    data_size, LF_Dist_mm, LC_Dist_mm, LR_Dist_mm, LeftSteeringVal);
    //DEBUG!!

    I2C_writeAnything(LF_Dist_mm);
    I2C_writeAnything(LC_Dist_mm);
    I2C_writeAnything(LR_Dist_mm);
    I2C_writeAnything(LeftSteeringVal);
    break;

  case VL53L0X_ALL:
    //Serial.printf("In VL53L0X_ALL case\n");
    //added 08/05/20 to get data from both sides at once
    //10/31/20 chg to VL53L0X_ALL & report all 7 sensor values

//DEBUG!!
    //data_size = 3 * sizeof(uint16_t) + sizeof(float);
    //data_size = 7 * sizeof(uint16_t) + 2 * sizeof(float);
    //Serial.printf("Sending %d bytes to master\n", data_size);
    //Serial.printf("%d bytes: %d\t%d\t%d\t%3.2f\t%d\t%d\t%d\t%d\t%3.2f\n",
    //    data_size, LF_Dist_mm, LC_Dist_mm, LR_Dist_mm, LeftSteeringVal,
    //  RF_Dist_mm, RC_Dist_mm, RR_Dist_mm, Rear_Dist_mm, RightSteeringVal);
//DEBUG!!



    //DEBUG!!
      //data_size = 3 * sizeof(uint16_t) + sizeof(float);
      //Serial.printf("Sending %d bytes LF/LC/LR/LS vals = %d, %d, %d, %3.2f to master\n",
      //    data_size, LF_Dist_mm, LC_Dist_mm, LR_Dist_mm, LeftSteeringVal);
    //DEBUG!!

    //left side  
    I2C_writeAnything(LF_Dist_mm);
    I2C_writeAnything(LC_Dist_mm);
    I2C_writeAnything(LR_Dist_mm);
    I2C_writeAnything(LeftSteeringVal);


    //DEBUG!!
      //data_size = 3 * sizeof(uint16_t) + sizeof(float);
      //data_size = 4 * sizeof(uint16_t) + sizeof(float);
      //Serial.printf("Sending %d bytes RF/RC/RR/R/RS vals = %d, %d, %d, %d, %3.2f to master\n",
      //    data_size, RF_Dist_mm, RC_Dist_mm, RR_Dist_mm, Rear_Dist_mm, RightSteeringVal);
    //DEBUG!!

       //right side
    I2C_writeAnything(RF_Dist_mm);
    I2C_writeAnything(RC_Dist_mm);
    I2C_writeAnything(RR_Dist_mm);
    I2C_writeAnything(Rear_Dist_mm);
    I2C_writeAnything(RightSteeringVal);

    break;

  case VL53L0X_REAR_ONLY:

    //DEBUG!!
      //data_size = sizeof(uint16_t);
      //Serial.printf("Sending %d bytes Rear_Dist_mm = %d to master\n", data_size, Rear_Dist_mm);
    //DEBUG!!

    I2C_writeAnything(Rear_Dist_mm);
    break;

  default:
    break;
  }
  digitalToggle(LED_BUILTIN);//2/21/22 added for visual indication of I2C activity

  digitalWrite(REQUEST_EVENT_DURATION_OUTPUT_PIN, LOW);
  //digitalWrite(LED_BUILTIN, LOW);//added 01/22/22
}
0

As an alternative, you can send the numbers as text, as suggested by Edgar Bonet above. Here's a short program I just whipped up that demos this capability, using two Teensy 3.x processors. The program waits for a character on its serial port, and if any are found, they are transmitted to the other processor via a serial connection between the two, and also echoed back to the sending serial port. This should work with any Arduino processor that has two serial ports (Serial for talking to the PC, Serial1 for talking to the other processor). I used the built-in LED as an activity monitor.

/*
    Name:       Serial_Anything.ino
    Created:    4/26/2022 6:23:01 PM
    Author:     FRANKNEWXPS15\Frank

    Project to demonstrate passing arbitrary data types over a serial connection
    The idea is to port I2C_Anything to use over a common serial port connection
*/

#include "Serial_Anything.h"

//char buff[30];

void setup()
{
  Serial.begin(115200);
  delay(1000);
  Serial1.begin(115200);
  delay(1000);

  Serial.printf("Serial_Anything Demo\n");

  pinMode(LED_BUILTIN, OUTPUT);

  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);

}

void loop()
{
  if (Serial.available())
  {
    //buff[buffidx] = Serial.read();
    //buffidx++;
    char c = Serial.read();
    Serial1.write(c);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(50);
    digitalWrite(LED_BUILTIN, LOW);
    Serial.write(c);
  }

  if (Serial1.available())
  {
    //buff[buffidx] = Serial.read();
    //buffidx++;
    char c = Serial1.read();
    Serial.write(c);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(50);
    digitalWrite(LED_BUILTIN, LOW);
  }
}

Here's a short section of output from a typical run:

Teensy1:

Port closed
Opening port
Port open
Serial_Anything Demo
y
y
y
y
X
X
X
X
the quick
314159
3.14159

Teensy2:

Opening port
Port open
y
y
y
y
y
y
y
y
y
y
y
y
y
X
X
X
X
the quick
314159
3.14159
1
  • Thank you for your time with the example and sample code. i will try with client.read() based on your explanation above. Im highly appreciate the helps and suggestions. Apr 27, 2022 at 2:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.