Map() function acting bizarre

Hey everyone, I'm receiving some data over modbus and trying to map that value. Here is the code snippet responsible:

batchMassRegVal = modbusTCPServer.holdingRegisterRead(batchMassReg);
  while(batchMassRegVal == 0){
    batchMassRegVal = modbusTCPServer.holdingRegisterRead(batchMassReg);

    yield();
  }

  Serial.print("batchMassRegVal: ");
  Serial.println(batchMassRegVal);
  Serial.println();
  batchMassCalc = batchMassRegVal;
  batchMass = batchMassCalc / 10;

  fanSpeedRoastCalc = map(batchMassRegVal, 30, 180, 850, 1000);
  fanSpeedRoast = (fanSpeedRoastCalc/100);
  SV = map(batchMassRegVal, 30, 180, 18000, 24000);
  modbusTCPServer.holdingRegisterWrite(setpointReg, SV);

  Serial.print("Batch size: ");
  Serial.print(batchMass);
  Serial.println(" kg");
  Serial.print("Roast fan speed: ");
  Serial.println(fanSpeedRoast);
  Serial.print("Charge fan speed: ");
  Serial.println(fanSpeedCharge);
  Serial.print("Initial SV: ");
  Serial.println(SV);
  Serial.println();

  chargeDelay = map(batchMassRegVal, 30, 180, 8000, 15000);
  Serial.print("Charge delay: ");
  Serial.println(chargeDelay);
  dischargeDelay = map(batchMassRegVal, 30, 180, 9000, 25000);
  Serial.print("Discharge delay: ");
  Serial.println(chargeDelay);
  Serial.println();

And here is some example output:
image

As you see I'm getting a fanspeed of 8.0V, and the lowest possible should be 8.5V. Similar situation with dischargeDelay...
Any ideas what could be ****ing up?
batchMassRegVal is an int variable, and switching it over to long changes nothing.

There is so much that you haven't told us

Please post your full sketch that illustrates the problem.

Sorry can't do that :wink:
Also the sketch is very long so I doubt you'd want to read the whole thing haha.
But what is some essential info that I could have missed providing?
/ Einar

If you can't post the whole sketch for some reason then post a smaller but complete sketch that illustrates the problem

The declaration of the variables for a start, along with details of the libraries used

Ok, here is a heavily trimmed version of the code where I try to capture just the modbus functionality. In reality I have 8 different threads running. The board is the portenta machine control:

#include "mbed.h"

#include <Arduino_MachineControl.h>
#include <Ethernet.h>
#include <PortentaEthernet.h>
#include <SPI.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
#include <Wire.h>
#include <PID_v1.h>

using namespace machinecontrol;
using namespace rtos;
using namespace std::chrono;

int fanSpeedRoastCalc;
int fanSpeedChargeCalc;

float fanSpeedBase = 6.50;
float fanSpeedCharge = 8.50;
float fanSpeedRoast;
float fanSpeedCooling = 6.50;

int chargeDelay;
int dischargeDelay;

float batchMass;

//TIMING FUNCTIONALITY:

void waitWithoutDelayMS(int waitTimeMilliseconds){
  mbed::Timer timer1;
  timer1.start();

  int currentTime = 0;
  timer1.reset();
  while(currentTime < waitTimeMilliseconds){
    currentTime = duration_cast<milliseconds>(timer1.elapsed_time()).count();
    yield();
  }
}

//DEFINITION OF GENERAL MODBUS VARIABLES

constexpr unsigned long baudrate = 115200;
constexpr int predelay = 310;
constexpr int postdelay = 310; 

//DEFINITION OF MODBUS TCP VARIABLES

byte mac[] = {
  //Example: 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
  0x90, 0x2E, 0x16, 0xF4, 0xED, 0xB4
};

//Example IPAddress ip(192, 168, 1, 177);
IPAddress ip(192, 168, 1, 177);

EthernetServer ethServer(502);
EthernetClient client;

ModbusTCPServer modbusTCPServer;

int batchMassReg = 13;
int batchMassRegVal = 0;

void modbusTasks(){
  while(true){
    Serial.println("Searching for TCP client...");
    client = ethServer.available();
    if (client) {
      Serial.println("TCP client available.");
      modbusTCPServer.accept(client);
      if(client.connected()){
        Serial.println("TCP client connected.");
      }
      while (client.connected()) {
        modbusTCPServer.poll();
        yield();
      }
      Serial.println("TCP communication ended.");
    }
    yield();
  }  
}

//THREADS:

Thread modbusThread;

void setup() {

  Serial.begin(baudrate);

  Ethernet.begin(mac, ip);
  ethServer.begin();

  comm_protocols.init();
  comm_protocols.rs485Enable(true);
  comm_protocols.rs485.setDelays(predelay, postdelay);

  modbusTCPServer.begin(0); //address is 0
  ModbusRTUClient.begin(comm_protocols.rs485, baudrate, SERIAL_8N1);

  modbusTCPServer.configureHoldingRegisters(0, 19); //Configures 19 (0-18) holding registers.
  modbusTCPServer.holdingRegisterWrite(burnerReg, 1); //Sets burner to power 1

  modbusThread.start(modbusTasks);

}

void loop(){

  batchMassRegVal = modbusTCPServer.holdingRegisterRead(batchMassReg);
  while(batchMassRegVal == 0){
    batchMassRegVal = modbusTCPServer.holdingRegisterRead(batchMassReg);

    yield();
  }

  Serial.print("batchMassRegVal: ");
  Serial.println(batchMassRegVal);
  Serial.println();
  batchMassCalc = batchMassRegVal;
  batchMass = batchMassCalc / 10;

  fanSpeedRoastCalc = map(batchMassRegVal, 30, 180, 850, 1000);
  fanSpeedRoast = (fanSpeedRoastCalc/100);
  SV = map(batchMassRegVal, 30, 180, 18000, 24000);
  modbusTCPServer.holdingRegisterWrite(setpointReg, SV);

  Serial.print("Batch size: ");
  Serial.print(batchMass);
  Serial.println(" kg");
  Serial.print("Roast fan speed: ");
  Serial.println(fanSpeedRoast);
  Serial.print("Charge fan speed: ");
  Serial.println(fanSpeedCharge);
  Serial.print("Initial SV: ");
  Serial.println(SV);
  Serial.println();

  chargeDelay = map(batchMassRegVal, 30, 180, 8000, 15000);
  Serial.print("Charge delay: ");
  Serial.println(chargeDelay);
  dischargeDelay = map(batchMassRegVal, 30, 180, 9000, 25000);
  Serial.print("Discharge delay: ");
  Serial.println(chargeDelay);
  Serial.println();

  batchMassRegVal = 0 
}

It would have been very good if we have known this in the first place, and if you had posted in the correct section of the forum which is the portenta section. I suggest you move the there, use the big black pencil at the top of the first post to move it. Or I could do it for you if you want.

Well I deliberately did not post it there :joy: because that forum has a pretty low interaction level plus seeing portenta scares people off even if the problem may not be portenta specific...

Are you thinking that the result value is constrained between 850 and 1000? Well, it isn't..

Add

  fanSpeedRoastCalc = constrain(fanSpeedRoastCalc, 850, 1000);

and similar wherever necessary.

Are you thinking that the result value is constrained between 850 and 1000? Well, it isn't..

No, and that would be fine if it was going outside the limit in a predictable fashion. But then you would expect the input to be outside the original high and original low range no?

Note: I solved the fanSpeedRoast problem, it was due to fanSpeedRoastCalc being an Int and not a Float so that when I divided it by 100 it just rounded the number down.

However look at the outputs for chargeDelay and dischargeDelay map functions... why are they throwing this weird number 8466 when they have the same input and different output ranges :thinking:

Only because many members have no experience with that system and so they refrain from answering questions.

It seems we can't win.

If a member responds to something they would like to try on their own machine to trace your problem. Then finds out they haven't got that system to try it out with, then there is only a limited amount of help they can give. And then they get lambasted for not supplying useful help.

1 Like

When you divide fanSpeedRoastCalc by 100 it is using integer maths.
https://www.arduino.cc/reference/en/language/structure/arithmetic-operators/division/

  fanSpeedRoast = (fanSpeedRoastCalc / 100);

Change that line to:

  fanSpeedRoast = (fanSpeedRoastCalc / 100.0);

to ensure that floating point maths is used.

1 Like

If a member responds to something they would like to try on their own machine to trace your problem. Then finds out they haven't got that system to try it out with, then there is only a limited amount of help they can give

That's fair. I was secretly hoping that it was a fundamental problem in my understanding of the function and something a veteran could easily spot and correct on the fly :upside_down_face:

As regards to lambasting, in my opinion the amount of that in this thread is appropriately low...

1 Like

Correct, I did figure that out as mentioned above, but the problem with the chargeDelay and dischargeDelay map()'s still stands :slightly_frowning_face:

i get following

     30    850  18000   8000   9000
     40    860  18400   8466  10066
     50    870  18800   8933  11133
     60    880  19200   9400  12200
     70    890  19600   9866  13266
     80    900  20000  10333  14333
     90    910  20400  10800  15400
    100    920  20800  11266  16466
    110    930  21200  11733  17533
    120    940  21600  12200  18600
    130    950  22000  12666  19666
    140    960  22400  13133  20733
    150    970  22800  13600  21800
    160    980  23200  14066  22866
    170    990  23600  14533  23933
    180   1000  24000  15000  25000

using

int chargeDelay;
int dischargeDelay;
int batchMassRegVal = 0;
int fanSpeedRoastCalc;

int SV;

char s [90];

void
calc (
    int x )
{
        fanSpeedRoastCalc = map(x, 30, 180, 850, 1000);
        SV                = map(x, 30, 180, 18000, 24000);
        chargeDelay       = map(x, 30, 180, 8000, 15000);
        dischargeDelay    = map(x, 30, 180, 9000, 25000);

        sprintf (s, " %6d %6d %6d %6d %6d", x,
            fanSpeedRoastCalc, SV, chargeDelay, dischargeDelay);
        Serial.println (s);
}

void test ()
{
    calc ();
    for (batchMassRegVal = 30; batchMassRegVal <= 180; batchMassRegVal += 10)
        calc (batchMassRegVal);
}

void
setup (void)
{
    Serial.begin (9600);

    test ();
}

void loop (void) { }i
1 Like

Error

1 Like

Gosh darnit I'm a moron! :expressionless: :expressionless: :expressionless: