# Работа с CAN FD через Python

В данном разделе мы рассмотрим пример кода программ для отправки и получения сообщения через CAN FD, написанных на языке программирования Python. Для работы с CAN у Python есть отдельная библиотека python-can, которая устанавливается с помощью pip3:

```python
$ pip3 install python-can
```

Импортируем три библиотеки:

```python
import can
import struct
import time
```

Модуль struct умеет упаковывать данные из Python в байты и распаковывать их обратно, позволяя нам не задумываться о том как это делать. Он очень удобен в использовании, подробнее про struct и его методах можно прочитать в [документации](https://docs.python.org/3/library/struct.html).

Далее создадим управляющую can-ом структуру, назовем ее can0 и сообщение, которое будем отправлять - число типа float, например 2.5 в байтах  это 0х00002040:

```python
can0 = can.interface.Bus(channel = 'can0', bustype = 'socketcan', fd=True)
msg = 2.5 # 00 00 20 40
```

[По ссылке](https://gregstoll.com/~gregstoll/floattohex/) можно найти очень удобный конвертер, который легко переведет float в hex и обратно, самое главное не забыть поставить галочку рядом с Swap to use big-endian

<figure><img src="https://3551773033-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBjLyfPc4FcQUfXFi5fQr%2Fuploads%2FD01eefnqc7C9ZdrmnNn2%2Fimage.png?alt=media&#x26;token=0e4372b6-f723-47c6-8b3b-cc24b3be3e5a" alt=""><figcaption></figcaption></figure>

Дальше в бесконечном цикле формируем массив байтов, используя функцию pack модуля struct, переводим его в тип сообщения, понятного для CAN и отправляем это сообщение. В качестве ID укажем 101, в hex это 0х065. По аналогии с программой, написанной на ардуино, в конце добавим задержку на все оставшееся время до 1 милисекунды.

```python
while(1):
     t = time.time()
     data = bytearray(struct.pack("f", msg))
     msg_to_send = can.Message(arbitration_id=0x065, data = data)
     can0.send(msg_to_send)
     time.sleep(0.001 - (time.time()-t)) #время работы тела цикла - 1 мс
```

Весь код программы, предназначенной отправлять сообщения:

```python
import can
import struct
import time


can0 = can.interface.Bus(channel = 'can0', bustype = 'socketcan', fd=True)
msg = 2.5
while(1):
     t = time.time()
     data = bytearray(struct.pack("f", msg))
     msg_to_send = can.Message(arbitration_id=0x065, data = data)
     can0.send(msg_to_send)
     time.sleep(0.001 - (time.time()-t)) # время работы тела цикла - 1 мс
```

Чтобы убедиться в корректной работе, в первом окне запустите программу (у нас она называется can\_send.py)

```
python3 can_send.py
```

В соседнем терминале воспользуйтесь утилитой candump, вы должны увидеть пакет из 4 байтов 00 00 20 40

<figure><img src="https://3551773033-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBjLyfPc4FcQUfXFi5fQr%2Fuploads%2FjQuNmN2wBo00yEqP0UjS%2Fimage.png?alt=media&#x26;token=749b9590-d749-4d17-bb63-5b323729dbfc" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3551773033-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBjLyfPc4FcQUfXFi5fQr%2Fuploads%2F0wkplKW8YV47xjlfpgp3%2Fimage.png?alt=media&#x26;token=efd84956-0d47-4a99-a866-d8b4c3077b08" alt=""><figcaption></figcaption></figure>

Теперь напишем программу для получения сообщений. Подключаем все те же модули, создаем управлющую can-ом структуру. В бесконечном цикле получаем сообщение и если его ID = 101 (см. пример выше), распаковываем пакет и печатаем полученные данные.

```python
import can
import struct
import time


can0 = can.interface.Bus(channel = 'can0', bustype = 'socketcan', fd=True)
while(1):
     t = time.time()
     msg = can0.recv()
     if msg.arbitration_id == 101:
          data = struct.unpack('f', msg.data)
          print(data)
     time.sleep(0.002 - (time.time()-t)) # время работы тела цикла - 2 мс
```

Эту программу назовем can\_recv и запустим ее в терминале. А в соседнем запустим программу, которая отправляет число 2.5, написанную ранее.

<figure><img src="https://3551773033-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBjLyfPc4FcQUfXFi5fQr%2Fuploads%2FA5scUg1rWXuRVuwmr8Iw%2Fimage.png?alt=media&#x26;token=58cdd067-5084-4cdb-817b-f4cb763a82ee" alt=""><figcaption></figcaption></figure>

Как видим мы получили немного не то, что ожидали (а ожидали мы увидеть просто число 2.5). Дело в том, что результатом struct.unpack() является кортеж, даже если он содержит ровно один элемент. Об этом подробнее можно прочитать в [документации](https://docs.python.org/3/library/struct.html). Давайте немного скорректируем наш код:

```python
import can
import struct
import time


can0 = can.interface.Bus(channel = 'can0', bustype = 'socketcan', fd=True)
while(1):
     t = time.time()
     msg = can0.recv()
     if msg.arbitration_id == 101:
          data = struct.unpack('f', msg.data)
          print(data[0]) # первый элемент кортежа
     time.sleep(0.002 - (time.time()-t)) # время работы тела цикла - 2 мс
```

<figure><img src="https://3551773033-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBjLyfPc4FcQUfXFi5fQr%2Fuploads%2FUmkQgNd7ejEf2j0NSCID%2Fimage.png?alt=media&#x26;token=4142cc3b-ef2b-4a2e-a2fb-21b242c425b6" alt=""><figcaption></figcaption></figure>

И теперь мы видим то число, которое и отправляем.&#x20;

В данном разделе мы рассмотрели примеры программ для передачи и получения сообщений по CAN FD. Для обычного CAN в коде поменяется только одна строчка - создание управляющей can-ом структуры. Вместо

```python
 can0 = can.interface.Bus(channel = 'can0', bustype = 'socketcan', fd=True)
```

необходимо написать

```python
can0 = can.interface.Bus(channel = 'can0', bustype = 'socketcan')
```
