Array Error Message

Compiling the following code, the case structure produces this error message for each line and finally -

status 1
Compilation error: cannot convert '' to 'int' in assignment

I'm a newby with C++ and haven't managed to understand arrays. It's part of a sketch for a mecanum wheel car using the Adafruit Motor Shield v2 on a Uno R3. The wheel array independently sets the direction of rotation of each wheel for various compass directions of travel.

These lines are from Monitor_Input.ino to receive an integer typed into the IDE monitor.
recvWithEndMarker();
showNewNumber();
if (dataNumber != 0)

LF, RR etc are abbreviations for left-front, right-rear wheel motors.

// Adafruit Motor Shield

#include <Adafruit_MotorShield.h>
#include <C:\Users\feral\Documents\Arduino\Monitor_Input\Monitor_Input.ino>

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();

Adafruit_DCMotor *motRF = AFMS.getMotor(1);
Adafruit_DCMotor *motRR = AFMS.getMotor(2);
Adafruit_DCMotor *motLR = AFMS.getMotor(3);
Adafruit_DCMotor *motLF = AFMS.getMotor(4);

int speed[4] = {80, 120, 80, 120};  // 0 <= n <= 255
int wheel[4] = {1, 1, 1, 1};        // stop (0), fore (1), rev (2)
int dir = 1;  // compass directions, 0 to 15 cw & rot

void setup() {
  Serial.begin(9600); // Set up Serial library at 9600 bps
  AFMS.begin(1000);   // PWM Frequency 1.0KHz
}

void loop() {
  recvWithEndMarker();
  showNewNumber();
  if (dataNumber != 0){
    dir = dataNumber;

    switch (dir) {
      case 1:  wheel[4] = {1, 1, 1, 1}; break;  // N
      case 2:  wheel[4] = {1, 1, 1, 1}; break;  // NNE
      case 3:  wheel[4] = {0, 1, 0, 1}; break;  // NE
      case 4:  wheel[4] = {2, 1, 2, 1}; break;  // ENE
      case 5:  wheel[4] = {2, 1, 2, 1}; break;  // E
      case 6:  wheel[4] = {2, 1, 2, 1}; break;  // ESE
      case 7:  wheel[4] = {2, 0, 2, 0}; break;  // SE
      case 8:  wheel[4] = {2, 2, 2, 2}; break;  // SSE
      case 9:  wheel[4] = {2, 2, 2, 2}; break;  // S
      case 10: wheel[4] = {2, 2, 2, 2}; break;  // SWS
      case 11: wheel[4] = {0, 2, 0, 2}; break;  // SW
      case 12: wheel[4] = {1, 2, 1, 2}; break;  // WSW
      case 13: wheel[4] = {1, 2, 1, 2}; break;  // W
      case 14: wheel[4] = {1, 2, 1, 2}; break;  // WNW
      case 15: wheel[4] = {1, 0, 1, 0}; break;  // NW
      case 16: wheel[4] = {1, 1, 1, 1}; break;  // NWN
      case 17: wheel[4] = {2, 2, 1, 1}; break;  // CW
      case 18: wheel[4] = {1, 1, 2, 2}; break;  // CCW
      default: Serial.print("Case n is corrupt"); break;
    }
  }

    motLFgo();
    motLRgo();
    motRRgo();
    motRFgo();
}

// ===============================

void motLFgo() {
  motLF ->setSpeed(speed[0]);
  motLF ->run(wheel[0]);}

void motLRgo() {
  motLR ->setSpeed(speed[1]);
  motLR ->run(wheel[1]);}

void motRRgo() {
  motRR ->setSpeed(speed[2]);
  motRR ->run(wheel[2]);}

void motRFgo() {
  motRF ->setSpeed(speed[3]);
  motRF ->run(wheel[3]);}

Imma let you look at this until you see your mistake:

      default: Serial.print("Case n is corrupt'); break;

I'll check back later, but you need to start appreciating subtle differences that don't matter so much except in code, where spelling and puncuation count.

Took me a minute...

a7

Here too. The next error that will trip you up.

wheel[4] is an integer. Besides, even if it were an array, C/C++ has no direct way but for the initialisation to copy a {set of values} to an array

      case 1:  wheel[4] = {1, 1, 1, 1}; break;  // N`

Here's where you'll need to learn a bit more about arrays. A two dimensional array 18 rows by 4 columns could hold all 18 commands. To invoke one, you would pass the row number.

Or, you could hands and knees it using what you may already know. I suggest a break from the project and see if you can get your head around 2D arrays.

Again, I see later where this thread is. I am not in the lab, just typing into the tiny window.

a7

You have "...' surrounding the print string while my code has consistent double quotes - "...". Other than that, I don't understand what you're indicating.

It's a one dimensional array.
Why is this ok when initialing the array but not ok when amending values?

wheel[4] = {1, 1, 1, 1};

Do you mean it needs to be something like this, loading each slot in turn -
wheel[0] = 1;
wheel[1] = 2;
etc

God did make frogs with wings and they all flew away. That's why we don't see any.

I commented out all the case lines and added these instead as a test and they work. Type in "1" and wheel[0] reverses. Type in "2" and wheel[3] speeds up, type in "3" and wheel[2] stops.

      case 1:  wheel[0] = 2; break;
      case 2:  wheel[3] = 1; speed[3] = 200; break;
      case 3:  wheel[2] = 0; speed[2] = 0; break;

What's the syntax to ammend all slots of an array in one go.

You can use this kind of syntax

case 7: setWheel(2,0,2,0); break;

and use a function:

void setWheel(int wheel0, int wheel1, int wheel2, int wheel3) {
   wheel[0] = wheel0;
   wheel[1] = wheel1;
   wheel[2] = wheel2;
   wheel[3] = wheel3;
}

Or do as @alto777 suggested in Post #3. It would be cleaner, easier to maintain.

Thanks. That works and I understand it too. Looking back at @alto777's suggestion again, I now understand what he meant by wheel[4] is an integer. I'll give the 2D array a try too.

I assumed wheel[4] was the array. I get that wheel[4] is really an error because the index 4 is outside of the bounds of the array.

Just this would not lead to a compilation error, since the C compiler does not check indexes for going beyond array boundaries. You can freely write wheel[44] or even wheel[-2] and there will be no compilation errors. (The fact that this, of course, will not work is discussed separately).

Your mistake was exact the fact that C doesn't allow you to assign arrays:

wheel[4] = {1, 1, 1, 1};

Good eye. As @b707 says, it's still possible to refer to wheel[4], but it is a genuine Bad Idea.

But you got the point of my stating that wheel[index] is an integer.

As for "this' matter, I apologize and have no idea how the code got mangled from what you posted when I compiled it myself... I'm usually pretty good at copy/pasting and hacking to get at things without distractions (or to compensate for lack of hardware or a library I don't wanna install).

I will blame the heat, yeah that's the ticket. :expressionless:

a7

If I had done "that' myself I might never have found my own error. Something I learned from my brother who worked sometimes as an editor - read things backwards. It breaks your usual pattern recognition making your own habits jump out at you as an anomaly.

This is the code after generous help about arrays - thanks to all. Next stage will be parsing the input of speed values for the four motors. Finally SoftSerial will replace input via USB from the IDE monitor. UART and 433MHz connection between another UNO with a three axis joystick and the UNO running the motors has already been tested.

Please don't give me hints. If I need help parsing speed data for the four motors I'll start a new thread. Gotta try it myself first.

// Adafruit Motor Shield

#include <Adafruit_MotorShield.h>
#include <C:\Users\feral\Documents\Arduino\Monitor_Input\Monitor_Input.ino>

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();

Adafruit_DCMotor *motRF = AFMS.getMotor(1);
Adafruit_DCMotor *motRR = AFMS.getMotor(2);
Adafruit_DCMotor *motLR = AFMS.getMotor(3);
Adafruit_DCMotor *motLF = AFMS.getMotor(4);

int speed[4] = {80, 120, 80, 120};  // 0 <= n <= 255
int wheel[4] = {0, 0, 0, 0};        // fore (1), rev (2), stop (4)
int dir = 0;  // compass directions, 1 to 16 cw & 17/18 rot

void setup() {
  Serial.begin(9600); // Set up Serial library at 9600 bps
  AFMS.begin(1000);   // PWM Frequency 1.0KHz
}

void loop() {
  recvWithEndMarker();
  showNewNumber();
  if (dataNumber != 0){
    dir = dataNumber;
    doWheels();
  }

    motLFgo();
    motLRgo();
    motRRgo();
    motRFgo();
}

// ===============================

void setWheel(int wheelLF, int wheelLR, int wheelRR, int wheelRF) {
   wheel[0] = wheelLF;
   wheel[1] = wheelLR;
   wheel[2] = wheelRR;
   wheel[3] = wheelRF;
}

void doWheels() {
  switch (dir) {
    case 1:  setWheel(1, 1, 1, 1); break;  // N
    case 2:  setWheel(1, 1, 1, 1); break;  // NNE
    case 3:  setWheel(4, 1, 4, 1); break;  // NE
    case 4:  setWheel(2, 1, 2, 1); break;  // ENE
    case 5:  setWheel(2, 1, 2, 1); break;  // E
    case 6:  setWheel(2, 1, 2, 1); break;  // ESE
    case 7:  setWheel(2, 4, 2, 4); break;  // SE
    case 8:  setWheel(2, 2, 2, 2); break;  // SSE
    case 9:  setWheel(2, 2, 2, 2); break;  // S
    case 10: setWheel(2, 2, 2, 2); break;  // SWS
    case 11: setWheel(4, 2, 4, 2); break;  // SW
    case 12: setWheel(1, 2, 1, 2); break;  // WSW
    case 13: setWheel(1, 2, 1, 2); break;  // W
    case 14: setWheel(1, 2, 1, 2); break;  // WNW
    case 15: setWheel(1, 4, 1, 4); break;  // NW
    case 16: setWheel(1, 1, 1, 1); break;  // NWN
    case 17: setWheel(2, 2, 1, 1); break;  // CW
    case 18: setWheel(1, 1, 2, 2); break;  // CCW
    default: setWheel(4, 4, 4, 4); break;  // All Stop
  }
}
void motLFgo() {
  motLF ->setSpeed(speed[0]);
  motLF ->run(wheel[0]);}

void motLRgo() {
  motLR ->setSpeed(speed[1]);
  motLR ->run(wheel[1]);}

void motRRgo() {
  motRR ->setSpeed(speed[2]);
  motRR ->run(wheel[2]);}

void motRFgo() {
  motRF ->setSpeed(speed[3]);
  motRF ->run(wheel[3]);}

Tried it once and liked it. The final neatness would be to use a for loop to load the four wheel spin directions but I get an error message. It's at the end of this little rave. Hope it's ok to include a few stripped down code fragments when targetting a specific thingumy.

int wheel[4] = {4, 4, 4, 4};  // fore (1), rev (2), stop (4)
int dir = 0;    // compass directions, 1 to 16 cw & 17/18 rot
#define for  1  // FORWARD in Adafruit_MotorShield.cpp
#define rev  2  // BACKWARD in Adafruit_MotorShield.cpp
#define halt 4  // RELEASE in Adafruit_MotorShield.cpp

int wheels[19][4] {
  {halt, halt, halt, halt},   // All Stop
  {for,  for,  for,  for },   // N
  {for,  for,  for,  for },   // NNE
  {halt, for,  halt, for },   // NE
  {rev,  for,  rev,  for },   // ENE
 . , , etc
 {rev,  rev,  for,  for },   // CW
 {for,  for,  rev,  rev }    // CCW
};

This just below works when I make dir = a compass direction (1 to 16). It loads the active wheel rotation array from the 2D array of options for various compass cardinal points.

  wheel[0] = wheels[dir][0];
  wheel[1] = wheels[dir][1];
  wheel[2] = wheels[dir][2];
  wheel[3] = wheels[dir][3];

but loading wheel[4] array one item at a time in a for loop gives an error - "expected primary-expression before 'int'"

I can't find an online reference that explains it at a low enough C++ beginner level.

  for (int i = 0; i < 4; i++) {
    wheel[i] = wheels[dir][i];
  }

OK.

The two snippets are insufficient for analysis. Please post a complete sketch that provides context.

Don't worry if it is 99.44 percent the code you already posted. Each time you post code, a complete sketch, This saves errors we would make if you say it like "I did this after line 43" or whatever. Fraught.

Either your actual sketch, or a minimum size example that shows the same error. That error is the kind that can start coming up if you miss a semicolon or make another inadvertent change nearby, or even not nearby.

What you posted should work.

But here's the best news… if you post a complete sketch, it is almost certain we will see that you have no need to copy out that vector of four values.

@alto777 said "To invoke [a command], you would pass the row number."

I think you might be able to see to this end. Let me say that

   wheels[n]

is an array of four integers, so if you had function

void spinTheseWheels(int wheelArray[]) { ... 

or a bit differently

void spinTheseWheels(int *wheelArray) { ... 

expecting to be passed your current wheel array as you set it up

// after copying from rom 11 into wheel, spin them
  spinTheseWheels(wheel);

you could instead just

  spinTheseWheels(wheels[11]);

So see if that makes sense. Post as I suggest and I can be more certain and point out exactly where you can avoid the explicit copying.

That's what pointers are for.

int         x             ;  // integer

int          y       [4]     ;  // 4 integers array

int       z[12]          [4]      ;  // 12 array of 4 integers.

C usage mimics declaration, another jewel to admire.

x    is an integer

y is an array of four integers 

y[2] is an integer

z[7][2]  is an integer and... 

z[9]  is an array of four integers

I'm overheated now and inconvenienced, so I may have bungled part of this - I like to test anything I say, haven't yet on this.

I'm sure by the time I look again you'll be flying or someone will have fixed me up.

L8R

a7

The whole code with the for loop commented out following the four individual lines in the format -
"wheel[n] = wheels[dir][m];

It uses example 5 from a great tutorial I found for parsing serial input -

Serial input is in the format <speed1, speed2, speed3, speed4, dir>

// Adafruit Motor Shield

#include <Adafruit_MotorShield.h>

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *motRF = AFMS.getMotor(1);
Adafruit_DCMotor *motRR = AFMS.getMotor(2);
Adafruit_DCMotor *motLR = AFMS.getMotor(3);
Adafruit_DCMotor *motLF = AFMS.getMotor(4);

int speed[4] = {0, 0, 0, 0};  // 0 <= n <= 255
int wheel[4] = {4, 4, 4, 4};  // fore (1), rev (2), stop (4)
int dir = 0;    // compass directions, 1 to 16 cw & 17/18 rot
#define for  1  // FORWARD in Adafruit_MotorShield.cpp
#define rev  2  // BACKWARD in Adafruit_MotorShield.cpp
#define halt 4  // RELEASE in Adafruit_MotorShield.cpp

int wheels[19][4] {
  {halt, halt, halt, halt},   // All Stop
  {for,  for,  for,  for },   // N
  {for,  for,  for,  for },   // NNE
  {halt, for,  halt, for },   // NE
  {rev,  for,  rev,  for },   // ENE
  {rev,  for,  rev,  for },   // E
  {rev,  for,  rev,  for },   // ESE
  {rev,  halt, rev,  halt},   // SE
  {rev,  rev,  rev,  rev },   // SSE
  {rev,  rev,  rev,  rev },   // S
  {rev,  rev,  rev,  rev },   // SSW
  {halt, rev,  halt, rev },   // SW
  {for,  rev,  for,  rev },   // WSW
  {for,  rev,  for,  rev },   // W
  {for,  rev,  for,  rev },   // WNW
  {for,  halt, for,  halt},   // NW
  {for,  for,  for,  for },   // NNW
  {rev,  rev,  for,  for },   // CW
  {for,  for,  rev,  rev }    // CCW
};

// Handle data input via serial
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];     // temporary array for use when parsing
boolean newData = false;

void setup() {
  Serial.begin(9600); // Set up Serial library at 9600 bps
  AFMS.begin(1000);   // PWM Frequency 1.0KHz
}

void loop() {
  recvWithStartEndMarkers();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    // this temporary copy is necessary to protect the original data
    //   because strtok() used in parseData() replaces the commas with \0
    parseData();
    showParsedData();
    newData = false;
  }

  wheel[0] = wheels[dir][0];
  wheel[1] = wheels[dir][1];
  wheel[2] = wheels[dir][2];
  wheel[3] = wheels[dir][3];
//  for (int i = 0; i < 4; i++) {
//    wheel[i] = wheels[dir][i];
//  }

  motLFgo();
  motLRgo();
  motRRgo();
  motRFgo();
}

// Functions ================================

void motLFgo() {
  motLF ->setSpeed(speed[0]);
  motLF ->run(wheel[0]);}

void motLRgo() {
  motLR ->setSpeed(speed[1]);
  motLR ->run(wheel[1]);}

void motRRgo() {
  motRR ->setSpeed(speed[2]);
  motRR ->run(wheel[2]);}

void motRFgo() {
  motRF ->setSpeed(speed[3]);
  motRF ->run(wheel[3]);}

// Data input
void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void parseData() {      // split the data into its parts
  char * strtokIndx;  // this is used by strtok() as an index

  strtokIndx = strtok(tempChars,","); // get the first part - the string
  speed[0] = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // continue where the previous call left off
  speed[1] = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  speed[2] = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  speed[3] = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ",");
  dir = atoi(strtokIndx);         // convert this part to an integer
}

void showParsedData() {
  Serial.print("speed [0]:");
  Serial.print(speed[0]);
  Serial.print("  [1]:");
  Serial.print(speed[1]);
  Serial.print("  [2]:");
  Serial.print(speed[2]);
  Serial.print("  [3]:");
  Serial.print(speed[3]);
  Serial.print("  dir:");
  Serial.println(dir);
}

I can't look at the code, but a friend spotted this obvious (!) flaw

#define for  1  // FORWARD in Adafruit_MotorShield.cpp

for is a reserved word. The C/C++ preprocessor lets you do really dumb things, like redeine the very meaning of "for".

Use another name for it: For, forward, forrrrr &c. Anything but for!

It's why ppl don't like # define, and use instead

const byte Forward = 1;

Your line of code ended up as

  1 (int i = 0; i < 4; i++) {

which is not syntactically valid.

a7

OK my friend who will not be named looked.

Change the real array wheel to a pointer.

int *wheel;

Change either copying code to make wheel point to the command you want

//  wheel[0] = wheels[dir][0];
//  wheel[1] = wheels[dir][1];
//  wheel[2] = wheels[dir][2];
//  wheel[3] = wheels[dir][3];

//  for (int i = 0; i < 4; i++) {
//    wheel[i] = wheels[dir][i];
//  }

  wheel = wheels[dir];

Just make sure you never use wheel until it has been assigned a plausible value.

This would be very slick except you've relied on global variables. Nothing wrong with that, as a beginner or in a small sketch, but you should transition away from using them where you could do without.

Now here, you may want to get your for (1, haha) loop working first. We can't test anything from under the umbrella.

a7

Changing it to fow fixed the for loop problem. Please thank your unnamed friend. And yourself.