Allow precise servo speed adjustments based on desired load
This commit is contained in:
parent
9f6e90f27f
commit
35b8bd0ab2
@ -7,7 +7,7 @@
|
||||
#define SERVO_L_BIT PD6
|
||||
#define SERVO_R_BIT PD5
|
||||
|
||||
// Not just STOP +- 500us because of rounding errors (e.g. 19.9 will become
|
||||
// Not just MID +- 500us because of rounding errors (e.g. 19.9 will become
|
||||
// 19 and not 20 because of integer division)
|
||||
#define SERVO_MID 1381UL
|
||||
#define SERVO_MAX 1883UL
|
||||
@ -21,18 +21,17 @@
|
||||
#define SERVO_R_FORW SERVO_MIN
|
||||
#define SERVO_R_BACKW SERVO_MAX
|
||||
|
||||
#define SERVO_DIR_BACKW 0
|
||||
#define SERVO_DIR_FORW 1
|
||||
|
||||
#define SERVO_90_TURN_MS 1000
|
||||
#define SERVO_CM_PER_S 15 // Distance in cm that servos travel in 1s
|
||||
|
||||
#define PRESCALER 1024UL
|
||||
#define PWM_PERIOD_MS (uint16_t)((256000UL * PRESCALER) / F_CPU)
|
||||
#define US2TIMER0(us) (uint16_t)((51U * us) / (200U * PWM_PERIOD_MS))
|
||||
#define US2TIMER0(us) (uint8_t)((51U * us) / (200U * PWM_PERIOD_MS))
|
||||
|
||||
void init_servos(void);
|
||||
|
||||
void servo_full_forw(void);
|
||||
void servo_turn_forw_r(void);
|
||||
void servo_turn_forw_l(void);
|
||||
void servo_full_backw(void);
|
||||
void servo_turn_backw_r(void);
|
||||
void servo_turn_backw_l(void);
|
||||
|
||||
void servo_speed(uint8_t direction, uint8_t load_percent_l, uint8_t load_percent_r);
|
||||
|
||||
#endif /* SERVOS_H */
|
||||
|
@ -14,7 +14,10 @@
|
||||
#include "debug.h"
|
||||
#endif /* DEBUG */
|
||||
|
||||
#define OBSTACLE_THRESHOLD 10
|
||||
// Distance in cm after which node should start evading the obstacle
|
||||
#define OBSTACLE_THRESHOLD 20
|
||||
// Wait 2s before starting to drive
|
||||
#define START_DELAY_MS 2000
|
||||
|
||||
uint8_t tx_raw[sizeof(data_packet_t)];
|
||||
data_packet_t tx_data;
|
||||
@ -28,31 +31,30 @@ int main(void)
|
||||
return R_PACKAGE_SIZE;
|
||||
|
||||
init_leds();
|
||||
init_servos();
|
||||
init_sonar();
|
||||
init_servos();
|
||||
nrf24_init();
|
||||
|
||||
SET(LED_PORT, LED_BLUE_BIT);
|
||||
_delay_ms(START_DELAY_MS);
|
||||
CLR(LED_PORT, LED_BLUE_BIT);
|
||||
|
||||
nrf24_config(2, sizeof(data_packet_t)); // Channel #2
|
||||
nrf24_tx_address(base_mac);
|
||||
nrf24_rx_address(node_mac);
|
||||
|
||||
// Use green LED as power LED
|
||||
// TODO: need all LEDs for debugging, will use as power when UART debugger
|
||||
// will arrive
|
||||
/* SET(LED_PORT, LED_GREEN_BIT); */
|
||||
|
||||
sei();
|
||||
|
||||
servo_full_forw();
|
||||
while (1) {
|
||||
// Distance is measured early so the same value gets sent to the base
|
||||
// station and gets used to decide movement. Needs to be done in order
|
||||
// for base station to receive meaningful distance value.
|
||||
distance_in_cm = read_sonar();
|
||||
decide_movement(&distance_in_cm);
|
||||
|
||||
// Update base station
|
||||
send_sensor_data(&distance_in_cm);
|
||||
|
||||
decide_movement(&distance_in_cm);
|
||||
}
|
||||
|
||||
cli();
|
||||
@ -71,9 +73,9 @@ void send_sensor_data(const int32_t *distance_in_cm)
|
||||
nrf24_send(tx_raw);
|
||||
|
||||
// Indicate package sending with a signal LED
|
||||
SET(LED_PORT, LED_GREEN_BIT);
|
||||
SET(LED_PORT, LED_BLUE_BIT);
|
||||
while (nrf24_isSending());
|
||||
CLR(LED_PORT, LED_GREEN_BIT);
|
||||
CLR(LED_PORT, LED_BLUE_BIT);
|
||||
}
|
||||
|
||||
/// Control servos based on received distance data
|
||||
@ -82,40 +84,39 @@ void decide_movement(const int32_t *distance_in_cm)
|
||||
uint8_t avoid_obstacle = 0;
|
||||
int32_t distance_to_obstacle = *distance_in_cm;
|
||||
|
||||
// No obstacle found
|
||||
if (distance_to_obstacle == ECHO_TIMEOUT) return;
|
||||
|
||||
while (1) {
|
||||
if (distance_to_obstacle == ECHO_TIMEOUT) {
|
||||
// No obstacle found
|
||||
servo_full_forw();
|
||||
servo_speed(SERVO_DIR_FORW, 100, 100);
|
||||
avoid_obstacle = 0;
|
||||
} else if (distance_to_obstacle >= 0
|
||||
&& distance_to_obstacle <= MIN_SONAR_RANGE) {
|
||||
// Obstacle is right in front, can't make a turn
|
||||
servo_full_backw();
|
||||
servo_speed(SERVO_DIR_BACKW, 100, 100);
|
||||
_delay_ms(SERVO_90_TURN_MS);
|
||||
avoid_obstacle = 1;
|
||||
_delay_ms(SONAR_DELAY);
|
||||
} else if (distance_to_obstacle > MIN_SONAR_RANGE
|
||||
&& distance_to_obstacle <= OBSTACLE_THRESHOLD) {
|
||||
// Obstacle is close and in front, make a turn backwards
|
||||
servo_turn_backw_r();
|
||||
// Obstacle is close and in front, make a turn left
|
||||
servo_speed(SERVO_DIR_FORW, 0, 100);
|
||||
_delay_ms(SERVO_90_TURN_MS);
|
||||
avoid_obstacle = 1;
|
||||
_delay_ms(SONAR_DELAY);
|
||||
} else {
|
||||
// TODO: factor this in decision making about maneuvers
|
||||
// Obstacle is in front, but a safe distance away
|
||||
servo_full_forw();
|
||||
servo_speed(SERVO_DIR_FORW, 50, 50);
|
||||
avoid_obstacle = 0;
|
||||
|
||||
}
|
||||
|
||||
if (avoid_obstacle == 1) {
|
||||
SET(LED_PORT, LED_BLUE_BIT);
|
||||
SET(LED_PORT, LED_GREEN_BIT);
|
||||
} else {
|
||||
CLR(LED_PORT, LED_BLUE_BIT);
|
||||
CLR(LED_PORT, LED_GREEN_BIT);
|
||||
return;
|
||||
}
|
||||
|
||||
_delay_ms(500);
|
||||
distance_to_obstacle = read_sonar();
|
||||
}
|
||||
}
|
||||
|
@ -23,38 +23,65 @@ void init_servos(void)
|
||||
SET(SERVO_DDR, SERVO_R_BIT);
|
||||
}
|
||||
|
||||
void servo_full_forw(void)
|
||||
void servo_speed(uint8_t direction, uint8_t load_percent_l, uint8_t load_percent_r)
|
||||
{
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_FORW);
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_FORW);
|
||||
}
|
||||
// Check max and min values (0 and 100) first to avoid division since that
|
||||
// will lose some precision
|
||||
|
||||
void servo_turn_forw_r(void)
|
||||
{
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_FORW);
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_STOP);
|
||||
}
|
||||
// Special case for full stop since it requires register clearing
|
||||
if (load_percent_l == 0 && load_percent_r == 0) {
|
||||
TCCR0A = 0x00;
|
||||
TCCR0B = 0x00;
|
||||
return;
|
||||
}
|
||||
|
||||
void servo_turn_forw_l(void)
|
||||
{
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_STOP);
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_FORW);
|
||||
}
|
||||
// Registers have been cleared, need to set them again
|
||||
if (TCCR0A == 0x00 || TCCR0B == 0x00)
|
||||
init_servos();
|
||||
|
||||
void servo_full_backw(void)
|
||||
{
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_BACKW);
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_BACKW);
|
||||
}
|
||||
// Left motor
|
||||
if (load_percent_l == 0) {
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_STOP);
|
||||
} else {
|
||||
// Forwards
|
||||
if (direction == SERVO_DIR_FORW) {
|
||||
if (load_percent_l == 100) {
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_FORW);
|
||||
} else {
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_STOP + ((SERVO_L_FORW - SERVO_L_STOP)
|
||||
* load_percent_l) / 100);
|
||||
}
|
||||
} else {
|
||||
// Backwards
|
||||
if (load_percent_l == 100) {
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_BACKW);
|
||||
} else {
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_STOP - ((SERVO_L_STOP - SERVO_L_BACKW)
|
||||
* load_percent_l) / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void servo_turn_backw_r(void)
|
||||
{
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_STOP);
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_BACKW);
|
||||
}
|
||||
|
||||
void servo_turn_backw_l(void)
|
||||
{
|
||||
SERVO_L_REG = US2TIMER0(SERVO_L_BACKW);
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_STOP);
|
||||
// Right motor
|
||||
if (load_percent_r == 0) {
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_STOP);
|
||||
} else {
|
||||
// Forwards
|
||||
if (direction == SERVO_DIR_FORW) {
|
||||
if (load_percent_r == 100) {
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_FORW);
|
||||
} else {
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_STOP - ((SERVO_R_STOP - SERVO_R_FORW)
|
||||
* load_percent_r) / 100);
|
||||
}
|
||||
} else {
|
||||
// Backwards
|
||||
if (load_percent_r == 100) {
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_BACKW);
|
||||
} else {
|
||||
SERVO_R_REG = US2TIMER0(SERVO_R_STOP + ((SERVO_R_BACKW - SERVO_R_STOP)
|
||||
* load_percent_r) / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user