top of page

BeagleBone Black – Tutorial Rede CAN + Python

Autor: Bruno Oliveira

Coautor: Rodrigo Pechoneri

1 - Introdução


Computadores e sistemas embarcados estão cada vez mais populares e presentes em nosso dia a dia. No ambiente acadêmico não é diferente. Com tecnologias compactas e de performance considerável, as opções de escolha para o hardware que fará parte de cada projeto são inúmeras, bastando apenas escolher a que mais se alinha com a aplicação do projeto.

A rede CAN, muito conhecida por sua aplicação na indústria automobilística, é uma rede versátil, usada atualmente nos mais diversos projetos. Sua segurança e confiabilidade são definitivamente fatores que pesam na sua escolha pelos projetistas.

Nesse tutorial em forma de artigo focaremos na BeagleBone Black, mostrando como habilitar os dois controladores CAN nativos da placa, estabelecendo uma rede entre eles e trocando mensagens via terminal. Além disso, será mostrado como utilizar a programação em Python para enviar e receber mensagens na rede.

Tudo o que foi feito aqui faz parte do meu Trabalho de Conclusão de Curso, que tem por objetivo implementar uma rede CAN no projeto de uma versão compacta de relógio de átomos frios, projeto do Centro de Pesquisa em Óptica e Fotônica - CePOF

Confesso que não sou um expert em redes CAN, e devido ao desafio desse projeto, tanto pela quantidade de informações (muitas vezes desatualizadas) quanto por todos os problemas encontrados, decidi fazer esse tutorial, e assim contribuir um pouco com toda a comunidade Open Source, que me ajudou muito no projeto.

Parto princípio aqui que o leitor está minimamente familiarizado com a BeagleBone e também com os conceitos de rede CAN, mesmo que nunca tenha implementado uma. Assim, poderei ser mais direto e específico no artigo, evitando o prolongamento do mesmo.

Esclarecimentos feitos, vamos começar.



2 - Meu setup


Neste tutorial, será utilizado os seguintes hardwares:


  • BeagleBone Black Rev C

  • 2 Transceiver CAN MCP2551 - Datasheet

  • Conversor bidirecional de nível lógico (4 canais) – Exemplo nesse link

  • Fonte 5V@1A – conector P4 (A fonte é opcional, poderá ser utilizada a alimentação USB)

  • Protoboard e cabos macho-macho

  • 2 resistores 120Ohm

  • Cartão SD de no mínimo 4Gb

Sistema operacional:

Debian (wheezy) versão 7.9 Pode ser baixada aqui

Tão importante quanto a distribuição do Linux, é necessário verificar também a versão do Kernel usada. Você poderá verificar através do comando:

$ uname –r

Utilizo aqui a versão 3.8.13 (Não foi necessário atualizar o Kernel, pois a imagem do Debian usava essa versão)

Recomendo utilizar o sistema operacional no cartão de memória, evitando assim que caso alguma coisa seja feita erroneamente, basta apenas regravar a imagem no cartão e recomeçar os procedimentos. Posteriormente você pode passar o conteúdo do cartão para a memória flash conforme este tutorial



3 - Configurando os controladores CAN


Apesar da placa possuir 2 controladores CAN, por padrão eles não estão habilitados. Isso porque eles compartilham os mesmos pinos que outras funções da placa, como i2c e GPIO.

É necessário então a criação de overlays, que irão alterar a função dos pinos, possibilitando que sejam usados para a CAN.


O controlador can0 utiliza os pinos P9_19(rx) e P9_20(tx), enquanto o can1 utiliza os pinos P9_24(rx) e P9_26(tx).


Por questão de preferência, usaremos a interface do cloud9 para a conexão com a Beaglebone (basta digitar no navegador 192.168.7.2:3000 , quando conectado ao cabo USB), por ser um pouco mais user-friendly, quando comparada aos terminais do Putty por exemplo. Além disso, no cloud9 posso gerenciar arquivos e terminais mais facilmente quando necessário. É apenas uma questão de preferência e não afetará em nada caso o usuário opte por outra opção.


Fig.1 Interface Cloud9


Os overlays foram retirados do blog Embedded Things. Nesse site é possível encontrar um tutorial (com alguns passos desatualizados e em inglês) sobre CAN e Beaglebone Black.


Vamos começar pelo can1, pois seu processo é mais simples.




Configurando o can1


Abra um editor de texto de sua preferência (utilizado aqui o ) e cole o código abaixo:


/dts-v1/;

/plugin/;


/ {

compatible = "ti,beaglebone", "ti,beaglebone-black";


/* identification */

part-number = "dcan1pinmux";


fragment@0 {

target = <&am33xx_pinmux>;

__overlay__ {

dcan1_pins_s0: dcan1_pins_s0 {

pinctrl-single,pins = <

0x180 0x12 /* d_can1_tx, SLEWCTRL_FAST | INPUT_PULLUP | MODE2 */

0x184 0x32 /* d_can1_rx, SLEWCTRL_FAST | RECV_ENABLE | INPUT_PULLUP | MODE2 */

>;

};

};

};


fragment@1 {

target = <&dcan1>;

__overlay__ {

#address-cells = <1>;

#size-cells = <0>;


status = "okay";

pinctrl-names = "default";

pinctrl-0 = <&dcan1_pins_s0>;

};

};

};


Salve o arquivo como


Agora vamos compilar o overlay, gerando um arquivo binário, através do comando:


$ dtc -O dtb -o BB-DCAN1-00A0.dtbo -b 0 -@ BB-DCAN1-00A0.dts


O arquivo gerado deverá ser copiado para a pasta lib/firmware. Use o comando:


$ sudo cp BB-DCAN1-00A0.dtbo /lib/firmware


Feito isso, já temos o necessário para habilitar o controlador can1


Configurando o controlador can0


O processo é similar ao can1, com a diferença de que haverá um passo adicional.

Novamente, abre-se um editor de texto e copia-se o código abaixo:


/dts-v1/;

/plugin/;


/ {

compatible = "ti,beaglebone", "ti,beaglebone-black";


/* identification */

part-number = "dcan0pinmux";


fragment@0 {

target = <&am33xx_pinmux>;

__overlay__ {

dcan0_pins_s0: dcan0_pins_s0 {

pinctrl-single,pins = <

0x178 0x12 /* d_can0_tx, SLEWCTRL_FAST | INPUT_PULLUP | MODE2 */

0x17C 0x32 /* d_can0_rx, SLEWCTRL_FAST | RECV_ENABLE | INPUT_PULLUP | MODE2 */

>;

};

};

};


fragment@1 {

target = <&dcan0>;

__overlay__ {

#address-cells = <1>;

#size-cells = <0>;


status = "okay";

pinctrl-names = "default";

pinctrl-0 = <&dcan0_pins_s0>;

};

};

};


Salve o arquivo como BB-DCAN0-00A0.dts . Depois, compile-o e mova o binário gerado para a pasta /lib/firmware:


$ dtc -O dtb -o BB-DCAN0-00A0.dtbo -b 0 -@ BB-DCAN0-00A0.dts

$ sudo cp BB-DCAN0-00A0.dtbo /lib/firmware


Até aqui, o processo foi semelhante. O que precisamos fazer agora é uma modificação no “” do kernel, para que ele permita a mudança da função dos pinos.

O problema que surge é o fato de que o can0 utiliza os mesmos pinos do i2c, e esse módulo tem prioridade no carregamento sobre qualquer outro módulo. Então mesmo que feito o overlay, como foi feito acima, ele não será usado pela prioridade do i2c.

Por isso, essa modificação que faremos irá mascarar essa prioridade permitindo assim carregar o can0 ao invés do i2c.

Aqui é importante a versão do Kernel, pois para cada versão a modificação é feita de uma maneira, utilizando arquivos diferentes.

É necessário baixar os arquivos fonte (source files) originais dessa versão, para isso, use os comandos a seguir para copia-los do repositório do Derek Molloy:


$ git clone https://github.com/derekmolloy/boneDeviceTree.git

$ cd boneDeviceTree/DTSource3.8.13/


Vamos abrir o seguinte arquivo, utilizando o comando nano com o parâmetro ‘–c ‘, que permite visualizar o número da linha atual do cursor


$ nano -c am335x-bone-common.dtsi


Vá até a linha 404 e a comente (use // no começo da linha), salve e saia do arquivo


// pinctrl-0 = <&i2c2_pins>;


Vamos compilar o binário:


$ dtc -O dtb -o am335x-boneblack.dtb -b 0 -@ am335x-boneblack.dts


Moveremos o arquivo criado para a pasta /boot/dtbs/3.8.13-bone79 . Note que no blog do embedded things o diretório indicado é diferente. Mas para a versão do sistema que estamos usando, o caminho é esse indicado acima.

Antes de mover o arquivo, vamos fazer um backup do arquivo que ele irá substituir, salvando ele com a terminação ‘.orig’ somente para referência:


$ sudo mv /boot/dtbs/3.8.13-bone79/am335x-boneblack.dtb /boot/dtbs/3.8.13-bone79/am335x-boneblack.orig.dtb


Então, movemos o arquivo que criamos:


$ sudo mv am335x-boneblack.dtb /boot/dtbs/3.8.13-bone79


Pronto, o procedimento para a can0 está feito. Reinicie a BeagleBone para utilizarmos os controladores.

Com os procedimentos acima, temos os dois controladores configurados. Para usa-los precisamos instalar o pacote can-utils, que contém o SocketCAN, uma espécie de pacote de utilidades para podermos interagir com a rede CAN e os controladores mais facilmente.


Instalando o can-utils


Digite os comandos abaixo:


$ git clone https://github.com/linux-can/can-utils.git

$ cd can-utils

$ ./autogen.sh

$ ./configure

$ sudo make

$ sudo make install


Assim, feita a instalação, podemos habilitar os controladores.


Habilitando os controladores CAN


Essa sequência de comandos deverá ser seguida toda vez que a placa for ligada:


$ echo BB-DCAN0 > /sys/devices/bone_capemgr.*/slots

$ echo BB-DCAN1 > /sys/devices/bone_capemgr.*/slots

$ sudo modprobe can

$ sudo modprobe can-dev

$ sudo modprobe can-raw

$ sudo ip link set can0 up type can bitrate 500000

$ sudo ifconfig can0 up

$ sudo ip link set can1 up type can bitrate 500000

$ sudo ifconfig can1 up


As duas primeiras linhas são os comandos que habilitam os controladores.


A terceira, quarta e quinta carregam o módulo CAN


A sexta e sétima configura a velocidade do barramento para o controlador can0 e também o ativa, da mesma forma que as duas últimas fazem para o can1.


Como são vários comandos, aconselho a coloca-los em um script simples, e assim evitamos ter que digitar toda vez (Colocarei meu script em meu repositório). Na próxima seção mostrarei como criar e adicionar esse script ao PATH.


Para verificar se a instalação e ativação foi concluída com êxito, digite o comando


$ ifconfig


Seu output deverá ser semelhante ao da imagem abaixo. Esse comando listará seus controladores ativos.


Fig2. Comando ifconfig


Vale ressaltar que se você optou por usar apenas o controlador can1 (pinos 24 e 26), a sequencia de comandos é parecida:


$ echo BB-DCAN1 > /sys/devices/bone_capemgr.*/slots

$ sudo modprobe can

$ sudo modprobe can-dev

$ sudo modprobe can-raw

$ sudo ip link set can0 up type can bitrate 500000

$ sudo ifconfig can0 up


Note que mesmo utilizando o controlador can1, ele está agora referenciado como can0 pois a Beaglebone nomeia os controladores conforme a ordem que você os habilita.


Agora que os controladores estão configurados e habilitados, podemos testar na rede física.


4 - Criando um script


Antes do teste da rede física, irei rapidamente mostrar como criar o script e adiciona-lo ao PATH, e dessa forma o usuário apenas precisará digitar o nome do script no terminal que todos aqueles comandos da seção anterior serão carregados.


Crie um arquivo, que será o nosso script (meu arquivo está disponibilizado na minha página no Github)


$ nano can_exec


Adicione todos os comandos anteriores. Nesse caso, está sendo feito para os dois controladores CAN:


#!/bin/bash

# Enable Can0 and Can1


echo "Ligando can........."

echo BB-DCAN0 > /sys/devices/bone_capemgr.*/slots

echo BB-DCAN1 > /sys/devices/bone_capemgr.*/slots

echo "Done"


echo "Habilitando Modprobe........."

modprobe can

modprobe can-dev

modprobe can-raw

echo "Done"


echo "Setando parametros can..........."

sudo ip link set can0 up type can bitrate 500000

sudo ifconfig can0 up

sudo ip link set can1 up type can bitrate 500000

sudo ifconfig can1 up

echo "Done"


Feito isso, salve o arquivo e saia do editor.

Adicione permissões de execução do script


$ chmod 777 can_exec


Para executa-lo, é necessário estar no diretório em que ele se encontra e digitar

./can_exec.


Como queremos que seja possível executa-lo em qualquer diretório, vamos adiciona-lo ao PATH. É necessário alterar o arquivo /etc/profile


$ nano /etc/profile


Nesse arquivo, procurea linha do PATH, que deve ser similar a isso:


PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"


Então basta adicionar o caminho do diretório em que se encontra seu script. Em meu exemplo, o script se encontra no meu diretório do cloud9 (/var/lib/cloud9), então modificando a linha teremos:


PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/lib/cloud9/Bruno/bin"


Reinicie sua BBB. Feito isso, basta abrir um terminal e digitar o nome do seu script (nesse caso can_exec) que ele executará todos os comandos de uma vez


$ can_exec


5 - Testando a CAN


O primeiro passo é montar todo o circuito, conforme a figura abaixo. Note que não se deve conectar o controlador direto a rede CAN. É necessário o uso de transceivers entre o controlador a rede.


Considerações importantes:

  • Faça isso com a placa desligada (caso algum seja desconectado/conectado com a placa ligada, é necessário desativar e ativar os controladores, através do comando sudo ifconfig can0 down e sudo infconfig can0 up. O mesmo vale para o can1)

  • Aqui eu usei um transceiver 5V. Porém, o nível logico da beaglebone é de 3V3. Por isso usamos o conversor de nível lógico. Usamos ele apenas no RX dos transceivers, pois para o TX, a tensão 3V3 dos pinos da BBB é suficiente para ser reconhecido como nível logico alto.

  • Como alternativa a esse transceiver, poderia ser usado um de 3V3 como o SN65HVD233

  • Não é possível testar a rede se ela não possuir pelo menos 2 controladores conectados a ela. Quando é verificado a ausência do número mínimo, as mensagens que deveriam ser enviadas ficam armazenadas no buffer. Caso muitas mensagens sejam armazenadas e não enviadas, surgirá um erro de buffer cheio.

  • Se você estiver utilizando a fonte externa, use os pinos P9_5 ou P9_6 ao invés do pino P9_7 (confira o pinout abaixo)


Fig. 3 – Circuito Completo

Fig. 4 – Pinout BeagleBone Black (retirado do livro Beaglebone for Dummies)

Por curiosidade, seguem imagens do meu circuito protótipo:


Figuras 5 e 6. Circuito real



Devido a quantidade de fios no circuito, estamos desenvolvendo paralelamente uma espécie de que agrupe os componentes e as conexões, otimizando o espaço.

Com o circuito montado, ligue a placa e espere que ela se inicialize. Depois, habilite os controladores CAN usando o script ou todos os comandos da seção anterior.


Existem basicamente 3 comandos que podemos usar:


  • : Mostra as mensagens recebidas ou enviadas pelo controlador.

  • : Envia uma única mensagem na rede

  • : Envia mensagens aleatórias na rede

Para ficar mais fácil a visualização, abra 2 terminais.

No primeiro, vamos digitar:


$ candump any –x


Usando essa linha de comando significa que será mostrado as mensagens de todos os controladores. O parâmetro –x dará os detalhes de qual controlador enviou o recebeu a mensagem


Em outro terminal, digite

$

Dessa forma, o controlador can1 passará a enviar mensagens na rede.

O resultado deverá ser semelhante a imagem abaixo:


Fig.7 – Comandos candump e cangen


Pode ser feito o mesmo processo para o can0, verificando sua funcionalidade


$


Caso não apareçam as mensagens no terminal do candump, sugiro verificar alguns pontos:

  • Cheque as conexões, e os componentes. São muitos fios, com isso a chance de alguma ligação estar errada e/ou solta

  • Tive muito problema com transceiver queimando. Troque por outros transceivers e veja se o problema continua. (Troque um por um, intercale-os também).

  • Confira os sinais com um osciloscópio. Abaixo segue uma medida feita durante o cangen.

  • Não se esqueça de desligar e ligar os controladores (ou até mesmo reinciar a BBB) toda vez que conectar e desconectar os fios.

  • Deixe o cangen rodando durante alguns minutos para ver se ele apresenta o erro de buffer cheio (isso é um indicativo que a CAN funciona, mas algum componente ou fio está errado)


Fig.8 – Medida do osciloscópio: Sinal da rede CAN


Com os controladores funcionando dessa forma mais crua, vamos então implementar a rede programando em python


6 - Instalando a python-can


A instalação do python-can, biblioteca do Python que permite a programação e iteração com os drivers CAN, é bem simples. Basta fazer seu download e instação através do comando:

$ pip install python-can

Feito a instação, podemos checar se funciona abrindo a interface do python no terminal, e digitando no terminal os comandos a seguir:

$ python #abre a interface python no terminal

$ import can

ou

$ help(can)

Como a programação nessa interface python é dinâmica, ou seja, ela é processada na medida que o usuário escreve as linhas, se a biblioteca não estiver instalada corretamente, o sistema fornecerá um erro ao digitar os dois últimos comandos acima


Fig.9 – Resultado correto da linha ‘import can’


7 - Exemplos em Python utilizando CAN


Feita a instalação da biblioteca, mostrar 2 programas simples, mas que utilizam dos dois recursos principais da rede CAN, enviar e receber mensagens.


Disponibilizarei os programas em meu repositório no github.


Antes de analisarmos os códigos, algumas considerações importantes:


  • As mensagens que são enviadas para a rede contêm 2 partes importantes: O id da mensagem e seu conteúdo.

  • O id, em sua forma não estendida varia de 0 a 2047(ou 0 a 7FF hexadecimal) enquanto o conteúdo é composto por um vetor de no máximo 8 elementos, cada elemento possuindo 8 bits, ou seja, cada elemento varia de 0 a 255 (ou 0 a FF hexadecimal)

  • Os programas mostrados aqui consideram que a can já está habilitada e ativa (todos os comandos daquele script foram executados)


Vamos começar com o programa rx_simples.



Programa rx_simples


Ele praticamente simularia o comando que vimos anteriormente.

Tentei deixar comentado ao máximo para que fique tudo explicado


#!/usr/bin/python

# coding=UTF-8


### Esse programa monitorará a rede CAN, mostrando todas as mensagens recebidas.

### Também verificará se a mensagem possuem um id conhecido ou não



#Importando bibliotecas


import can #Biblioteca do python-can



#Definir qual controlador vamos usar


bus = can.interface.Bus(channel='can0', bustype='socketcan_ctypes') #Selecionamos o can0 como o controlador que monitorará as mensagens


#Definindo um id conhecido


id = 0x123


while True:


message = bus.recv() ##Fica esperando receber mensagem no barramento CAN

print("Recebemos uma mensagem")

if message.arbitration_id == id: #verifica se o id da mensagem é o mesmo que o id definido

print("A mensagem possui um id conhecido!")

else:

print("A mensagem possui um id desconhecido!")


#O loop a seguir irá formatar o conteudo do vetor para que possa ser apresentado na tela da forma de hexadecimal

s=[]

for i in range(len(message.data)): #loop que percorrerá todo o vetor message.data

s.append(hex(message.data[i])) #Convertendo o valor em hexadecimal e adicionando ao fim do vetor s

print s



Gostaria de ressaltar alguns pontos do código.

O primeiro é em relação a linha 15. O parâmetro passado para o bustype, para o python2.x, deverá ser ‘socketcan_ctypes’. Se você usa a partir da versão 3.0, o parâmetro deverá ser ‘socketcan_native’.

O programa roda em loop. Ele fica esperando as mensagens no barramento CAN, e quando as recebe, analisa o identificador da mensagem, processa o conteúdo (faz uma formatação simples para ficar melhor apresentável) e o mostra na tela.


Programa tx_simples


# coding=UTF-8


### Esse programa enviará periodicamente uma mensagem para a rede can


#Importando bibliotecas


import can

import time


#Definir qual controlador vamos usar


bus = can.interface.Bus(channel='can1', bustype='socketcan_ctypes') #Selecionamos o can0 como o controlador que monitorará as mensagens


#Definindo um id para nossas mensagens


id = 0x123


#Definindo o conteudo das mensagens

cont = [0xf5,0x23,0x1A]



while True:


msg = can.Message(arbitration_id = id,data=cont) #Criando a mensagem que será enviada na rede

bus.send(msg) #Enviado para a rede

print "Mensagem enviada"

time.sleep(5) #espera 5 segundos antes de enviar a mesma mensagem




O programa tx simularia o comando , enviando uma mensagem ao barramento. Essa ação se repete a cada 5 segundos.

Da mesma forma que o programa anterior, primeiramente é selecionado o barramento. Depois, definimos os dois elementos chaves da mensagem a ser transmitida, o id e o conteúdo.

Utilizamos as funções da biblioteca para criar a mensagem no formato da rede CAN e posteriormente a enviamos.


Aqui podemos ver os dois programas funcionando simultaneamente:

Fig. 10 – Enviando e recebendo mensagens pela CAN + Python


Esses dois programas ilustram realmente o básico de python+can. Com isso já é possível expandir as possibilidades do que pode ser feito. Para se ter uma ideia, com id’s diferentes é possível fazer um filtro, sendo que cada módulo conectado à rede responderá de uma maneira. E com o conteúdo das mensagens podemos enviar de tudo, desde que os módulos da rede saibam trabalhar com a mensagem que você enviou. E lógico, todo o conteúdo é apenas um monte números sendo enviados, deixando seu sistema mais seguro, caso alguém decida se conectar à rede e monitorar as mensagens.


Recomendo também olhar estes exemplos. São ligeiramente mais complexos e possuem mais conteúdo, e podem te ajudar a entender ainda mais o assunto. A descrição e todos os documentos relacionados à biblioteca python-can podem ser encontrados aqui.


8 - Considerações finais


Espero que esse tutorial sirva para qualquer pessoa que esteja começando nessa área de implementar uma rede CAN. O conteúdo disponível na internet é gigantesco. Fóruns, blogs me ajudaram muito, mas sinto que perdi muito tempo tentando entender as informações que muitas vezes eram demasiadamente complexas, e por não ter um mínimo conhecimento básico desse assunto, senti muita dificuldade tentando entender as discussões que aconteciam.

Dessa forma, se esse texto servir de ponto de partida para o leitor ou leitora, a missão aqui está cumprida.

Deixo aqui o blog do laboratório em que fiz meu TCC, o LIEPO. Tem muito conteúdo interessante, sobre sistemas embarcados e muito mais.

Agradeço pelo tempo dispensado para ler o artigo!


9 - Referências:


  • Beaglebone for dummies – Rui Santos e Luís Perestrelo

  • Python programming for the absolute beginner – Michael Dawson

  • Documentação Python-can: Disponível aqui

  • AM335X DCAN Driver Guide: Disponível aqui

  • Readme file for SocketCAN: Disponível aqui










bottom of page