1 /*
2  * Copyright (c) 2019 Maksim Masalski maxxliferobot@gmail.com
3  * A Line follower robot program using DFRobot Maqueen Robot and microbit
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/printk.h>
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/device.h>
12 
13 enum motor {
14 	MOTOR_LEFT,
15 	MOTOR_RIGHT,
16 };
17 
18 static const struct gpio_dt_spec left_gpio =
19 	GPIO_DT_SPEC_GET(DT_PATH(zephyr_user), left_gpios);
20 static const struct gpio_dt_spec right_gpio =
21 	GPIO_DT_SPEC_GET(DT_PATH(zephyr_user), right_gpios);
22 
23 static const struct i2c_dt_spec motorctl =
24 	I2C_DT_SPEC_GET(DT_NODELABEL(motorctl));
25 
26 static struct gpio_callback left_cb;
27 static struct gpio_callback right_cb;
28 
29 static int left_line;
30 static int right_line;
31 
left_irq(const struct device * dev,struct gpio_callback * cb,uint32_t pins)32 static void left_irq(const struct device *dev, struct gpio_callback *cb,
33 		     uint32_t pins)
34 {
35 	left_line = gpio_pin_get_dt(&left_gpio);
36 }
37 
right_irq(const struct device * dev,struct gpio_callback * cb,uint32_t pins)38 static void right_irq(const struct device *dev, struct gpio_callback *cb,
39 		      uint32_t pins)
40 {
41 	right_line = gpio_pin_get_dt(&right_gpio);
42 }
43 
motor_control(enum motor motor,int16_t speed)44 static void motor_control(enum motor motor, int16_t speed)
45 {
46 	uint8_t buf[3];
47 
48 	if (motor == MOTOR_LEFT) {
49 		buf[0] = 0x00U;
50 	} else {
51 		buf[0] = 0x02U;
52 	}
53 
54 	if (speed < 0) {
55 		buf[1] = 0x01U;
56 		buf[2] = (uint8_t)(speed * (-1));
57 	} else {
58 		buf[1] = 0x00U;
59 		buf[2] = (uint8_t)speed;
60 	}
61 
62 	i2c_write_dt(&motorctl, buf, sizeof(buf));
63 }
64 
65 /* Line follower algorithm for the robot */
line_follow(void)66 static void line_follow(void)
67 {
68 	if ((left_line == 0) && (right_line == 0)) {
69 		motor_control(MOTOR_LEFT, 200);
70 		motor_control(MOTOR_RIGHT, 200);
71 	} else {
72 		if ((left_line == 0) && (right_line == 1)) {
73 			motor_control(MOTOR_LEFT, 0);
74 			motor_control(MOTOR_RIGHT, 200);
75 			if ((left_line == 1) && (right_line == 1)) {
76 				motor_control(MOTOR_LEFT, 0);
77 				motor_control(MOTOR_RIGHT, 200);
78 			}
79 		} else {
80 			if ((left_line == 1) && (right_line == 0)) {
81 				motor_control(MOTOR_LEFT, 200);
82 				motor_control(MOTOR_RIGHT, 0);
83 				if ((left_line == 1) &&
84 					(right_line == 1)) {
85 					motor_control(MOTOR_LEFT, 200);
86 					motor_control(MOTOR_RIGHT, 0);
87 				}
88 				if ((left_line == 1) && (right_line == 0)) {
89 					motor_control(MOTOR_LEFT, 200);
90 				} else {
91 					motor_control(MOTOR_RIGHT, 0);
92 				}
93 			}
94 		}
95 	}
96 }
97 
main(void)98 int main(void)
99 {
100 	if (!gpio_is_ready_dt(&left_gpio) ||
101 	    !gpio_is_ready_dt(&right_gpio)) {
102 		printk("Left/Right GPIO controllers not ready.\n");
103 		return 0;
104 	}
105 
106 	if (!device_is_ready(motorctl.bus)) {
107 		printk("Motor controller I2C bus not ready.\n");
108 		return 0;
109 	}
110 
111 	/* Setup gpio to read data from digital line sensors of the robot */
112 	gpio_pin_configure_dt(&left_gpio, GPIO_INPUT);
113 	gpio_pin_configure_dt(&right_gpio, GPIO_INPUT);
114 
115 	gpio_pin_interrupt_configure_dt(&left_gpio, GPIO_INT_EDGE_BOTH);
116 	gpio_pin_interrupt_configure_dt(&right_gpio, GPIO_INT_EDGE_BOTH);
117 
118 	gpio_init_callback(&left_cb, left_irq, BIT(left_gpio.pin));
119 	gpio_add_callback(left_gpio.port, &left_cb);
120 	gpio_init_callback(&right_cb, right_irq, BIT(right_gpio.pin));
121 	gpio_add_callback(right_gpio.port, &right_cb);
122 
123 	while (1) {
124 		line_follow();
125 	}
126 	return 0;
127 }
128