Basically, I'm building some code in which an array of objects (I've made the object myself) need to be accessible class wide, but initialized after some other steps. This is what I've made:
The base object
unsigned char stepPin;
unsigned char dirPin;
unsigned char sensorPin;
const char* ident;
//Object
StepperMotor :: StepperMotor(const unsigned char _stepPin,
const unsigned char _dirPin,
const unsigned char _sensorPin,
const char* _ident)
{
stepPin = _stepPin;
dirPin = _dirPin;
sensorPin = _sensorPin;
ident = _ident;
std::cout << "Motor " << ident << ": Step Pin - " << (int)stepPin << " | Direction Pin - " << (int)dirPin << std::endl;
}
The object manager
#include "stepperMotor.h"
#include <iostream>
#include <wiringPi.h>
#include <thread>
#include <cstdlib>
#include <vector>
#include "stepperManager.h"
StepperMotor motors[] = {
{7, 15, 16, "HS"},
{0, 1, 2, "HL"},
{3, 4, 5, "HP"},
{12, 13, 6, "CS"},
{14, 10, 11, "VP"},
{21, 22, 26, "TC"},
{23, 24, 27, "TR"},
{25, 28, 29, "IN"}
};
StepperManager::StepperManager()
{
for (int i = 0; i < 8; i++){
motors[i].dumpData();
}
}
Now to the actual problem...
After the initial declaration, all the elements in the array become the last element. You can see this by looking at the output when it's run:
Output:
Motor HS: Step Pin - 7 | Direction Pin - 15
Motor HL: Step Pin - 0 | Direction Pin - 1
Motor HP: Step Pin - 3 | Direction Pin - 4
Motor CS: Step Pin - 12 | Direction Pin - 13
Motor VP: Step Pin - 14 | Direction Pin - 10
Motor TC: Step Pin - 21 | Direction Pin - 22
Motor TR: Step Pin - 23 | Direction Pin - 24
Motor IN: Step Pin - 25 | Direction Pin - 28
Declare the motor man
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
So, I don't fully understand why this is happening, I've tried making the array static, and switching to vectors instead, but none of it has helped. I'm afraid that I just don't know enough about the language to find the issue on my own.
EDIT
It was pointed out that I missed the actual run code. Sorry about that guys.
This is the "main" file that implements the objects.
#include <iostream> // For cout and cerr
#include <cstdlib> // For atoi()
#include <cstring>
#include "stepperManager.h"
int main(int argc, char **argv)
{
std::cout << "Declare the motor man" << std::endl;
StepperManager motorMan;
return 0;
}
Here you want to learn a bit more about classes and how they work. In StepperMotor's source file, you're defining file-scope global variables with external linkage. Every time you construct a StepperMotor, you're overwriting those same variables, so all StepperMotors are effectively accessing the same values (and hence the behavior you're seeing).
Since you have a C# background, it's like you're using static member variables for StepperMotors here. You want non-static member variables. Simple example:
Foo.h:
// Foo.h
#ifndef FOO_H
#define FOO_H
class Foo
{
public:
explicit Foo(int value);
void print_value() const;
private:
int member_variable;
}
#endif
Foo.cpp:
// Foo.cpp
#include "Foo.h"
#include <iostream>
using namespace std;
Foo::Foo(int value): member_variable(value)
{
}
void Foo::print_value() const
{
cout << member_variable << endl;
}
main.cpp:
// main.cpp
#include "Foo.h"
int main()
{
Foo f1(123);
Foo f2(456);
Foo f3(789);
f1.print_value();
f2.print_value();
f3.print_value();
}
Output:
123
456
789
Also I see some thread usage in your example. I'd suggest, at this point, that this is like juggling razor blades. You want to kind of stick to the basics first, get the hang of the language, debugger, and then you can babystep your way towards parallelizing execution, micro-tuning with a profiler in hand, etc.
You've declared four global variables, which you change every time a StepperMotor is created. Instead, you want these to be class members, so that each object has its own copy of them, independent of those in other objects:
class StepperMotor {
unsigned char stepPin;
unsigned char dirPin;
unsigned char sensorPin;
const char* ident;
// and constructors, member functions, etc.
};
I think there should be something like this in your steppermotor.h
class StepperMotor{
//some more stuff
public:
unsigned char stepPin;
unsigned char dirPin;
unsigned char sensorPin;
const char* ident;
unsigned int stepVal;
}
This is how member variables are declared in c++.
I think it might be usefull though to read some c++ tutorial, to learn the basics.
Related
So I am using the c/c++ sdk for the pi pico to try and send data to a raspberry pi 4 over spi. On the Pi 4 I am using wiringPi library for the SPI functionality. However when I send the value I want to send on SPI from my PICO (which is being sent as I checked with a scope), to the Pi 4, the pi 4 receives the information wrong, such as prints seemingly random characters instead of the intended value.
Any help with this would be greatly appreciated, see below the code from my Pico and my Pi 4, I am expecting the value of 5 to be received. I have changed the len parameter in both the pico and pi 4 to 1,2,4 and 8 and all gives the same result.
#include <iostream>
#include <stdio.h>
#include "hardware/uart.h"
#include "pico/stdlib.h"
#include "hardware/spi.h"
using namespace std;
//-------SPI Ports-------
#define SPI_PORT spi0
#define SPI_PORT_1 spi1
//-----------------------
//-------Port 0 SPI pins--------
#define MOSI 3
#define MISO 4
#define SCK 2
#define CS 5
//------------------------------
//-------UART Setup-------
#define UART_ID uart0
#define BAUD_RATE_UART 115200
#define UART_TX_PIN 0
#define UART_RX_PIN 1
//------------------------
uint8_t test_send;
uint8_t test_read[3];
int main() {
stdio_init_all();
//-------------------UART init------------------
uart_init(UART_ID, BAUD_RATE_UART);
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
//----------------------------------------------
spi_init(SPI_PORT, 500000);
gpio_init(CS);
gpio_set_dir(CS, GPIO_OUT);
gpio_put(CS, 1);
spi_set_format(SPI_PORT, 12, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
gpio_set_function(SCK, GPIO_FUNC_SPI);
gpio_set_function(MOSI, GPIO_FUNC_SPI);
gpio_set_function(MISO, GPIO_FUNC_SPI);
test_send = 5;
while(1){
//printf("here top");
gpio_put(CS, 0);
spi_write_blocking(SPI_PORT, &test_send, 1);
//spi_read_blocking(SPI_PORT, 0, test_read, 1);
gpio_put(CS, 1);
//printf("here\n");
}
}
And here is the code I am using for Pi 4
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
//#include </home/dean21/Documents/mosquitto-master/include/mosquitto.h>
#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <errno.h>
#include <string.h>
using namespace std;
static const int CHANNEL = 0;
unsigned char holder[100];
unsigned char test;
static int myFd;
int main(){
wiringPiSetupGpio();
//holder[0] = 0x5;
unsigned char result;
wiringPiSPISetup (CHANNEL, 500000);
// even though this function is for read and write im only using it as a read
while(1){
wiringPiSPIDataRW(CHANNEL, //Enable / CS pin
holder, //Data
1); //Lenth
cout << "holder value is: " << holder << endl;
//delay(1000);
}
}
output example looks like this, when it should be receiving the value of 5
holder value is:(
holder value is:
holder value is:#
holder value is:P
holder value is:
holder value is:
holder value is:
There are a few problems with your code.
Your unsigned char holder[100]; seems to be uninitialized, so there is no way to know what data you have in those 100 bytes. You should always initialize your data.
It looks like you are only reading 1 byte at a time into holder, but you are trying to print the whole buffer. Your probably only want to cout << holder[0]; . What seems to be happening is that it will try to print until it gets to a \0 or 0 but since holder is not initialized the first \0 is in some random place.
I am afraid that you have misunderstood the SPI protocol. In SPI you have one master and a number of slaves, what you have is two masters yelling at each other - that is never going to work.
As far as I know, there are no ready driver that allows you to turn the Raspberry Pi 4 into a SPI slave, but a search found support for turning your Raspberry Pi Pico into a SPI slave: https://github.com/raspberrypi/pico-examples/tree/master/spi/spi_master_slave
Try to read up on the SPI protocol and then see if you can rethink what you want to work with that. One issue is that a SPI slave is written to or read from by the master, but the slave never initiates a transfer (a workaround is to use a GPIO as a "I have data ready" signal, some SPI ICs use that method so that the master doesn't have to constantly poll for new data).
guys. I am learning about the Producer-Consumer Problem. My professor gave us an example code using a classical int array to share resources between the two threads. It works as expected, however, I wanted to try it using std:list class from C++ and it doesn't work as expected. The consumer seems not to respect sem_wait(&full); so it tries to consume many times when there is nothing in the shared list.
Original code with array buffer
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define N 2
#define TRUE 1
int buffer[N], in = 0, out = 0;
sem_t empty, full, mutexC, mutexP;
void *producer(void *arg) {
while(TRUE) {
sleep(rand()%5);
sem_wait(&empty);
sem_wait(&mutexP);
buffer[in] = rand() % 100;
printf("Producing buffer[%d] = %d\n", in, buffer[in]);
in= (in+1) % N;
sem_post(&mutexP);
sem_post(&full);
}
}
void *consumer(void *arg) {
while(TRUE) {
sleep(rand()%5);
sem_wait(&full);
sem_wait(&mutexC);
printf("Consuming buffer[%d] = %d\n", out, buffer[out]);
out = (out+1) % N;
sem_post(&mutexC);
sem_post(&empty);
}
}
int main(int argc, char *argv[ ]) {
pthread_t cons, prod;
sem_init(&mutexC, 0, 1);
sem_init(&mutexP, 0, 1);
sem_init(&empty, 0, N);
sem_init(&full, 0, 0);
pthread_create(&prod, NULL, producer, NULL);
pthread_create(&cons, NULL, consumer, NULL);
pthread_exit(0);
}
My implementation with list:
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <list>
#define TRUE 1
#define N 2
using namespace std;
list<int> sharedList;
sem_t empty, full, mutexC, mutexP;
void *producer(void *arg) {
while(TRUE) {
sleep(rand()%5);
sem_wait(&empty);
sem_wait(&mutexP);
int prod = rand() % 100;
cout << "producing: " << prod << endl;
sharedList.push_back(prod);
sem_post(&mutexP);
sem_post(&full);
}
}
void *consumer(void *arg) {
while(TRUE) {
sleep(rand()%5);
sem_wait(&full);
sem_wait(&mutexC);
if (!sharedList.empty()) {
cout << "consuming: ";
cout << sharedList.front() << endl;
sharedList.pop_front();
} else {
cout << "not possible to consume" << endl;
}
sem_post(&mutexC);
sem_post(&empty);
}
}
int main(int argc, char *argv[ ]) {
pthread_t cons, prod;
sem_init(&mutexC, 0, 1);
sem_init(&mutexP, 0, 1);
sem_init(&empty, 0, N);
sem_init(&full, 0, 0);
pthread_create(&prod, NULL, producer, NULL);
pthread_create(&cons, NULL, consumer, NULL);
pthread_exit(0);
}
The - unexpected - logs from my implementation:
producing: 73
consuming: 73
not possible to consume
producing: 44
consuming: 44
producing: 9
producing: 65
consuming: 9
producing: 87
consuming: 65
consuming: producing: 29
87
not possible to consume
consuming: 29
producing: 9
producing: 60
consuming: 9
producing: 78
Can somebody explain to me what is happening?
Thanks in advance!
In the first place, note that in both programs:
with only one producer ever contending for semaphore mutexP, that semaphore serves no useful purpose.
Likewise, with only one consumer ever contending for semaphore mutexC, that serves no useful purpose either.
Now, consider what purpose is served in your first program by initializing semaphore empty with value 2 instead of value 1: I presume that you will agree that doing so allows the producer to run concurrently with the consumer, one position ahead. This is ok because accesses to different array elements do not conflict.
But when your storage is a std::list instead of an array, it is not ok for two threads to manipulate it concurrently if one of them modifies it. There are several complementary ways to look at it, among them:
a std::list is a single object, access to which must be synchronized, whereas an array is merely an aggregate of its elements, not a distinct object of its own as far as synchronization requirements are concerned.
a std::list has members -- maintaining the current list size, for example -- that are used by all manipulations, access to which must be synchronized.
However you choose to look at it, you must ensure that the std::list cannot be accessed concurrently by two threads if one of those threads modifies it.
Follow up
Although the second code does have its errors, it turns out that macOS does ignore sem_wait(). I tried to initialize all the semaphores with 0 expecting the program to enter a deadlock, but it actually didn't. So, if running on macOS, please refer to this answer
rand() % 6 can generate some interesting sequences; so the spurious wakeup not possible to consume is to be expected.
Beyond that, the only confusing bit is:
consuming: producing: 29
87
not possible to consume
Which isn't that confusing; the io statements interleave. If they didn't, you would see this as:
consuming: 87
producing: 29
not possible to consume
where the last statement would be a result of checking the condition just before the producer created 29.
I have this code in the setup for my Arduino to create a filename using the date. It is working however there is a problem.
#include <DS3231.h>
#include <SD.h>
#include <SPI.h>
#include <dht.h>
dht DHT;
Time now;
int dt;
int t;
unsigned int interation = 1;
char filename[12];
DS3231 rtc(SDA, SCL);
void setup() {
Serial.begin(9600);
rtc.begin(); // Initialize the rtc object
rtc.setDOW(THURSDAY); // Set Day-of-Week to SUNDAY
rtc.setTime(21, 48, 0); // Set the time to 12:00:00 (24hr format)
rtc.setDate(10, 11, 2017); // Set the date to January 1st, 2014
now = rtc.getTime();
String(String(now.year) + String(now.mon) + String(now.dow) + ".csv").toCharArray(filename, 12);
Serial.println(filename);
It is printing a string of the date but there is no leading zero in the month digit when it is a single digit.
The code prints this 2017111.csv instead of 20170111.csv. How can I fix this?
You need an if statement to test if the number is less than 10 and if so add your own 0.
String myMonthString = "";
int mon = now.mon;
if(mon < 10){
myMonthString += '0';
}
myMonthString += mon;
A far more elegant solution would be to use sprintf. This also doesn't use the String class which can do some bad things on little microcontrollers and is generally to be avoided on Arduino.
char fileName[12];
sprintf(fileName, "%d%02d%02d.csv", now.year, now.mon, now.dow);
I am looking for any library of example parsing a binary msg in C++. Most people asks for reading a binary file, or data received in a socket, but I just have a set of binary messages I need to decode. Somebody mentioned boost::spirit, but I haven't been able to find a suitable example for my needs.
As an example:
9A690C12E077033811FFDFFEF07F042C1CE0B704381E00B1FEFFF78004A92440
where first 8 bits are a preamble, next 6 bits the msg ID (an integer from 0 to 63), next 212 bits are data, and final 24 bits are a CRC24.
So in this case, msg 26, I have to get this data from the 212 data bits:
4 bits integer value
4 bits integer value
A 9 bit float value from 0 to 63.875, where LSB is 0.125
4 bits integer value
EDIT: I need to operate at bit level, so a memcpy is not a good solution, since it copies a number of bytes. To get first 4-bit integer value I should get 2 bits from a byte, and another 2 bits from the next byte, shift each pair and compose. What I am asking for is a more elegant way of extracting the values, because I have about 20 different messages and wanted to reach a common solution to parse them at bit level.
And so on.
Do you know os any library which can easily achieve this?
I also found other Q/A where static_cast is being used. I googled about it, and for each person recommending this approach, there is another one warning about endians. Since I already have my message, I don't know if such a warning applies to me, or is just for socket communications.
EDIT: boost:dynamic_bitset looks promising. Any help using it?
If you can't find a generic library to parse your data, use bitfields to get the data and memcpy() it into an variable of the struct. See the link Bitfields. This will be more streamlined towards your application.
Don't forget to pack the structure.
Example:
#pragma pack
include "order32.h"
struct yourfields{
#if O32_HOST_ORDER == O32_BIG_ENDIAN
unsigned int preamble:8;
unsigned int msgid:6;
unsigned data:212;
unsigned crc:24;
#else
unsigned crc:24;
unsigned data:212;
unsigned int msgid:6;
unsigned int preamble:8;
#endif
}/*__attribute__((packed)) for gcc*/;
You can do a little compile time check to assert if your machine uses LITTLE ENDIAN or BIG ENDIAN format. After that define it into a PREPROCESSOR SYMBOL::
//order32.h
#ifndef ORDER32_H
#define ORDER32_H
#include <limits.h>
#include <stdint.h>
#if CHAR_BIT != 8
#error "unsupported char size"
#endif
enum
{
O32_LITTLE_ENDIAN = 0x03020100ul,
O32_BIG_ENDIAN = 0x00010203ul,
O32_PDP_ENDIAN = 0x01000302ul
};
static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order =
{ { 0, 1, 2, 3 } };
#define O32_HOST_ORDER (o32_host_order.value)
#endif
Thanks to code by Christoph # here
Example program for using bitfields and their outputs:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <memory.h>
using namespace std;
struct bitfields{
unsigned opcode:5;
unsigned info:3;
}__attribute__((packed));
struct bitfields opcodes;
/* info: 3bits; opcode: 5bits;*/
/* 001 10001 => 0x31*/
/* 010 10010 => 0x52*/
void set_data(unsigned char data)
{
memcpy(&opcodes,&data,sizeof(data));
}
void print_data()
{
cout << opcodes.opcode << ' ' << opcodes.info << endl;
}
int main(int argc, char *argv[])
{
set_data(0x31);
print_data(); //must print 17 1 on my little-endian machine
set_data(0x52);
print_data(); //must print 18 2
cout << sizeof(opcodes); //must print 1
return 0;
}
You can manipulate bits for your own, for example to parse 4 bit integer value do:
char[64] byte_data;
size_t readPos = 3; //any byte
int value = 0;
int bits_to_read = 4;
for (size_t i = 0; i < bits_to_read; ++i) {
value |= static_cast<unsigned char>(_data[readPos]) & ( 255 >> (7-i) );
}
Floats usually sent as string data:
std::string temp;
temp.assign(_data+readPos, 9);
flaot value = std::stof(temp);
If your data contains custom float format then just extract bits and do your math:
char[64] byte_data;
size_t readPos = 3; //any byte
float value = 0;
int i = 0;
int bits_to_read = 9;
while (bits_to_read) {
if (i > 8) {
++readPos;
i = 0;
}
const int bit = static_cast<unsigned char>(_data[readPos]) & ( 255 >> (7-i) );
//here your code
++i;
--bits_to_read;
}
Here is a good article that describes several solutions to the problem.
It even contains the reference to the ibstream class that the author created specifically for this purpose (the link seems dead, though). The only other mention of this class I could find is in the bit C++ library here - it might be what you need, though it's not popular and it's under GPL.
Anyway, the boost::dynamic_bitset might be the best choice as it's time-tested and community-proven. But I have no personal experience with it.
I'm baffled. I have an identical program being uploaded to two different Arduino boards. It's in C++.
It's a much larger program, but I'm cutting it down to only the problematic part. Basically, I have a "host" Arduino and a "rover" Arduino communicating wirelessly. There are multiple rover units, but the problem is only happening on one of them. The rovers have motors that need to be calibrated, so I have static variables in my Motor namespace to hold those calibration values. To prevent having to change these values in the source code, recompile and reupload every time I want to calibrate it, I'm using the wireless system to allow the host to send calibration values to the rover at runtime.
Here's the problem: on one rover, the values aren't being updated if I call the ChangeSpeed method, but they do get updated if I modify the variables directly.
Let me stress that it works fine on four out of five rovers. The problem is happening on exactly one rover. The code being uploaded to each rover is identical.
The following code is causing a problem:
Motor.h:
namespace Motor
{
static unsigned char left_speed = 0;
static unsigned char right_speed = 0;
void ChangeSpeed(unsigned char, unsigned char);
}
Motor.cpp:
void Motor::ChangeSpeed(unsigned char l_speed, unsigned char r_speed)
{
left_speed = l_speed;
right_speed = r_speed;
soft.println("Change speed: " + String(left_speed) + ", " + String(right_speed));
}
Main.cpp:
void UpdateSpeedValuesBad(unsigned char l_speed, unsigned char r_speed)
{
Motor::ChangeSpeed(l_speed, r_speed);
soft.println("Motor write: " + String(l_speed) + ", " + String(r_speed));
}
void UpdateSpeedValuesGood(unsigned char l_speed, unsigned char r_speed)
{
Motor::left_speed = l_speed;
Motor::right_speed = r_speed;
soft.println("Motor write: " + String(l_speed) + ", " + String(r_speed));
}
void ReturnSpeedValues()
{
soft.println("Motor read: " + String(Motor::left_speed) + ", " + String(Motor::right_speed));
}
Case 1:
On the bad rover, the host invokes UpdateSpeedValuesBad(5, 5), and then invokes ReturnSpeedValues. The output is:
Change speed: 5, 5
Motor write: 5, 5
Motor read: 0, 0
Case 2:
On the bad rover, the host invokes UpdateSpeedValuesGood(5, 5), and then invokes ReturnSpeedValues. The output is:
Motor write: 5, 5
Motor read: 5, 5
Case 3:
On a good rover, the host invokes UpdateSpeedValuesBad(5, 5), and then invokes ReturnSpeedValues. The output is:
Change speed: 5, 5
Motor write: 5, 5
Motor read: 5, 5
Am I doing something fundamentally wrong? I come from a C# background so C++ is pretty alien to me. I have no idea if I'm doing something that has undefined behaviour.
Edit: If I shove everything into one single file, it works fine. It only fails once I split it up across a header file and a cpp file.
Main.cpp:
#include <SoftwareSerial.h>
SoftwareSerial soft(9, 10);
namespace Motor
{
static int left_speed = 0;
void ChangeSpeed(unsigned char);
}
void Motor::ChangeSpeed(unsigned char l_speed)
{
left_speed = l_speed;
soft.println("Change speed: " + String(left_speed));
}
void setup()
{
soft.begin(9600);
soft.println("Before: " + String(Motor::left_speed));
Motor::ChangeSpeed(5);
soft.println("Bad attempt: " + String(Motor::left_speed));
Motor::left_speed = 5;
soft.println("Good attempt: " + String(Motor::left_speed));
}
void loop()
{
}
Output:
Before: 0
Change speed: 5
Bad attempt: 5
Good attempt: 5
Edit 2: I dove into the assembly and found this for the bad case. It's using different memory addresses based on whether I call ChangeSpeed or I update the values directly. Anyone know why that would be? Is it a compiler bug or is it not guaranteed that the addresses will be the same?
000000a8 <setup>:
{
Motor::ChangeSpeed(5, 6);
a8: 85 e0 ldi r24, 0x05 ; 5
aa: 66 e0 ldi r22, 0x06 ; 6
ac: 0e 94 5f 00 call 0xbe ; 0xbe <_ZN5Motor11ChangeSpeedEhh>
Motor::left_speed = 5;
b0: 85 e0 ldi r24, 0x05 ; 5
b2: 80 93 00 01 sts 0x0100, r24
Motor::right_speed = 6;
b6: 86 e0 ldi r24, 0x06 ; 6
b8: 80 93 01 01 sts 0x0101, r24
}
bc: 08 95 ret
000000be <_ZN5Motor11ChangeSpeedEhh>:
void Motor::ChangeSpeed( unsigned char l_speed, unsigned char r_speed )
{
left_speed = l_speed;
be: 80 93 02 01 sts 0x0102, r24
right_speed = r_speed;
c2: 60 93 03 01 sts 0x0103, r22
c6: 08 95 ret
You should not make these variables static. A static global variable means the variable is local to the compilation unit (generally, the .cpp file that is being compiled) so if you have the static variable declared in a header file and include that header file in 3 different .cpp files that are compiled separately then you will have 3 independent versions of that variable, one for each .cpp file.
Instead, in the header file declare them as
namespace Motor {
extern unsigned char left_speed;
extern unsigned char right_speed;
void ChangeSpeed(unsigned char, unsigned char);
}
This tells the compiler that some file will provide a definition for these variables and to use that common shared definition.
Then, since the variables need to be defined exactly once (this is called the one definition rule) you should add the definition to Motor.cpp:
unsigned char Motor::left_speed = 0;
unsigned char Motor::right_speed = 0;
I chose Motor.cpp to hold the definition since this is where the definition of the ChangeSpeed function is.
In C++, the static keyword works much differently than in C#. It might be somewhat similar when used inside a class definition, but that is where the similarities end.
By declaring the variables static, you limit their range to the current code unit. In other words, by having static variables in your .h, you cause Motor.cpp and Main.cpp to have separate copies of those two variables.
Your case 1 modifies the Motor.cpp copies of those variables while outputs the ones from Main.cpp. Case 2 works only on Main.cpp copies so it works as expected. And if you shove everything into a single file, you just get one copy of those variables.
You should either:
Declare the variables as extern unsigned char left_speed, right_speed; in the header, and then declare the values as unsigned char left_speed = 0; in one of the .cpp files;
Declare the static variables in one of the .cpp files directly (e.g. Rotor.cpp) and use functions to get their values like you use one to set them.