I2C works with fixed size byte arrays.
Single bytes for commands should be sufficient. For positions you might need int16_t or even bigger numbers. Unsigned positions relative to (above) zero might make things easier, eventually (?)
As you have the same architecture on both sides, mapping of byte arrays to bigger numbers via union will work well.
If both devices are the same, are configured the same, and respond the same, then it is impossible to tell if there is one, two, or four hundred.
However if there are differences between the two devices you will get corrupt data.
I2C is an open-drain protocol. For a device to send a 0 it pulls the data line low. For it to send a 1 it lets the pullup ...
It's my understanding that duplicate I2C addresses prevent the master from communicating from the slaved devices, so the answer is no.
Instead, connect the devices one at a time, run the I2C scanner, note the address for each, and take note of any duplicate addresses.
Strings (aka byte arrays of arbitrary length) are perfect for asynchronous and full duplex protocols like UART, essentially because those are no master-slave protocols. Here, both master and slave can transmit a byte stream independent of each other at any time and with any length.
But using strings on I2C is quite uncommon. As I2C is a master-slave bus ...
I added pull-up resistors to the board and it started working. Turns out that the boards weren't well designed and the I2C lines were pulled up to 1.8V instead of Vin. By removing the pull-ups and adding pull-ups to Vin, the circuit started functioning. The circuit worked with Mega because it has in-built Pull-up Resistors.