Building the new EVOIII router is still a long road to go and one of the major changes is the way the wire is controlled. It uses the wire feeder from the Pico designed by Alex Treseder.
The wire feeder has to steppers. One stepper drives the pulling side while the other one will monitor and keep the desired wire tension using the Servo42C driver in FOC mode.
The full wire unit will be controlled by this tiny ESP32 from Seeed. Next to it is a normal ESP32-Wroom board to get the size.

I want to program the driver using the G-EDM UI but well, there is no library available. The documentation is all there is and it looks pretty complicated. They do provide a closed source interface for windows but that doesn't help much.
Writing a library for this driver to be able to fully control it is everything but not noob friendly. And I mean it.
First it doesn't use normal integer value that are send around via UART. It uses hexadecimal values. And they are limited to 8bit. The format for sending data to the driver is like this:
slave_address command data1 [data2 data3 ...] checksum_modulo_256_8bit
slave_address command data1 [data2 data3 ...] checksum_modulo_256_8bit
If the data value exceeds the 8bit it needs to be split across multiple cells as big-endian byte array or something.
I don't have the driver yet and all this is just extracted from the documentation that shows this for the max torque setting (manual example sets the value to 600 = 0x258 = 02 58):

The command for setting the max torque to 1200 would look like this:
E0 A5 04 B0 39
Let's break that down.
E0 is the slave_address used to identify the driver.
A5 is the command to set the max torque
04 B0 is the tricky part. It is the formatting of 0x4B0 (Hex representation of 1200). A number larger 255 exceeds the uint8_t (0-255) limitation and therefore it is converted into two cells or more if the number is really large.
The last cell always contains the checksum of the previous cells also limited to 8bit. I think it is called modulo 256. Collisions will happen but it doesn't look like a real problem. Good enough for what it is.
How to convert the 0x4B0 into 04 B0 ?
It would be no problem to convert the hexadecimal value into a string or char array and then split it but the functions should be as fast as possible and therefore it is done with bitshifting and bitmasking. Working with strings and string streams etc. is always bloated and slower. Char arrays are somehow uint8_t and would work. But let's not get into that. I want to shift some bits.
The start of the code looks like this:
#define MAX_BYTES 4 // maximum input is 32-bit
enum COMMANDS_42C {
CMD_SET_MAX_TORQUE = 0
};
std::map<COMMANDS_42C, int> servo_commands = {
{ CMD_SET_MAX_TORQUE, 0xa5 }
};
static const int MAX_POS_TORQUE = 1200;
bool SERVO42C::set_max_torque( int torque ){
if( torque > MAX_POS_TORQUE ){ // max pos torque is static const int 1200
torque = MAX_POS_TORQUE;
} else if( torque < 0 ){
torque = 0;
}
return send( servo_commands[CMD_SET_MAX_TORQUE], torque );
}
// Function to convert an integer into an array of bytes (formatted as hex)
void SERVO42C::int_to_hex_array(uint32_t value, uint8_t *array, int *length) {
// Determine how many bytes are needed for the value
int needed_bytes = 0;
for (int i = 0; i < MAX_BYTES; i++) {
if (value >> (i * 8))
needed_bytes = i + 1;
}
*length = needed_bytes;
for (int i = 0; i < needed_bytes; i++) { // Fill the array with bytes, starting from the most significant byte
array[needed_bytes - 1 - i] = (value >> (i * 8)) & 0xFF;
}
if( length <= 0 ){
*length = 1; // at least one cell even if value is zero
}
}
uint8_t SERVO42C::create_checksum( uint8_t *hex_blocks, int block_num ){
int sum = 0;
for( int i = 0; i <= block_num; ++i ) {
sum += hex_blocks[i];
}
return sum & 0xFF; // Mask to 8 bits // modulo 256
}
bool SERVO42C::send( int command, int value ){
uint8_t hex_array[MAX_BYTES] = {0};
int length = 0;
int_to_hex_array( value, hex_array, &length );
if( length <= 0 ){
length = 1;
}
int total_blocks = length + 3; // address, command and checksum cells added to the length
uint8_t hex_block_set[total_blocks] = {0};
hex_block_set[0] = slave_address;
hex_block_set[1] = command;
int start_at_index = 2; // index 0 and 1 is for address and command
// copy the hex cells into the main hex block array
for( int i = 0; i < length; ++i ){
hex_block_set[start_at_index] = hex_array[i];
++start_at_index;
}
// calculate the checksum of all cells and add the checksum as 8bit value in hex format as the last cell
// the cell for the checksum is not part of the checksum calculation. It should contain a 0 value at this point anyway
//int cells_for_checksum_calc = total_blocks-1;
hex_block_set[start_at_index] = create_checksum( hex_block_set, start_at_index-1 );
for (int i = 0; i <= start_at_index; i++) {
Serial.printf("%02X", hex_block_set[i]);
if (i < start_at_index ) {
Serial.printf(" ");
}
}
Serial.print("\n");
return true;
}
The function int_to_hex_array can take numbers up to 32bit and fill and array with the needed 8bit blocks. It also provides the number of cells that is then used to copy them into the final array.
The dummy Serial.printf code gives an output like this:

There is one command that needs a different code to work. If we want the stepper to move a given number of steps the format looks like this (CRC = cyclic redundancy check = the checksum):

There is one 8bit and one 32 bit value in the data section. The current code above does not cover this case but I'm working on it as this is one feature that will for sure be available in the next firmware update.
All in all I totally can't in any way recommend the SERVO42C driver to anyone who is not very familiar with coding at this time if the driver needs to be used without the provided makerbase interface.

gedm-dev
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.