Kilobot Firmware

From Kilobots
Jump to: navigation, search

We recommend to use the firmware 2.0, which has a more stable code, more supported communication interface and allows working with Linux and MacOS. Additionally, most of the tools provided in this website require the firmware 2.0 to work properly.

Upgrade to Kilobot Firmware 2.0

Most of the information reported here below come from (and can be found also on) the kilobotics website (https://www.kilobotics.com/documentation).


NOTE:
You will only need to do this once. If you already have the latest controller firmware and bootlader installed, then you can skip the next steps.


We recommend doing the firmware upgrade from a Linux machine.

Here below, the steps to upgrade the kilobot firmware:

1. Setup of your Linux machine installing avrdude. For Ubuntu, use the following command:
sudo apt-get install avrdude
2. If it's not done yet, update the firmware of the Overhead Controller (OHC) (see OHC Firmware for details)
3. Download the file bootloader.hex
4. Set the OHC jumper to "external" mode as in this figure:
OHC jumper in external mode. Image source: http://ftp.k-team.com/kilobot/user_manual/Kilobot_UserManual.pdf
5. Turn on the kilobot by adding the power jumper:
Turn on the kilobot by adding the power jumper. Image source: https://www.kilobotics.com/documentation
6. Connect the OHC to the PC through Usb, and plug the cable connecting the OHC to the kilobot as in this figure:
Connect the ICSP programming cable to the robot. Image source: https://www.kilobotics.com/documentation
Gently press and tilt the programming cable to ensure a good connection.
7. Run (from the directory containing the bootloader file) the update command:
sudo avrdude -p m328p -P usb -c avrispmkII -U "flash:w:bootloader.hex:i"
8. If you succeed, the robot should be happy and start vibrating in your hands the terminal message should say: Fuses OK. avrdude done. Thank you. Similarly to this screenshot.

Troubleshooting

1. Problem: The kilobot (that you're trying to upgrade) is not detected by the avrdude as connected through USB.
    Solution 1: Bad connection. Check that the OHC jumper is in the correct position
    Solution 2: Software failure. Try to reset the kilobot by removing and placing back its jumper
    Solution 3: Low battery. Place the kilobot on a charging dock for a few minutes and retry
    Solution 4: Damaged battery. Replace the kilobot battery

Firmware 1.0

In case needed, here you can get the firmware 1.0 (from K-team): KilobotFirstFirmware.hex

Modified firmware to filter out noise

At the Bristol Robotics Laboratory we have realised that some Kilobots go to SLEEP or IDLE mode when running. We believe this happens due to 1) background IR noise that sometimes interferes with the Kilobots, and/or 2) if the message from a Kilobot gets corrupted. When this happens, the robots might interpret the signal/message as one coming from the overhead controller commanding them to go to SLEEP or IDLE state.

We have modified Firmware 2.0 to filter out this noise by adding a counter for the number of consecutive times that the robot receives a message with type ≥ 128 (user messages must have a type < 128) in the RUNNING state. When it reaches a certain threshold (10 consecutive messages), it then processes the command. After this modification to the firmware, the Kilobots take a bit more time to process the signal from the controller when running, but none of them go the SLEEP or IDLE while running.

The modified library can be found here. Concretely, a new constant THRESHOLD_N_COMMANDS and variable n_commands_received have been added to kilolib.c, and the process_message function has been properly adapted. The modified code is the following:

// Parameter for IR filter
#define THRESHOLD_N_COMMANDS 10

// Number of consecutive commands received from the programmer (or noise)
uint8_t n_commands_received;

static inline void process_message() {
    AddressPointer_t reset = (AddressPointer_t)0x0000, bootload = (AddressPointer_t)0x7000;
    calibmsg_t *calibmsg = (calibmsg_t*)&rx_msg.data;
    if (rx_msg.type < BOOT) {
        kilo_message_rx(&rx_msg, &rx_dist);
        
        n_commands_received = 0;
        return;
    }
    
    // Doesn't respond to other signals apart from neighbors while running if a few received
    if(kilo_state == RUNNING && n_commands_received < THRESHOLD_N_COMMANDS){
    
        n_commands_received++;
        
        return;
    }
    
    // In RUNNING state, it has to receive at least THREHOLD_N_COMMANDS continuous commands to react
    else if( (kilo_state == RUNNING && n_commands_received == THRESHOLD_N_COMMANDS) || (kilo_state != RUNNING)){
    
        n_commands_received = 0;

        if (rx_msg.type != READUID && rx_msg.type != RUN && rx_msg.type != CALIB)
            motors_off();
        switch (rx_msg.type) {
            case BOOT:
                tx_timer_off();
                bootload();
                break;
            case RESET:
                reset();
                break;
            case SLEEP:
                kilo_state = SLEEPING;
                break;
            case WAKEUP:
                kilo_state = IDLE;
                break;
            case CHARGE:
                kilo_state = CHARGING;
                break;
            case VOLTAGE:
                kilo_state = BATTERY;
                break;
            case RUN:
                if (kilo_state != SETUP && kilo_state != RUNNING) {
                    motors_on();
                    kilo_state = SETUP;
                }
                break;
            case CALIB:
                switch(calibmsg->mode) {
                    case CALIB_SAVE:
                        if (kilo_state == MOVING) {
                            eeprom_write_byte(EEPROM_UID, kilo_uid&0xFF);
                            eeprom_write_byte(EEPROM_UID+1, (kilo_uid>>8)&0xFF);
                            eeprom_write_byte(EEPROM_LEFT_ROTATE, kilo_turn_left);
                            eeprom_write_byte(EEPROM_RIGHT_ROTATE, kilo_turn_right);
                            eeprom_write_byte(EEPROM_LEFT_STRAIGHT, kilo_straight_left);
                            eeprom_write_byte(EEPROM_RIGHT_STRAIGHT, kilo_straight_right);
                            motors_off();
                            kilo_state = IDLE;
                        }
                        break;
                    case CALIB_UID:
                        kilo_uid = calibmsg->uid;
                        cur_motion = MOVE_STOP;
                        break;
                    case CALIB_TURN_LEFT:
                        if (cur_motion != MOVE_LEFT || kilo_turn_left != calibmsg->turn_left) {
                            prev_motion = MOVE_STOP;
                            cur_motion = MOVE_LEFT;
                            kilo_turn_left = calibmsg->turn_left;
                        }
                        break;
                    case CALIB_TURN_RIGHT:
                        if (cur_motion != MOVE_RIGHT || kilo_turn_right != calibmsg->turn_right) {
                            prev_motion = MOVE_STOP;
                            cur_motion = MOVE_RIGHT;
                            kilo_turn_right = calibmsg->turn_right;
                        }
                        break;
                    case CALIB_STRAIGHT:
                        if (cur_motion != MOVE_STRAIGHT || kilo_straight_right != calibmsg->straight_right || kilo_straight_left != calibmsg->straight_left) {
                            prev_motion = MOVE_STOP;
                            cur_motion = MOVE_STRAIGHT;
                            kilo_straight_left = calibmsg->straight_left;
                            kilo_straight_right = calibmsg->straight_right;
                        }
                        break;
                }
                if (calibmsg->mode != CALIB_SAVE && kilo_state != MOVING) {
                    motors_on();
                    kilo_state = MOVING;
                }
                break;
            case READUID:
                if (kilo_state != MOVING) {
                    motors_on();
                    set_color(RGB(0,0,0));
                    prev_motion = cur_motion = MOVE_STOP;
                    kilo_state = MOVING;
                }

                if (kilo_uid&(1<<rx_msg.data[0]))
                    cur_motion = MOVE_LEFT;
                else
                    cur_motion = MOVE_STOP;
                break;
            default:
                break;
        }
    }
}

Links

For further information, check the kilobotics website: https://www.kilobotics.com/documentation

The source code of the firmware (both of OHC and kilobots) can be found here: https://github.com/acornejo/kilolib